[libvirt] [PATCH 00/28] Rename files in src/util to have a 'vir' prefix

Currently the files in src/util are 50/50 split between those having a 'vir' prefix and those which don't. Finish the job by remaining all remaining files to have a 'vir' prefix too, guaranteeing that they can't clash with system headers[1]. The only case which was not a plain rename, was merging processinfo.{c,h} into the virprocess.{c,h} since the functionality logically belongs together. At the end src/Makefile.am is updated to sort util files alphabetically. Left as further work - make sure all functions in these files also have a 'vir' prefix. eg dnsmasq, ebtables, iptables, usb and pci files are violators in this regard. Also left, much of virutil.c should move into virfile.c Daniel [1] Not a theoretical problem - we already hit a clsah on 'usb.h' before forcing us to use 'hostusb.h' and 'memory.h' clashes with a system header but we never noticed so far.

From: "Daniel P. Berrange" <berrange@redhat.com> To bring in line with new naming practice, rename the= src/util/cgroup.{h,c} files to vircgroup.{h,c} Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/conf/domain_audit.h | 2 +- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_conf.h | 2 +- src/qemu/qemu_cgroup.c | 2 +- src/qemu/qemu_conf.h | 2 +- src/util/cgroup.c | 2099 ----------------------------------------------- src/util/cgroup.h | 167 ---- src/util/vircgroup.c | 2099 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/vircgroup.h | 167 ++++ 11 files changed, 2273 insertions(+), 2273 deletions(-) delete mode 100644 src/util/cgroup.c delete mode 100644 src/util/cgroup.h create mode 100644 src/util/vircgroup.c create mode 100644 src/util/vircgroup.h diff --git a/po/POTFILES.in b/po/POTFILES.in index f0cfd7f..19ed187 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/cgroup.c src/util/command.c src/util/conf.c src/util/dnsmasq.c @@ -157,6 +156,7 @@ src/util/util.c src/util/viraudit.c src/util/virauth.c src/util/virauthconfig.c +src/util/vircgroup.c src/util/virdbus.c src/util/virfile.c src/util/virhash.c diff --git a/src/Makefile.am b/src/Makefile.am index 53ec9da..149ffc9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,7 +57,6 @@ UTIL_SOURCES = \ util/buf.c util/buf.h \ util/command.c util/command.h \ util/conf.c util/conf.h \ - util/cgroup.c util/cgroup.h \ util/event.c util/event.h \ util/event_poll.c util/event_poll.h \ util/hooks.c util/hooks.h \ @@ -92,6 +91,7 @@ UTIL_SOURCES = \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ + util/vircgroup.c util/vircgroup.h \ util/virdbus.c util/virdbus.h \ util/virhash.c util/virhash.h \ util/virhashcode.c util/virhashcode.h \ diff --git a/src/conf/domain_audit.h b/src/conf/domain_audit.h index 63a8f75..381fe37 100644 --- a/src/conf/domain_audit.h +++ b/src/conf/domain_audit.h @@ -25,7 +25,7 @@ # define __VIR_DOMAIN_AUDIT_H__ # include "domain_conf.h" -# include "cgroup.h" +# include "vircgroup.h" void virDomainAuditStart(virDomainObjPtr vm, const char *reason, diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 767ef26..e354d6c 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "logging.h" #include "memory.h" -#include "cgroup.h" +#include "vircgroup.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index ea345be..c02966f 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -32,7 +32,7 @@ # include "domain_event.h" # include "capabilities.h" # include "threads.h" -# include "cgroup.h" +# include "vircgroup.h" # include "security/security_manager.h" # include "configmake.h" diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 30cd1d6..6c6607d 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -26,7 +26,7 @@ #include "qemu_cgroup.h" #include "qemu_domain.h" #include "qemu_process.h" -#include "cgroup.h" +#include "vircgroup.h" #include "logging.h" #include "memory.h" #include "virterror_internal.h" diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 1a39946..cfa6fff 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -34,7 +34,7 @@ # include "domain_event.h" # include "threads.h" # include "security/security_manager.h" -# include "cgroup.h" +# include "vircgroup.h" # include "pci.h" # include "hostusb.h" # include "cpu_conf.h" diff --git a/src/util/cgroup.c b/src/util/cgroup.c deleted file mode 100644 index 8f3b8b7..0000000 --- a/src/util/cgroup.c +++ /dev/null @@ -1,2099 +0,0 @@ -/* - * cgroup.c: Tools for managing cgroups - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * Copyright IBM Corp. 2008 - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Dan Smith <danms@us.ibm.com> - */ -#include <config.h> - -#include <stdio.h> -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -# include <mntent.h> -#endif -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <signal.h> -#include <libgen.h> -#include <dirent.h> - -#include "internal.h" -#include "util.h" -#include "memory.h" -#include "cgroup.h" -#include "logging.h" -#include "virfile.h" -#include "virhash.h" -#include "virhashcode.h" - -#define CGROUP_MAX_VAL 512 - -VIR_ENUM_IMPL(virCgroupController, VIR_CGROUP_CONTROLLER_LAST, - "cpu", "cpuacct", "cpuset", "memory", "devices", - "freezer", "blkio"); - -struct virCgroupController { - int type; - char *mountPoint; - char *placement; -}; - -struct virCgroup { - char *path; - - struct virCgroupController controllers[VIR_CGROUP_CONTROLLER_LAST]; -}; - -typedef enum { - VIR_CGROUP_NONE = 0, /* create subdir under each cgroup if possible. */ - VIR_CGROUP_MEM_HIERACHY = 1 << 0, /* call virCgroupSetMemoryUseHierarchy - * before creating subcgroups and - * attaching tasks - */ - VIR_CGROUP_VCPU = 1 << 1, /* create subdir only under the cgroup cpu, - * cpuacct and cpuset if possible. */ -} virCgroupFlags; - -/** - * 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); -} - -/** - * virCgroupMounted: query whether a cgroup subsystem is mounted or not - * - * @cgroup: The group structure to be queried - * @controller: cgroup subsystem id - * - * Returns true if a cgroup is subsystem is mounted. - */ -bool virCgroupMounted(virCgroupPtr cgroup, int controller) -{ - return cgroup->controllers[controller].mountPoint != NULL; -} - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -/* - * 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_ERROR(_("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); - } - /* NB, the same controller can appear >1 time in mount list - * due to bind mounts from one location to another. Pick the - * first entry only - */ - if (typelen == len && STREQLEN(typestr, tmp, len) && - !group->controllers[i].mountPoint && - !(group->controllers[i].mountPoint = strdup(entry.mnt_dir))) - goto no_memory; - tmp = next; - } - } - } - - VIR_FORCE_FCLOSE(mounts); - - return 0; - -no_memory: - VIR_FORCE_FCLOSE(mounts); - return -ENOMEM; -} - - -/* - * Process /proc/self/cgroup figuring out what cgroup - * sub-path the current process is assigned to. ie not - * necessarily 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_ERROR(_("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; - } - } - } - - VIR_FORCE_FCLOSE(mapping); - - return 0; - -no_memory: - VIR_FORCE_FCLOSE(mapping); - 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; -} -#endif - - -int virCgroupPathOfController(virCgroupPtr group, - int controller, - const char *key, - char **path) -{ - if (controller == -1) { - int i; - for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { - if (group->controllers[i].mountPoint && - group->controllers[i].placement) { - controller = i; - break; - } - } - } - if (controller == -1) - return -ENOSYS; - - 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' to '%s'", keypath, value); - rc = virFileWriteStr(keypath, value, 0); - if (rc < 0) { - rc = -errno; - VIR_DEBUG("Failed to write value '%s': %m", value); - } 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) { - VIR_DEBUG("No path of %s, %s", group->path, key); - return rc; - } - - VIR_DEBUG("Get value %s", keypath); - - rc = virFileReadAll(keypath, 1024*1024, value); - if (rc < 0) { - rc = -errno; - VIR_DEBUG("Failed to read %s: %m\n", keypath); - } else { - /* Terminated with '\n' has sometimes harmful effects to the caller */ - if ((*value)[rc - 1] == '\n') - (*value)[rc - 1] = '\0'; - - rc = 0; - } - - VIR_FREE(keypath); - - return rc; -} - -static int virCgroupSetValueU64(virCgroupPtr group, - int controller, - const char *key, - unsigned long long int value) -{ - char *strval = NULL; - int rc; - - if (virAsprintf(&strval, "%llu", value) == -1) - return -ENOMEM; - - rc = virCgroupSetValueStr(group, controller, key, strval); - - VIR_FREE(strval); - - return rc; -} - - - -static int virCgroupSetValueI64(virCgroupPtr group, - int controller, - const char *key, - long long int value) -{ - char *strval = NULL; - int rc; - - if (virAsprintf(&strval, "%lld", 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, - long long int *value) -{ - char *strval = NULL; - int rc = 0; - - rc = virCgroupGetValueStr(group, controller, key, &strval); - if (rc != 0) - goto out; - - if (virStrToLong_ll(strval, NULL, 10, value) < 0) - rc = -EINVAL; -out: - VIR_FREE(strval); - - return rc; -} - -static int virCgroupGetValueU64(virCgroupPtr group, - int controller, - const char *key, - unsigned long long int *value) -{ - char *strval = NULL; - int rc = 0; - - rc = virCgroupGetValueStr(group, controller, key, &strval); - if (rc != 0) - goto out; - - if (virStrToLong_ull(strval, NULL, 10, value) < 0) - rc = -EINVAL; -out: - VIR_FREE(strval); - - return rc; -} - - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -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); - VIR_FREE(value); - - if (rc != 0) { - VIR_ERROR(_("Failed to set %s %d"), inherit_values[i], rc); - break; - } - } - - return rc; -} - -static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group) -{ - int rc = 0; - unsigned long long value; - const char *filename = "memory.use_hierarchy"; - - rc = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - filename, &value); - if (rc != 0) { - VIR_ERROR(_("Failed to read %s/%s (%d)"), group->path, filename, rc); - return rc; - } - - /* Setting twice causes error, so if already enabled, skip setting */ - if (value == 1) - return 0; - - VIR_DEBUG("Setting up %s/%s", group->path, filename); - rc = virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - filename, 1); - - if (rc != 0) { - VIR_ERROR(_("Failed to set %s/%s (%d)"), group->path, filename, rc); - } - - return rc; -} - -static int virCgroupMakeGroup(virCgroupPtr parent, - virCgroupPtr group, - bool create, - unsigned int flags) -{ - 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; - - /* We need to control cpu bandwidth for each vcpu now */ - if ((flags & VIR_CGROUP_VCPU) && - (i != VIR_CGROUP_CONTROLLER_CPU && - i != VIR_CGROUP_CONTROLLER_CPUACCT && - i != VIR_CGROUP_CONTROLLER_CPUSET)) { - /* treat it as unmounted and we can use virCgroupAddTask */ - VIR_FREE(group->controllers[i].mountPoint); - continue; - } - - rc = virCgroupPathOfController(group, i, "", &path); - if (rc < 0) - return rc; - /* As of Feb 2011, clang can't see that the above function - * call did not modify group. */ - sa_assert(group->controllers[i].mountPoint); - - VIR_DEBUG("Make controller %s", path); - if (access(path, F_OK) != 0) { - if (!create || - mkdir(path, 0755) < 0) { - /* With a kernel that doesn't support multi-level directory - * for blkio controller, libvirt will fail and disable all - * other controllers even though they are available. So - * treat blkio as unmounted if mkdir fails. */ - if (i == VIR_CGROUP_CONTROLLER_BLKIO) { - rc = 0; - VIR_FREE(group->controllers[i].mountPoint); - VIR_FREE(path); - continue; - } else { - 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) { - VIR_FREE(path); - break; - } - } - /* - * Note that virCgroupSetMemoryUseHierarchy should always be - * called prior to creating subcgroups and attaching tasks. - */ - if ((flags & VIR_CGROUP_MEM_HIERACHY) && - (group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint != NULL) && - (i == VIR_CGROUP_CONTROLLER_MEMORY || - STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint))) { - rc = virCgroupSetMemoryUseHierarchy(group); - if (rc != 0) { - VIR_FREE(path); - 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(bool privileged, - virCgroupPtr *group, - bool create) -{ - 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(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, create, VIR_CGROUP_NONE); - -cleanup: - virCgroupFree(&rootgrp); - return rc; -} -#endif - -#if defined _DIRENT_HAVE_D_TYPE -static int virCgroupRemoveRecursively(char *grppath) -{ - DIR *grpdir; - struct dirent *ent; - int rc = 0; - - grpdir = opendir(grppath); - if (grpdir == NULL) { - if (errno == ENOENT) - return 0; - rc = -errno; - VIR_ERROR(_("Unable to open %s (%d)"), grppath, errno); - return rc; - } - - for (;;) { - char *path; - - errno = 0; - ent = readdir(grpdir); - if (ent == NULL) { - if ((rc = -errno)) - VIR_ERROR(_("Failed to readdir for %s (%d)"), grppath, errno); - break; - } - - if (ent->d_name[0] == '.') continue; - if (ent->d_type != DT_DIR) continue; - - if (virAsprintf(&path, "%s/%s", grppath, ent->d_name) == -1) { - rc = -ENOMEM; - break; - } - rc = virCgroupRemoveRecursively(path); - VIR_FREE(path); - if (rc != 0) - break; - } - closedir(grpdir); - - VIR_DEBUG("Removing cgroup %s", grppath); - if (rmdir(grppath) != 0 && errno != ENOENT) { - rc = -errno; - VIR_ERROR(_("Unable to remove %s (%d)"), grppath, errno); - } - - return rc; -} -#else -static int virCgroupRemoveRecursively(char *grppath ATTRIBUTE_UNUSED) -{ - /* Claim no support */ - return -ENXIO; -} -#endif - -/** - * virCgroupRemove: - * - * @group: The group to be removed - * - * It first removes all child groups recursively - * in depth first order and then removes @group - * because the presence of the child groups - * prevents removing @group. - * - * 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; - - VIR_DEBUG("Removing cgroup %s and all child cgroups", grppath); - rc = virCgroupRemoveRecursively(grppath); - 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; -} - -/** - * virCgroupAddTaskController: - * - * @group: The cgroup to add a task to - * @pid: The pid of the task to add - * @controller: The cgroup controller to be operated on - * - * Returns: 0 on success or -errno on failure - */ -int virCgroupAddTaskController(virCgroupPtr group, pid_t pid, int controller) -{ - if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST) - return -EINVAL; - - if (!group->controllers[controller].mountPoint) - return -EINVAL; - - return virCgroupSetValueU64(group, controller, "tasks", - (unsigned long long)pid); -} - - -static int virCgroupAddTaskStrController(virCgroupPtr group, - const char *pidstr, - int controller) -{ - char *str = NULL, *cur = NULL, *next = NULL; - unsigned long long p = 0; - int rc = 0; - char *endp; - - if (virAsprintf(&str, "%s", pidstr) < 0) - return -1; - - cur = str; - while (*cur != '\0') { - rc = virStrToLong_ull(cur, &endp, 10, &p); - if (rc != 0) - goto cleanup; - - rc = virCgroupAddTaskController(group, p, controller); - if (rc != 0) - goto cleanup; - - next = strchr(cur, '\n'); - if (next) { - cur = next + 1; - *next = '\0'; - } else { - break; - } - } - -cleanup: - VIR_FREE(str); - return rc; -} - -/** - * virCgroupMoveTask: - * - * @src_group: The source cgroup where all tasks are removed from - * @dest_group: The destination where all tasks are added to - * @controller: The cgroup controller to be operated on - * - * Returns: 0 on success or -errno on failure - */ -int virCgroupMoveTask(virCgroupPtr src_group, virCgroupPtr dest_group, - int controller) -{ - int rc = 0, err = 0; - char *content = NULL; - - if (controller < VIR_CGROUP_CONTROLLER_CPU || - controller > VIR_CGROUP_CONTROLLER_BLKIO) - return -EINVAL; - - if (!src_group->controllers[controller].mountPoint || - !dest_group->controllers[controller].mountPoint) { - VIR_WARN("no vm cgroup in controller %d", controller); - return 0; - } - - rc = virCgroupGetValueStr(src_group, controller, "tasks", &content); - if (rc != 0) - return rc; - - rc = virCgroupAddTaskStrController(dest_group, content, controller); - if (rc != 0) - goto cleanup; - - VIR_FREE(content); - - return 0; - -cleanup: - /* - * We don't need to recover dest_cgroup because cgroup will make sure - * that one task only resides in one cgroup of the same controller. - */ - err = virCgroupAddTaskStrController(src_group, content, controller); - if (err != 0) - VIR_ERROR(_("Cannot recover cgroup %s from %s"), - src_group->controllers[controller].mountPoint, - dest_group->controllers[controller].mountPoint); - VIR_FREE(content); - - return rc; -} - -/** - * virCgroupForDriver: - * - * @name: name of this driver (e.g., xen, qemu, lxc) - * @group: Pointer to returned virCgroupPtr - * - * Returns 0 on success - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForDriver(const char *name, - virCgroupPtr *group, - bool privileged, - bool create) -{ - int rc; - char *path = NULL; - virCgroupPtr rootgrp = NULL; - - rc = virCgroupAppRoot(privileged, &rootgrp, create); - 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) { - rc = virCgroupMakeGroup(rootgrp, *group, create, VIR_CGROUP_NONE); - if (rc != 0) - virCgroupFree(group); - } - -out: - virCgroupFree(&rootgrp); - - return rc; -} -#else -int virCgroupForDriver(const char *name ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool privileged ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - /* Claim no support */ - return -ENXIO; -} -#endif - -/** -* virCgroupGetAppRoot: -* -* @group: Pointer to returned virCgroupPtr -* -* Returns 0 on success -*/ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupGetAppRoot(virCgroupPtr *group) -{ - return virCgroupNew("/", group); -} -#else -int virCgroupGetAppRoot(virCgroupPtr *group ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} -#endif - -/** - * virCgroupForDomain: - * - * @driver: group for driver owning the domain - * @name: name of the domain - * @group: Pointer to returned virCgroupPtr - * - * Returns 0 on success - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForDomain(virCgroupPtr driver, - const char *name, - virCgroupPtr *group, - bool create) -{ - int rc; - char *path; - - if (driver == NULL) - return -EINVAL; - - if (virAsprintf(&path, "%s/%s", driver->path, name) < 0) - return -ENOMEM; - - rc = virCgroupNew(path, group); - VIR_FREE(path); - - if (rc == 0) { - /* - * Create a cgroup with memory.use_hierarchy enabled to - * surely account memory usage of lxc with ns subsystem - * enabled. (To be exact, memory and ns subsystems are - * enabled at the same time.) - * - * The reason why doing it here, not a upper group, say - * a group for driver, is to avoid overhead to track - * cumulative usage that we don't need. - */ - rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_MEM_HIERACHY); - if (rc != 0) - virCgroupFree(group); - } - - return rc; -} -#else -int virCgroupForDomain(virCgroupPtr driver ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} -#endif - -/** - * virCgroupForVcpu: - * - * @driver: group for the domain - * @vcpuid: id of the vcpu - * @group: Pointer to returned virCgroupPtr - * - * Returns 0 on success - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForVcpu(virCgroupPtr driver, - int vcpuid, - virCgroupPtr *group, - bool create) -{ - int rc; - char *path; - - if (driver == NULL) - return -EINVAL; - - if (virAsprintf(&path, "%s/vcpu%d", driver->path, vcpuid) < 0) - return -ENOMEM; - - rc = virCgroupNew(path, group); - VIR_FREE(path); - - if (rc == 0) { - rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_VCPU); - if (rc != 0) - virCgroupFree(group); - } - - return rc; -} -#else -int virCgroupForVcpu(virCgroupPtr driver ATTRIBUTE_UNUSED, - int vcpuid ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} -#endif - -/** - * virCgroupForEmulator: - * - * @driver: group for the domain - * @group: Pointer to returned virCgroupPtr - * - * Returns: 0 on success or -errno on failure - */ -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -int virCgroupForEmulator(virCgroupPtr driver, - virCgroupPtr *group, - bool create) -{ - int rc; - char *path; - - if (driver == NULL) - return -EINVAL; - - if (virAsprintf(&path, "%s/emulator", driver->path) < 0) - return -ENOMEM; - - rc = virCgroupNew(path, group); - VIR_FREE(path); - - if (rc == 0) { - rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_VCPU); - if (rc != 0) - virCgroupFree(group); - } - - return rc; -} -#else -int virCgroupForEmulator(virCgroupPtr driver ATTRIBUTE_UNUSED, - virCgroupPtr *group ATTRIBUTE_UNUSED, - bool create ATTRIBUTE_UNUSED) -{ - return -ENXIO; -} - -#endif -/** - * virCgroupSetBlkioWeight: - * - * @group: The cgroup to change io weight for - * @weight: The Weight for this cgroup - * - * Returns: 0 on success - */ -int virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight) -{ - if (weight > 1000 || weight < 100) - return -EINVAL; - - return virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_BLKIO, - "blkio.weight", - weight); -} - -/** - * virCgroupGetBlkioWeight: - * - * @group: The cgroup to get weight for - * @Weight: Pointer to returned weight - * - * Returns: 0 on success - */ -int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight) -{ - unsigned long long tmp; - int ret; - ret = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_BLKIO, - "blkio.weight", &tmp); - if (ret == 0) - *weight = tmp; - return ret; -} - -/** - * virCgroupSetBlkioDeviceWeight: - * - * @group: The cgroup to change io device weight device for - * @path: The device with a weight to alter - * @weight: The new device weight (100-1000), or 0 to clear - * - * device_weight is treated as a write-only parameter, so - * there isn't a getter counterpart. - * - * Returns: 0 on success, -errno on failure - */ -#if defined(major) && defined(minor) -int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, - const char *path, - unsigned int weight) -{ - char *str; - struct stat sb; - int ret; - - if (weight && (weight > 1000 || weight < 100)) - return -EINVAL; - - if (stat(path, &sb) < 0) - return -errno; - - if (!S_ISBLK(sb.st_mode)) - return -EINVAL; - - if (virAsprintf(&str, "%d:%d %d", major(sb.st_rdev), minor(sb.st_rdev), - weight) < 0) - return -errno; - - ret = virCgroupSetValueStr(group, - VIR_CGROUP_CONTROLLER_BLKIO, - "blkio.weight_device", - str); - VIR_FREE(str); - return ret; -} -#else -int -virCgroupSetBlkioDeviceWeight(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *path ATTRIBUTE_UNUSED, - unsigned int weight ATTRIBUTE_UNUSED) -{ - return -ENOSYS; -} -#endif - -/** - * virCgroupSetMemory: - * - * @group: The cgroup to change memory for - * @kb: The memory amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb) -{ - unsigned long long maxkb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; - - if (kb > maxkb) - return -EINVAL; - else if (kb == maxkb) - return virCgroupSetValueI64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.limit_in_bytes", - -1); - else - return virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.limit_in_bytes", - kb << 10); -} - -/** - * virCgroupGetMemoryUsage: - * - * @group: The cgroup to change memory for - * @kb: Pointer to returned used memory in kilobytes - * - * Returns: 0 on success - */ -int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb) -{ - long long unsigned int usage_in_bytes; - int ret; - ret = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.usage_in_bytes", &usage_in_bytes); - if (ret == 0) - *kb = (unsigned long) usage_in_bytes >> 10; - return ret; -} - -/** - * virCgroupSetMemoryHardLimit: - * - * @group: The cgroup to change memory hard limit for - * @kb: The memory amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb) -{ - return virCgroupSetMemory(group, kb); -} - -/** - * virCgroupGetMemoryHardLimit: - * - * @group: The cgroup to get the memory hard limit for - * @kb: The memory amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb) -{ - long long unsigned int limit_in_bytes; - int ret; - ret = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.limit_in_bytes", &limit_in_bytes); - if (ret == 0) - *kb = limit_in_bytes >> 10; - return ret; -} - -/** - * virCgroupSetMemorySoftLimit: - * - * @group: The cgroup to change memory soft limit for - * @kb: The memory amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb) -{ - unsigned long long maxkb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; - - if (kb > maxkb) - return -EINVAL; - else if (kb == maxkb) - return virCgroupSetValueI64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.soft_limit_in_bytes", - -1); - else - return virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.soft_limit_in_bytes", - kb << 10); -} - - -/** - * virCgroupGetMemorySoftLimit: - * - * @group: The cgroup to get the memory soft limit for - * @kb: The memory amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb) -{ - long long unsigned int limit_in_bytes; - int ret; - ret = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.soft_limit_in_bytes", &limit_in_bytes); - if (ret == 0) - *kb = limit_in_bytes >> 10; - return ret; -} - -/** - * virCgroupSetMemSwapHardLimit: - * - * @group: The cgroup to change mem+swap hard limit for - * @kb: The mem+swap amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb) -{ - unsigned long long maxkb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; - - if (kb > maxkb) - return -EINVAL; - else if (kb == maxkb) - return virCgroupSetValueI64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.memsw.limit_in_bytes", - -1); - else - return virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.memsw.limit_in_bytes", - kb << 10); -} - -/** - * virCgroupGetMemSwapHardLimit: - * - * @group: The cgroup to get mem+swap hard limit for - * @kb: The mem+swap amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb) -{ - long long unsigned int limit_in_bytes; - int ret; - ret = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.memsw.limit_in_bytes", &limit_in_bytes); - if (ret == 0) - *kb = limit_in_bytes >> 10; - return ret; -} - -/** - * virCgroupGetMemSwapUsage: - * - * @group: The cgroup to get mem+swap usage for - * @kb: The mem+swap amount in kilobytes - * - * Returns: 0 on success - */ -int virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb) -{ - long long unsigned int usage_in_bytes; - int ret; - ret = virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_MEMORY, - "memory.memsw.usage_in_bytes", &usage_in_bytes); - if (ret == 0) - *kb = usage_in_bytes >> 10; - return ret; -} - -/** - * virCgroupSetCpusetMems: - * - * @group: The cgroup to set cpuset.mems for - * @mems: the numa nodes to set - * - * Returns: 0 on success - */ -int virCgroupSetCpusetMems(virCgroupPtr group, const char *mems) -{ - return virCgroupSetValueStr(group, - VIR_CGROUP_CONTROLLER_CPUSET, - "cpuset.mems", - mems); -} - -/** - * virCgroupGetCpusetMems: - * - * @group: The cgroup to get cpuset.mems for - * @mems: the numa nodes to get - * - * Returns: 0 on success - */ -int virCgroupGetCpusetMems(virCgroupPtr group, char **mems) -{ - return virCgroupGetValueStr(group, - VIR_CGROUP_CONTROLLER_CPUSET, - "cpuset.mems", - mems); -} - -/** - * virCgroupSetCpusetCpus: - * - * @group: The cgroup to set cpuset.cpus for - * @cpus: the cpus to set - * - * Retuens: 0 on success - */ -int virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus) -{ - return virCgroupSetValueStr(group, - VIR_CGROUP_CONTROLLER_CPUSET, - "cpuset.cpus", - cpus); -} - -/** - * virCgroupGetCpusetCpus: - * - * @group: The cgroup to get cpuset.cpus for - * @cpus: the cpus to get - * - * Retuens: 0 on success - */ -int virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus) -{ - return virCgroupGetValueStr(group, - VIR_CGROUP_CONTROLLER_CPUSET, - "cpuset.cpus", - cpus); -} - -/** - * virCgroupDenyAllDevices: - * - * @group: The cgroup to deny all permissions, for all devices - * - * 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 - * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow - * - * Returns: 0 on success - */ -int virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor, - int perms) -{ - int rc; - char *devstr = NULL; - - if (virAsprintf(&devstr, "%c %i:%i %s%s%s", type, major, minor, - perms & VIR_CGROUP_DEVICE_READ ? "r" : "", - perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", - perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -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 - * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow - * - * Returns: 0 on success - */ -int virCgroupAllowDeviceMajor(virCgroupPtr group, char type, int major, - int perms) -{ - int rc; - char *devstr = NULL; - - if (virAsprintf(&devstr, "%c %i:* %s%s%s", type, major, - perms & VIR_CGROUP_DEVICE_READ ? "r" : "", - perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", - perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -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 - * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow - * - * Queries the type of device and its major/minor number, and - * adds that to the cgroup ACL - * - * Returns: 0 on success, 1 if path exists but is not a device, or - * negative errno value on failure - */ -#if defined(major) && defined(minor) -int virCgroupAllowDevicePath(virCgroupPtr group, const char *path, int perms) -{ - struct stat sb; - - if (stat(path, &sb) < 0) - return -errno; - - if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) - return 1; - - return virCgroupAllowDevice(group, - S_ISCHR(sb.st_mode) ? 'c' : 'b', - major(sb.st_rdev), - minor(sb.st_rdev), - perms); -} -#else -int virCgroupAllowDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *path ATTRIBUTE_UNUSED, - int perms ATTRIBUTE_UNUSED) -{ - return -ENOSYS; -} -#endif - - -/** - * 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 - * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to deny - * - * Returns: 0 on success - */ -int virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor, - int perms) -{ - int rc; - char *devstr = NULL; - - if (virAsprintf(&devstr, "%c %i:%i %s%s%s", type, major, minor, - perms & VIR_CGROUP_DEVICE_READ ? "r" : "", - perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", - perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -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 - * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to deny - * - * Returns: 0 on success - */ -int virCgroupDenyDeviceMajor(virCgroupPtr group, char type, int major, - int perms) -{ - int rc; - char *devstr = NULL; - - if (virAsprintf(&devstr, "%c %i:* %s%s%s", type, major, - perms & VIR_CGROUP_DEVICE_READ ? "r" : "", - perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", - perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -1) { - rc = -ENOMEM; - goto out; - } - - rc = virCgroupSetValueStr(group, - VIR_CGROUP_CONTROLLER_DEVICES, - "devices.deny", - devstr); - out: - VIR_FREE(devstr); - - return rc; -} - -#if defined(major) && defined(minor) -int virCgroupDenyDevicePath(virCgroupPtr group, const char *path, int perms) -{ - struct stat sb; - - if (stat(path, &sb) < 0) - return -errno; - - if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) - return 1; - - return virCgroupDenyDevice(group, - S_ISCHR(sb.st_mode) ? 'c' : 'b', - major(sb.st_rdev), - minor(sb.st_rdev), - perms); -} -#else -int virCgroupDenyDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, - const char *path ATTRIBUTE_UNUSED, - int perms ATTRIBUTE_UNUSED) -{ - return -ENOSYS; -} -#endif - -int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares) -{ - return virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_CPU, - "cpu.shares", shares); -} - -int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares) -{ - return virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_CPU, - "cpu.shares", shares); -} - -/** - * virCgroupSetCpuCfsPeriod: - * - * @group: The cgroup to change cpu.cfs_period_us for - * @cfs_period: The bandwidth period in usecs - * - * Returns: 0 on success - */ -int virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period) -{ - /* The cfs_period shoule be greater or equal than 1ms, and less or equal - * than 1s. - */ - if (cfs_period < 1000 || cfs_period > 1000000) - return -EINVAL; - - return virCgroupSetValueU64(group, - VIR_CGROUP_CONTROLLER_CPU, - "cpu.cfs_period_us", cfs_period); -} - -/** - * virCgroupGetCpuCfsPeriod: - * - * @group: The cgroup to get cpu.cfs_period_us for - * @cfs_period: Pointer to the returned bandwidth period in usecs - * - * Returns: 0 on success - */ -int virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period) -{ - return virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_CPU, - "cpu.cfs_period_us", cfs_period); -} - -/** - * virCgroupSetCpuCfsQuota: - * - * @group: The cgroup to change cpu.cfs_quota_us for - * @cfs_quota: the cpu bandwidth (in usecs) that this tg will be allowed to - * consume over period - * - * Returns: 0 on success - */ -int virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota) -{ - if (cfs_quota >= 0) { - /* The cfs_quota shoule be greater or equal than 1ms */ - if (cfs_quota < 1000) - return -EINVAL; - - /* check overflow */ - if (cfs_quota > ULLONG_MAX / 1000) - return -EINVAL; - } - - return virCgroupSetValueI64(group, - VIR_CGROUP_CONTROLLER_CPU, - "cpu.cfs_quota_us", cfs_quota); -} - -/** - * virCgroupGetCpuCfsQuota: - * - * @group: The cgroup to get cpu.cfs_quota_us for - * @cfs_quota: Pointer to the returned cpu bandwidth (in usecs) that this tg - * will be allowed to consume over period - * - * Returns: 0 on success - */ -int virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota) -{ - return virCgroupGetValueI64(group, - VIR_CGROUP_CONTROLLER_CPU, - "cpu.cfs_quota_us", cfs_quota); -} - -int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage) -{ - return virCgroupGetValueU64(group, - VIR_CGROUP_CONTROLLER_CPUACCT, - "cpuacct.usage", usage); -} - -int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage) -{ - return virCgroupGetValueStr(group, VIR_CGROUP_CONTROLLER_CPUACCT, - "cpuacct.usage_percpu", usage); -} - -#ifdef _SC_CLK_TCK -int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, - unsigned long long *sys) -{ - char *str; - char *p; - int ret; - static double scale = -1.0; - - if ((ret = virCgroupGetValueStr(group, VIR_CGROUP_CONTROLLER_CPUACCT, - "cpuacct.stat", &str)) < 0) - return ret; - if (!(p = STRSKIP(str, "user ")) || - virStrToLong_ull(p, &p, 10, user) < 0 || - !(p = STRSKIP(p, "\nsystem ")) || - virStrToLong_ull(p, NULL, 10, sys) < 0) { - ret = -EINVAL; - goto cleanup; - } - /* times reported are in system ticks (generally 100 Hz), but that - * rate can theoretically vary between machines. Scale things - * into approximate nanoseconds. */ - if (scale < 0) { - long ticks_per_sec = sysconf(_SC_CLK_TCK); - if (ticks_per_sec == -1) { - ret = -errno; - goto cleanup; - } - scale = 1000000000.0 / ticks_per_sec; - } - *user *= scale; - *sys *= scale; - - ret = 0; -cleanup: - VIR_FREE(str); - return ret; -} -#else -int virCgroupGetCpuacctStat(virCgroupPtr group ATTRIBUTE_UNUSED, - unsigned long long *user ATTRIBUTE_UNUSED, - unsigned long long *sys ATTRIBUTE_UNUSED) -{ - return -ENOSYS; -} -#endif - -int virCgroupSetFreezerState(virCgroupPtr group, const char *state) -{ - return virCgroupSetValueStr(group, - VIR_CGROUP_CONTROLLER_FREEZER, - "freezer.state", state); -} - -int virCgroupGetFreezerState(virCgroupPtr group, char **state) -{ - return virCgroupGetValueStr(group, - VIR_CGROUP_CONTROLLER_FREEZER, - "freezer.state", state); -} - - -#if defined HAVE_KILL && defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -static int virCgroupKillInternal(virCgroupPtr group, int signum, virHashTablePtr pids) -{ - int rc; - int killedAny = 0; - char *keypath = NULL; - bool done = false; - FILE *fp = NULL; - VIR_DEBUG("group=%p path=%s signum=%d pids=%p", - group, group->path, signum, pids); - - rc = virCgroupPathOfController(group, -1, "tasks", &keypath); - if (rc != 0) { - VIR_DEBUG("No path of %s, tasks", group->path); - return rc; - } - - /* PIDs may be forking as we kill them, so loop - * until there are no new PIDs found - */ - while (!done) { - done = true; - if (!(fp = fopen(keypath, "r"))) { - rc = -errno; - VIR_DEBUG("Failed to read %s: %m\n", keypath); - goto cleanup; - } else { - while (!feof(fp)) { - unsigned long pid_value; - if (fscanf(fp, "%lu", &pid_value) != 1) { - if (feof(fp)) - break; - rc = -errno; - VIR_DEBUG("Failed to read %s: %m\n", keypath); - goto cleanup; - } - if (virHashLookup(pids, (void*)pid_value)) - continue; - - VIR_DEBUG("pid=%lu", pid_value); - /* Cgroups is a Linux concept, so this cast is safe. */ - if (kill((pid_t)pid_value, signum) < 0) { - if (errno != ESRCH) { - rc = -errno; - goto cleanup; - } - /* Leave RC == 0 since we didn't kill one */ - } else { - killedAny = 1; - done = false; - } - - ignore_value(virHashAddEntry(pids, (void*)pid_value, (void*)1)); - } - VIR_FORCE_FCLOSE(fp); - } - } - - rc = killedAny ? 1 : 0; - -cleanup: - VIR_FREE(keypath); - VIR_FORCE_FCLOSE(fp); - - return rc; -} - - -static uint32_t virCgroupPidCode(const void *name, uint32_t seed) -{ - unsigned long pid_value = (unsigned long)(intptr_t)name; - return virHashCodeGen(&pid_value, sizeof(pid_value), seed); -} -static bool virCgroupPidEqual(const void *namea, const void *nameb) -{ - return namea == nameb; -} -static void *virCgroupPidCopy(const void *name) -{ - return (void*)name; -} - -/* - * Returns - * < 0 : errno that occurred - * 0 : no PIDs killed - * 1 : at least one PID killed - */ -int virCgroupKill(virCgroupPtr group, int signum) -{ - VIR_DEBUG("group=%p path=%s signum=%d", group, group->path, signum); - int rc; - /* The 'tasks' file in cgroups can contain duplicated - * pids, so we use a hash to track which we've already - * killed. - */ - virHashTablePtr pids = virHashCreateFull(100, - NULL, - virCgroupPidCode, - virCgroupPidEqual, - virCgroupPidCopy, - NULL); - - rc = virCgroupKillInternal(group, signum, pids); - - virHashFree(pids); - - return rc; -} - - -static int virCgroupKillRecursiveInternal(virCgroupPtr group, int signum, virHashTablePtr pids, bool dormdir) -{ - int rc; - int killedAny = 0; - char *keypath = NULL; - DIR *dp; - virCgroupPtr subgroup = NULL; - struct dirent *ent; - VIR_DEBUG("group=%p path=%s signum=%d pids=%p", group, group->path, signum, pids); - - rc = virCgroupPathOfController(group, -1, "", &keypath); - if (rc != 0) { - VIR_DEBUG("No path of %s, tasks", group->path); - return rc; - } - - if ((rc = virCgroupKillInternal(group, signum, pids)) != 0) - return rc; - - VIR_DEBUG("Iterate over children of %s", keypath); - if (!(dp = opendir(keypath))) { - rc = -errno; - return rc; - } - - while ((ent = readdir(dp))) { - char *subpath; - - if (STREQ(ent->d_name, ".")) - continue; - if (STREQ(ent->d_name, "..")) - continue; - if (ent->d_type != DT_DIR) - continue; - - VIR_DEBUG("Process subdir %s", ent->d_name); - if (virAsprintf(&subpath, "%s/%s", group->path, ent->d_name) < 0) { - rc = -ENOMEM; - goto cleanup; - } - - if ((rc = virCgroupNew(subpath, &subgroup)) != 0) - goto cleanup; - - if ((rc = virCgroupKillRecursiveInternal(subgroup, signum, pids, true)) < 0) - goto cleanup; - if (rc == 1) - killedAny = 1; - - if (dormdir) - virCgroupRemove(subgroup); - - virCgroupFree(&subgroup); - } - - rc = killedAny; - -cleanup: - virCgroupFree(&subgroup); - closedir(dp); - - return rc; -} - -int virCgroupKillRecursive(virCgroupPtr group, int signum) -{ - int rc; - VIR_DEBUG("group=%p path=%s signum=%d", group, group->path, signum); - virHashTablePtr pids = virHashCreateFull(100, - NULL, - virCgroupPidCode, - virCgroupPidEqual, - virCgroupPidCopy, - NULL); - - rc = virCgroupKillRecursiveInternal(group, signum, pids, false); - - virHashFree(pids); - - return rc; -} - - -int virCgroupKillPainfully(virCgroupPtr group) -{ - int i; - int rc; - VIR_DEBUG("cgroup=%p path=%s", group, group->path); - for (i = 0 ; i < 15 ; i++) { - int signum; - if (i == 0) - signum = SIGTERM; - else if (i == 8) - signum = SIGKILL; - else - signum = 0; /* Just check for existence */ - - rc = virCgroupKillRecursive(group, signum); - VIR_DEBUG("Iteration %d rc=%d", i, rc); - /* If rc == -1 we hit error, if 0 we ran out of PIDs */ - if (rc <= 0) - break; - - usleep(200 * 1000); - } - VIR_DEBUG("Complete %d", rc); - return rc; -} - -#else /* !(HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R) */ -int virCgroupKill(virCgroupPtr group ATTRIBUTE_UNUSED, - int signum ATTRIBUTE_UNUSED) -{ - return -ENOSYS; -} -int virCgroupKillRecursive(virCgroupPtr group ATTRIBUTE_UNUSED, - int signum ATTRIBUTE_UNUSED) -{ - return -ENOSYS; -} - -int virCgroupKillPainfully(virCgroupPtr group ATTRIBUTE_UNUSED) -{ - return -ENOSYS; -} -#endif /* HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R */ diff --git a/src/util/cgroup.h b/src/util/cgroup.h deleted file mode 100644 index fc9e409..0000000 --- a/src/util/cgroup.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * cgroup.h: Interface to tools for managing cgroups - * - * Copyright (C) 2011-2012 Red Hat, Inc. - * Copyright IBM Corp. 2008 - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * 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_FREEZER, - VIR_CGROUP_CONTROLLER_BLKIO, - - VIR_CGROUP_CONTROLLER_LAST -}; - -VIR_ENUM_DECL(virCgroupController); - -int virCgroupForDriver(const char *name, - virCgroupPtr *group, - bool privileged, - bool create); - -int virCgroupGetAppRoot(virCgroupPtr *group); - -int virCgroupForDomain(virCgroupPtr driver, - const char *name, - virCgroupPtr *group, - bool create); - -int virCgroupForVcpu(virCgroupPtr driver, - int vcpuid, - virCgroupPtr *group, - bool create); - -int virCgroupForEmulator(virCgroupPtr driver, - virCgroupPtr *group, - bool create); - -int virCgroupPathOfController(virCgroupPtr group, - int controller, - const char *key, - char **path); - -int virCgroupAddTask(virCgroupPtr group, pid_t pid); - -int virCgroupAddTaskController(virCgroupPtr group, - pid_t pid, - int controller); - -int virCgroupMoveTask(virCgroupPtr src_group, - virCgroupPtr dest_group, - int controller); - -int virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight); -int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight); - -int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, - const char *path, - unsigned int weight); - -int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb); -int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb); - -int virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb); -int virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb); -int virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb); -int virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb); -int virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb); -int virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb); -int virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb); - -enum { - VIR_CGROUP_DEVICE_READ = 1, - VIR_CGROUP_DEVICE_WRITE = 2, - VIR_CGROUP_DEVICE_MKNOD = 4, - VIR_CGROUP_DEVICE_RW = VIR_CGROUP_DEVICE_READ | VIR_CGROUP_DEVICE_WRITE, - VIR_CGROUP_DEVICE_RWM = VIR_CGROUP_DEVICE_RW | VIR_CGROUP_DEVICE_MKNOD, -}; - -int virCgroupDenyAllDevices(virCgroupPtr group); - -int virCgroupAllowDevice(virCgroupPtr group, - char type, - int major, - int minor, - int perms); -int virCgroupAllowDeviceMajor(virCgroupPtr group, - char type, - int major, - int perms); -int virCgroupAllowDevicePath(virCgroupPtr group, - const char *path, - int perms); - -int virCgroupDenyDevice(virCgroupPtr group, - char type, - int major, - int minor, - int perms); -int virCgroupDenyDeviceMajor(virCgroupPtr group, - char type, - int major, - int perms); -int virCgroupDenyDevicePath(virCgroupPtr group, - const char *path, - int perms); - -int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares); -int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares); - -int virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period); -int virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period); - -int virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota); -int virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota); - -int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage); -int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage); -int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, - unsigned long long *sys); - -int virCgroupSetFreezerState(virCgroupPtr group, const char *state); -int virCgroupGetFreezerState(virCgroupPtr group, char **state); - -int virCgroupSetCpusetMems(virCgroupPtr group, const char *mems); -int virCgroupGetCpusetMems(virCgroupPtr group, char **mems); - -int virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus); -int virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus); - -int virCgroupRemove(virCgroupPtr group); - -void virCgroupFree(virCgroupPtr *group); -bool virCgroupMounted(virCgroupPtr cgroup, int controller); - -int virCgroupKill(virCgroupPtr group, int signum); -int virCgroupKillRecursive(virCgroupPtr group, int signum); -int virCgroupKillPainfully(virCgroupPtr group); - -#endif /* CGROUP_H */ diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c new file mode 100644 index 0000000..e9fc67f --- /dev/null +++ b/src/util/vircgroup.c @@ -0,0 +1,2099 @@ +/* + * vircgroup.c: methods for managing control cgroups + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Dan Smith <danms@us.ibm.com> + */ +#include <config.h> + +#include <stdio.h> +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +# include <mntent.h> +#endif +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <signal.h> +#include <libgen.h> +#include <dirent.h> + +#include "internal.h" +#include "util.h" +#include "memory.h" +#include "vircgroup.h" +#include "logging.h" +#include "virfile.h" +#include "virhash.h" +#include "virhashcode.h" + +#define CGROUP_MAX_VAL 512 + +VIR_ENUM_IMPL(virCgroupController, VIR_CGROUP_CONTROLLER_LAST, + "cpu", "cpuacct", "cpuset", "memory", "devices", + "freezer", "blkio"); + +struct virCgroupController { + int type; + char *mountPoint; + char *placement; +}; + +struct virCgroup { + char *path; + + struct virCgroupController controllers[VIR_CGROUP_CONTROLLER_LAST]; +}; + +typedef enum { + VIR_CGROUP_NONE = 0, /* create subdir under each cgroup if possible. */ + VIR_CGROUP_MEM_HIERACHY = 1 << 0, /* call virCgroupSetMemoryUseHierarchy + * before creating subcgroups and + * attaching tasks + */ + VIR_CGROUP_VCPU = 1 << 1, /* create subdir only under the cgroup cpu, + * cpuacct and cpuset if possible. */ +} virCgroupFlags; + +/** + * 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); +} + +/** + * virCgroupMounted: query whether a cgroup subsystem is mounted or not + * + * @cgroup: The group structure to be queried + * @controller: cgroup subsystem id + * + * Returns true if a cgroup is subsystem is mounted. + */ +bool virCgroupMounted(virCgroupPtr cgroup, int controller) +{ + return cgroup->controllers[controller].mountPoint != NULL; +} + +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +/* + * 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_ERROR(_("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); + } + /* NB, the same controller can appear >1 time in mount list + * due to bind mounts from one location to another. Pick the + * first entry only + */ + if (typelen == len && STREQLEN(typestr, tmp, len) && + !group->controllers[i].mountPoint && + !(group->controllers[i].mountPoint = strdup(entry.mnt_dir))) + goto no_memory; + tmp = next; + } + } + } + + VIR_FORCE_FCLOSE(mounts); + + return 0; + +no_memory: + VIR_FORCE_FCLOSE(mounts); + return -ENOMEM; +} + + +/* + * Process /proc/self/cgroup figuring out what cgroup + * sub-path the current process is assigned to. ie not + * necessarily 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_ERROR(_("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; + } + } + } + + VIR_FORCE_FCLOSE(mapping); + + return 0; + +no_memory: + VIR_FORCE_FCLOSE(mapping); + 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; +} +#endif + + +int virCgroupPathOfController(virCgroupPtr group, + int controller, + const char *key, + char **path) +{ + if (controller == -1) { + int i; + for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { + if (group->controllers[i].mountPoint && + group->controllers[i].placement) { + controller = i; + break; + } + } + } + if (controller == -1) + return -ENOSYS; + + 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' to '%s'", keypath, value); + rc = virFileWriteStr(keypath, value, 0); + if (rc < 0) { + rc = -errno; + VIR_DEBUG("Failed to write value '%s': %m", value); + } 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) { + VIR_DEBUG("No path of %s, %s", group->path, key); + return rc; + } + + VIR_DEBUG("Get value %s", keypath); + + rc = virFileReadAll(keypath, 1024*1024, value); + if (rc < 0) { + rc = -errno; + VIR_DEBUG("Failed to read %s: %m\n", keypath); + } else { + /* Terminated with '\n' has sometimes harmful effects to the caller */ + if ((*value)[rc - 1] == '\n') + (*value)[rc - 1] = '\0'; + + rc = 0; + } + + VIR_FREE(keypath); + + return rc; +} + +static int virCgroupSetValueU64(virCgroupPtr group, + int controller, + const char *key, + unsigned long long int value) +{ + char *strval = NULL; + int rc; + + if (virAsprintf(&strval, "%llu", value) == -1) + return -ENOMEM; + + rc = virCgroupSetValueStr(group, controller, key, strval); + + VIR_FREE(strval); + + return rc; +} + + + +static int virCgroupSetValueI64(virCgroupPtr group, + int controller, + const char *key, + long long int value) +{ + char *strval = NULL; + int rc; + + if (virAsprintf(&strval, "%lld", 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, + long long int *value) +{ + char *strval = NULL; + int rc = 0; + + rc = virCgroupGetValueStr(group, controller, key, &strval); + if (rc != 0) + goto out; + + if (virStrToLong_ll(strval, NULL, 10, value) < 0) + rc = -EINVAL; +out: + VIR_FREE(strval); + + return rc; +} + +static int virCgroupGetValueU64(virCgroupPtr group, + int controller, + const char *key, + unsigned long long int *value) +{ + char *strval = NULL; + int rc = 0; + + rc = virCgroupGetValueStr(group, controller, key, &strval); + if (rc != 0) + goto out; + + if (virStrToLong_ull(strval, NULL, 10, value) < 0) + rc = -EINVAL; +out: + VIR_FREE(strval); + + return rc; +} + + +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +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); + VIR_FREE(value); + + if (rc != 0) { + VIR_ERROR(_("Failed to set %s %d"), inherit_values[i], rc); + break; + } + } + + return rc; +} + +static int virCgroupSetMemoryUseHierarchy(virCgroupPtr group) +{ + int rc = 0; + unsigned long long value; + const char *filename = "memory.use_hierarchy"; + + rc = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + filename, &value); + if (rc != 0) { + VIR_ERROR(_("Failed to read %s/%s (%d)"), group->path, filename, rc); + return rc; + } + + /* Setting twice causes error, so if already enabled, skip setting */ + if (value == 1) + return 0; + + VIR_DEBUG("Setting up %s/%s", group->path, filename); + rc = virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + filename, 1); + + if (rc != 0) { + VIR_ERROR(_("Failed to set %s/%s (%d)"), group->path, filename, rc); + } + + return rc; +} + +static int virCgroupMakeGroup(virCgroupPtr parent, + virCgroupPtr group, + bool create, + unsigned int flags) +{ + 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; + + /* We need to control cpu bandwidth for each vcpu now */ + if ((flags & VIR_CGROUP_VCPU) && + (i != VIR_CGROUP_CONTROLLER_CPU && + i != VIR_CGROUP_CONTROLLER_CPUACCT && + i != VIR_CGROUP_CONTROLLER_CPUSET)) { + /* treat it as unmounted and we can use virCgroupAddTask */ + VIR_FREE(group->controllers[i].mountPoint); + continue; + } + + rc = virCgroupPathOfController(group, i, "", &path); + if (rc < 0) + return rc; + /* As of Feb 2011, clang can't see that the above function + * call did not modify group. */ + sa_assert(group->controllers[i].mountPoint); + + VIR_DEBUG("Make controller %s", path); + if (access(path, F_OK) != 0) { + if (!create || + mkdir(path, 0755) < 0) { + /* With a kernel that doesn't support multi-level directory + * for blkio controller, libvirt will fail and disable all + * other controllers even though they are available. So + * treat blkio as unmounted if mkdir fails. */ + if (i == VIR_CGROUP_CONTROLLER_BLKIO) { + rc = 0; + VIR_FREE(group->controllers[i].mountPoint); + VIR_FREE(path); + continue; + } else { + 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) { + VIR_FREE(path); + break; + } + } + /* + * Note that virCgroupSetMemoryUseHierarchy should always be + * called prior to creating subcgroups and attaching tasks. + */ + if ((flags & VIR_CGROUP_MEM_HIERACHY) && + (group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint != NULL) && + (i == VIR_CGROUP_CONTROLLER_MEMORY || + STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint))) { + rc = virCgroupSetMemoryUseHierarchy(group); + if (rc != 0) { + VIR_FREE(path); + 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(bool privileged, + virCgroupPtr *group, + bool create) +{ + 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(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, create, VIR_CGROUP_NONE); + +cleanup: + virCgroupFree(&rootgrp); + return rc; +} +#endif + +#if defined _DIRENT_HAVE_D_TYPE +static int virCgroupRemoveRecursively(char *grppath) +{ + DIR *grpdir; + struct dirent *ent; + int rc = 0; + + grpdir = opendir(grppath); + if (grpdir == NULL) { + if (errno == ENOENT) + return 0; + rc = -errno; + VIR_ERROR(_("Unable to open %s (%d)"), grppath, errno); + return rc; + } + + for (;;) { + char *path; + + errno = 0; + ent = readdir(grpdir); + if (ent == NULL) { + if ((rc = -errno)) + VIR_ERROR(_("Failed to readdir for %s (%d)"), grppath, errno); + break; + } + + if (ent->d_name[0] == '.') continue; + if (ent->d_type != DT_DIR) continue; + + if (virAsprintf(&path, "%s/%s", grppath, ent->d_name) == -1) { + rc = -ENOMEM; + break; + } + rc = virCgroupRemoveRecursively(path); + VIR_FREE(path); + if (rc != 0) + break; + } + closedir(grpdir); + + VIR_DEBUG("Removing cgroup %s", grppath); + if (rmdir(grppath) != 0 && errno != ENOENT) { + rc = -errno; + VIR_ERROR(_("Unable to remove %s (%d)"), grppath, errno); + } + + return rc; +} +#else +static int virCgroupRemoveRecursively(char *grppath ATTRIBUTE_UNUSED) +{ + /* Claim no support */ + return -ENXIO; +} +#endif + +/** + * virCgroupRemove: + * + * @group: The group to be removed + * + * It first removes all child groups recursively + * in depth first order and then removes @group + * because the presence of the child groups + * prevents removing @group. + * + * 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; + + VIR_DEBUG("Removing cgroup %s and all child cgroups", grppath); + rc = virCgroupRemoveRecursively(grppath); + 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; +} + +/** + * virCgroupAddTaskController: + * + * @group: The cgroup to add a task to + * @pid: The pid of the task to add + * @controller: The cgroup controller to be operated on + * + * Returns: 0 on success or -errno on failure + */ +int virCgroupAddTaskController(virCgroupPtr group, pid_t pid, int controller) +{ + if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST) + return -EINVAL; + + if (!group->controllers[controller].mountPoint) + return -EINVAL; + + return virCgroupSetValueU64(group, controller, "tasks", + (unsigned long long)pid); +} + + +static int virCgroupAddTaskStrController(virCgroupPtr group, + const char *pidstr, + int controller) +{ + char *str = NULL, *cur = NULL, *next = NULL; + unsigned long long p = 0; + int rc = 0; + char *endp; + + if (virAsprintf(&str, "%s", pidstr) < 0) + return -1; + + cur = str; + while (*cur != '\0') { + rc = virStrToLong_ull(cur, &endp, 10, &p); + if (rc != 0) + goto cleanup; + + rc = virCgroupAddTaskController(group, p, controller); + if (rc != 0) + goto cleanup; + + next = strchr(cur, '\n'); + if (next) { + cur = next + 1; + *next = '\0'; + } else { + break; + } + } + +cleanup: + VIR_FREE(str); + return rc; +} + +/** + * virCgroupMoveTask: + * + * @src_group: The source cgroup where all tasks are removed from + * @dest_group: The destination where all tasks are added to + * @controller: The cgroup controller to be operated on + * + * Returns: 0 on success or -errno on failure + */ +int virCgroupMoveTask(virCgroupPtr src_group, virCgroupPtr dest_group, + int controller) +{ + int rc = 0, err = 0; + char *content = NULL; + + if (controller < VIR_CGROUP_CONTROLLER_CPU || + controller > VIR_CGROUP_CONTROLLER_BLKIO) + return -EINVAL; + + if (!src_group->controllers[controller].mountPoint || + !dest_group->controllers[controller].mountPoint) { + VIR_WARN("no vm cgroup in controller %d", controller); + return 0; + } + + rc = virCgroupGetValueStr(src_group, controller, "tasks", &content); + if (rc != 0) + return rc; + + rc = virCgroupAddTaskStrController(dest_group, content, controller); + if (rc != 0) + goto cleanup; + + VIR_FREE(content); + + return 0; + +cleanup: + /* + * We don't need to recover dest_cgroup because cgroup will make sure + * that one task only resides in one cgroup of the same controller. + */ + err = virCgroupAddTaskStrController(src_group, content, controller); + if (err != 0) + VIR_ERROR(_("Cannot recover cgroup %s from %s"), + src_group->controllers[controller].mountPoint, + dest_group->controllers[controller].mountPoint); + VIR_FREE(content); + + return rc; +} + +/** + * virCgroupForDriver: + * + * @name: name of this driver (e.g., xen, qemu, lxc) + * @group: Pointer to returned virCgroupPtr + * + * Returns 0 on success + */ +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +int virCgroupForDriver(const char *name, + virCgroupPtr *group, + bool privileged, + bool create) +{ + int rc; + char *path = NULL; + virCgroupPtr rootgrp = NULL; + + rc = virCgroupAppRoot(privileged, &rootgrp, create); + 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) { + rc = virCgroupMakeGroup(rootgrp, *group, create, VIR_CGROUP_NONE); + if (rc != 0) + virCgroupFree(group); + } + +out: + virCgroupFree(&rootgrp); + + return rc; +} +#else +int virCgroupForDriver(const char *name ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED, + bool privileged ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED) +{ + /* Claim no support */ + return -ENXIO; +} +#endif + +/** +* virCgroupGetAppRoot: +* +* @group: Pointer to returned virCgroupPtr +* +* Returns 0 on success +*/ +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +int virCgroupGetAppRoot(virCgroupPtr *group) +{ + return virCgroupNew("/", group); +} +#else +int virCgroupGetAppRoot(virCgroupPtr *group ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} +#endif + +/** + * virCgroupForDomain: + * + * @driver: group for driver owning the domain + * @name: name of the domain + * @group: Pointer to returned virCgroupPtr + * + * Returns 0 on success + */ +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +int virCgroupForDomain(virCgroupPtr driver, + const char *name, + virCgroupPtr *group, + bool create) +{ + int rc; + char *path; + + if (driver == NULL) + return -EINVAL; + + if (virAsprintf(&path, "%s/%s", driver->path, name) < 0) + return -ENOMEM; + + rc = virCgroupNew(path, group); + VIR_FREE(path); + + if (rc == 0) { + /* + * Create a cgroup with memory.use_hierarchy enabled to + * surely account memory usage of lxc with ns subsystem + * enabled. (To be exact, memory and ns subsystems are + * enabled at the same time.) + * + * The reason why doing it here, not a upper group, say + * a group for driver, is to avoid overhead to track + * cumulative usage that we don't need. + */ + rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_MEM_HIERACHY); + if (rc != 0) + virCgroupFree(group); + } + + return rc; +} +#else +int virCgroupForDomain(virCgroupPtr driver ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} +#endif + +/** + * virCgroupForVcpu: + * + * @driver: group for the domain + * @vcpuid: id of the vcpu + * @group: Pointer to returned virCgroupPtr + * + * Returns 0 on success + */ +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +int virCgroupForVcpu(virCgroupPtr driver, + int vcpuid, + virCgroupPtr *group, + bool create) +{ + int rc; + char *path; + + if (driver == NULL) + return -EINVAL; + + if (virAsprintf(&path, "%s/vcpu%d", driver->path, vcpuid) < 0) + return -ENOMEM; + + rc = virCgroupNew(path, group); + VIR_FREE(path); + + if (rc == 0) { + rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_VCPU); + if (rc != 0) + virCgroupFree(group); + } + + return rc; +} +#else +int virCgroupForVcpu(virCgroupPtr driver ATTRIBUTE_UNUSED, + int vcpuid ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} +#endif + +/** + * virCgroupForEmulator: + * + * @driver: group for the domain + * @group: Pointer to returned virCgroupPtr + * + * Returns: 0 on success or -errno on failure + */ +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +int virCgroupForEmulator(virCgroupPtr driver, + virCgroupPtr *group, + bool create) +{ + int rc; + char *path; + + if (driver == NULL) + return -EINVAL; + + if (virAsprintf(&path, "%s/emulator", driver->path) < 0) + return -ENOMEM; + + rc = virCgroupNew(path, group); + VIR_FREE(path); + + if (rc == 0) { + rc = virCgroupMakeGroup(driver, *group, create, VIR_CGROUP_VCPU); + if (rc != 0) + virCgroupFree(group); + } + + return rc; +} +#else +int virCgroupForEmulator(virCgroupPtr driver ATTRIBUTE_UNUSED, + virCgroupPtr *group ATTRIBUTE_UNUSED, + bool create ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +#endif +/** + * virCgroupSetBlkioWeight: + * + * @group: The cgroup to change io weight for + * @weight: The Weight for this cgroup + * + * Returns: 0 on success + */ +int virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight) +{ + if (weight > 1000 || weight < 100) + return -EINVAL; + + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_BLKIO, + "blkio.weight", + weight); +} + +/** + * virCgroupGetBlkioWeight: + * + * @group: The cgroup to get weight for + * @Weight: Pointer to returned weight + * + * Returns: 0 on success + */ +int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight) +{ + unsigned long long tmp; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_BLKIO, + "blkio.weight", &tmp); + if (ret == 0) + *weight = tmp; + return ret; +} + +/** + * virCgroupSetBlkioDeviceWeight: + * + * @group: The cgroup to change io device weight device for + * @path: The device with a weight to alter + * @weight: The new device weight (100-1000), or 0 to clear + * + * device_weight is treated as a write-only parameter, so + * there isn't a getter counterpart. + * + * Returns: 0 on success, -errno on failure + */ +#if defined(major) && defined(minor) +int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, + const char *path, + unsigned int weight) +{ + char *str; + struct stat sb; + int ret; + + if (weight && (weight > 1000 || weight < 100)) + return -EINVAL; + + if (stat(path, &sb) < 0) + return -errno; + + if (!S_ISBLK(sb.st_mode)) + return -EINVAL; + + if (virAsprintf(&str, "%d:%d %d", major(sb.st_rdev), minor(sb.st_rdev), + weight) < 0) + return -errno; + + ret = virCgroupSetValueStr(group, + VIR_CGROUP_CONTROLLER_BLKIO, + "blkio.weight_device", + str); + VIR_FREE(str); + return ret; +} +#else +int +virCgroupSetBlkioDeviceWeight(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + unsigned int weight ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} +#endif + +/** + * virCgroupSetMemory: + * + * @group: The cgroup to change memory for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb) +{ + unsigned long long maxkb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; + + if (kb > maxkb) + return -EINVAL; + else if (kb == maxkb) + return virCgroupSetValueI64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.limit_in_bytes", + -1); + else + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.limit_in_bytes", + kb << 10); +} + +/** + * virCgroupGetMemoryUsage: + * + * @group: The cgroup to change memory for + * @kb: Pointer to returned used memory in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb) +{ + long long unsigned int usage_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.usage_in_bytes", &usage_in_bytes); + if (ret == 0) + *kb = (unsigned long) usage_in_bytes >> 10; + return ret; +} + +/** + * virCgroupSetMemoryHardLimit: + * + * @group: The cgroup to change memory hard limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb) +{ + return virCgroupSetMemory(group, kb); +} + +/** + * virCgroupGetMemoryHardLimit: + * + * @group: The cgroup to get the memory hard limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb) +{ + long long unsigned int limit_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.limit_in_bytes", &limit_in_bytes); + if (ret == 0) + *kb = limit_in_bytes >> 10; + return ret; +} + +/** + * virCgroupSetMemorySoftLimit: + * + * @group: The cgroup to change memory soft limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb) +{ + unsigned long long maxkb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; + + if (kb > maxkb) + return -EINVAL; + else if (kb == maxkb) + return virCgroupSetValueI64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.soft_limit_in_bytes", + -1); + else + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.soft_limit_in_bytes", + kb << 10); +} + + +/** + * virCgroupGetMemorySoftLimit: + * + * @group: The cgroup to get the memory soft limit for + * @kb: The memory amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb) +{ + long long unsigned int limit_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.soft_limit_in_bytes", &limit_in_bytes); + if (ret == 0) + *kb = limit_in_bytes >> 10; + return ret; +} + +/** + * virCgroupSetMemSwapHardLimit: + * + * @group: The cgroup to change mem+swap hard limit for + * @kb: The mem+swap amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb) +{ + unsigned long long maxkb = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED; + + if (kb > maxkb) + return -EINVAL; + else if (kb == maxkb) + return virCgroupSetValueI64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.memsw.limit_in_bytes", + -1); + else + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.memsw.limit_in_bytes", + kb << 10); +} + +/** + * virCgroupGetMemSwapHardLimit: + * + * @group: The cgroup to get mem+swap hard limit for + * @kb: The mem+swap amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb) +{ + long long unsigned int limit_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.memsw.limit_in_bytes", &limit_in_bytes); + if (ret == 0) + *kb = limit_in_bytes >> 10; + return ret; +} + +/** + * virCgroupGetMemSwapUsage: + * + * @group: The cgroup to get mem+swap usage for + * @kb: The mem+swap amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb) +{ + long long unsigned int usage_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.memsw.usage_in_bytes", &usage_in_bytes); + if (ret == 0) + *kb = usage_in_bytes >> 10; + return ret; +} + +/** + * virCgroupSetCpusetMems: + * + * @group: The cgroup to set cpuset.mems for + * @mems: the numa nodes to set + * + * Returns: 0 on success + */ +int virCgroupSetCpusetMems(virCgroupPtr group, const char *mems) +{ + return virCgroupSetValueStr(group, + VIR_CGROUP_CONTROLLER_CPUSET, + "cpuset.mems", + mems); +} + +/** + * virCgroupGetCpusetMems: + * + * @group: The cgroup to get cpuset.mems for + * @mems: the numa nodes to get + * + * Returns: 0 on success + */ +int virCgroupGetCpusetMems(virCgroupPtr group, char **mems) +{ + return virCgroupGetValueStr(group, + VIR_CGROUP_CONTROLLER_CPUSET, + "cpuset.mems", + mems); +} + +/** + * virCgroupSetCpusetCpus: + * + * @group: The cgroup to set cpuset.cpus for + * @cpus: the cpus to set + * + * Retuens: 0 on success + */ +int virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus) +{ + return virCgroupSetValueStr(group, + VIR_CGROUP_CONTROLLER_CPUSET, + "cpuset.cpus", + cpus); +} + +/** + * virCgroupGetCpusetCpus: + * + * @group: The cgroup to get cpuset.cpus for + * @cpus: the cpus to get + * + * Retuens: 0 on success + */ +int virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus) +{ + return virCgroupGetValueStr(group, + VIR_CGROUP_CONTROLLER_CPUSET, + "cpuset.cpus", + cpus); +} + +/** + * virCgroupDenyAllDevices: + * + * @group: The cgroup to deny all permissions, for all devices + * + * 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 + * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow + * + * Returns: 0 on success + */ +int virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor, + int perms) +{ + int rc; + char *devstr = NULL; + + if (virAsprintf(&devstr, "%c %i:%i %s%s%s", type, major, minor, + perms & VIR_CGROUP_DEVICE_READ ? "r" : "", + perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", + perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -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 + * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow + * + * Returns: 0 on success + */ +int virCgroupAllowDeviceMajor(virCgroupPtr group, char type, int major, + int perms) +{ + int rc; + char *devstr = NULL; + + if (virAsprintf(&devstr, "%c %i:* %s%s%s", type, major, + perms & VIR_CGROUP_DEVICE_READ ? "r" : "", + perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", + perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -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 + * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to allow + * + * Queries the type of device and its major/minor number, and + * adds that to the cgroup ACL + * + * Returns: 0 on success, 1 if path exists but is not a device, or + * negative errno value on failure + */ +#if defined(major) && defined(minor) +int virCgroupAllowDevicePath(virCgroupPtr group, const char *path, int perms) +{ + struct stat sb; + + if (stat(path, &sb) < 0) + return -errno; + + if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) + return 1; + + return virCgroupAllowDevice(group, + S_ISCHR(sb.st_mode) ? 'c' : 'b', + major(sb.st_rdev), + minor(sb.st_rdev), + perms); +} +#else +int virCgroupAllowDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} +#endif + + +/** + * 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 + * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to deny + * + * Returns: 0 on success + */ +int virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor, + int perms) +{ + int rc; + char *devstr = NULL; + + if (virAsprintf(&devstr, "%c %i:%i %s%s%s", type, major, minor, + perms & VIR_CGROUP_DEVICE_READ ? "r" : "", + perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", + perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -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 + * @perms: Bitwise or of VIR_CGROUP_DEVICE permission bits to deny + * + * Returns: 0 on success + */ +int virCgroupDenyDeviceMajor(virCgroupPtr group, char type, int major, + int perms) +{ + int rc; + char *devstr = NULL; + + if (virAsprintf(&devstr, "%c %i:* %s%s%s", type, major, + perms & VIR_CGROUP_DEVICE_READ ? "r" : "", + perms & VIR_CGROUP_DEVICE_WRITE ? "w" : "", + perms & VIR_CGROUP_DEVICE_MKNOD ? "m" : "") == -1) { + rc = -ENOMEM; + goto out; + } + + rc = virCgroupSetValueStr(group, + VIR_CGROUP_CONTROLLER_DEVICES, + "devices.deny", + devstr); + out: + VIR_FREE(devstr); + + return rc; +} + +#if defined(major) && defined(minor) +int virCgroupDenyDevicePath(virCgroupPtr group, const char *path, int perms) +{ + struct stat sb; + + if (stat(path, &sb) < 0) + return -errno; + + if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) + return 1; + + return virCgroupDenyDevice(group, + S_ISCHR(sb.st_mode) ? 'c' : 'b', + major(sb.st_rdev), + minor(sb.st_rdev), + perms); +} +#else +int virCgroupDenyDevicePath(virCgroupPtr group ATTRIBUTE_UNUSED, + const char *path ATTRIBUTE_UNUSED, + int perms ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} +#endif + +int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares) +{ + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_CPU, + "cpu.shares", shares); +} + +int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares) +{ + return virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_CPU, + "cpu.shares", shares); +} + +/** + * virCgroupSetCpuCfsPeriod: + * + * @group: The cgroup to change cpu.cfs_period_us for + * @cfs_period: The bandwidth period in usecs + * + * Returns: 0 on success + */ +int virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period) +{ + /* The cfs_period shoule be greater or equal than 1ms, and less or equal + * than 1s. + */ + if (cfs_period < 1000 || cfs_period > 1000000) + return -EINVAL; + + return virCgroupSetValueU64(group, + VIR_CGROUP_CONTROLLER_CPU, + "cpu.cfs_period_us", cfs_period); +} + +/** + * virCgroupGetCpuCfsPeriod: + * + * @group: The cgroup to get cpu.cfs_period_us for + * @cfs_period: Pointer to the returned bandwidth period in usecs + * + * Returns: 0 on success + */ +int virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period) +{ + return virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_CPU, + "cpu.cfs_period_us", cfs_period); +} + +/** + * virCgroupSetCpuCfsQuota: + * + * @group: The cgroup to change cpu.cfs_quota_us for + * @cfs_quota: the cpu bandwidth (in usecs) that this tg will be allowed to + * consume over period + * + * Returns: 0 on success + */ +int virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota) +{ + if (cfs_quota >= 0) { + /* The cfs_quota shoule be greater or equal than 1ms */ + if (cfs_quota < 1000) + return -EINVAL; + + /* check overflow */ + if (cfs_quota > ULLONG_MAX / 1000) + return -EINVAL; + } + + return virCgroupSetValueI64(group, + VIR_CGROUP_CONTROLLER_CPU, + "cpu.cfs_quota_us", cfs_quota); +} + +/** + * virCgroupGetCpuCfsQuota: + * + * @group: The cgroup to get cpu.cfs_quota_us for + * @cfs_quota: Pointer to the returned cpu bandwidth (in usecs) that this tg + * will be allowed to consume over period + * + * Returns: 0 on success + */ +int virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota) +{ + return virCgroupGetValueI64(group, + VIR_CGROUP_CONTROLLER_CPU, + "cpu.cfs_quota_us", cfs_quota); +} + +int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage) +{ + return virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_CPUACCT, + "cpuacct.usage", usage); +} + +int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage) +{ + return virCgroupGetValueStr(group, VIR_CGROUP_CONTROLLER_CPUACCT, + "cpuacct.usage_percpu", usage); +} + +#ifdef _SC_CLK_TCK +int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, + unsigned long long *sys) +{ + char *str; + char *p; + int ret; + static double scale = -1.0; + + if ((ret = virCgroupGetValueStr(group, VIR_CGROUP_CONTROLLER_CPUACCT, + "cpuacct.stat", &str)) < 0) + return ret; + if (!(p = STRSKIP(str, "user ")) || + virStrToLong_ull(p, &p, 10, user) < 0 || + !(p = STRSKIP(p, "\nsystem ")) || + virStrToLong_ull(p, NULL, 10, sys) < 0) { + ret = -EINVAL; + goto cleanup; + } + /* times reported are in system ticks (generally 100 Hz), but that + * rate can theoretically vary between machines. Scale things + * into approximate nanoseconds. */ + if (scale < 0) { + long ticks_per_sec = sysconf(_SC_CLK_TCK); + if (ticks_per_sec == -1) { + ret = -errno; + goto cleanup; + } + scale = 1000000000.0 / ticks_per_sec; + } + *user *= scale; + *sys *= scale; + + ret = 0; +cleanup: + VIR_FREE(str); + return ret; +} +#else +int virCgroupGetCpuacctStat(virCgroupPtr group ATTRIBUTE_UNUSED, + unsigned long long *user ATTRIBUTE_UNUSED, + unsigned long long *sys ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} +#endif + +int virCgroupSetFreezerState(virCgroupPtr group, const char *state) +{ + return virCgroupSetValueStr(group, + VIR_CGROUP_CONTROLLER_FREEZER, + "freezer.state", state); +} + +int virCgroupGetFreezerState(virCgroupPtr group, char **state) +{ + return virCgroupGetValueStr(group, + VIR_CGROUP_CONTROLLER_FREEZER, + "freezer.state", state); +} + + +#if defined HAVE_KILL && defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +static int virCgroupKillInternal(virCgroupPtr group, int signum, virHashTablePtr pids) +{ + int rc; + int killedAny = 0; + char *keypath = NULL; + bool done = false; + FILE *fp = NULL; + VIR_DEBUG("group=%p path=%s signum=%d pids=%p", + group, group->path, signum, pids); + + rc = virCgroupPathOfController(group, -1, "tasks", &keypath); + if (rc != 0) { + VIR_DEBUG("No path of %s, tasks", group->path); + return rc; + } + + /* PIDs may be forking as we kill them, so loop + * until there are no new PIDs found + */ + while (!done) { + done = true; + if (!(fp = fopen(keypath, "r"))) { + rc = -errno; + VIR_DEBUG("Failed to read %s: %m\n", keypath); + goto cleanup; + } else { + while (!feof(fp)) { + unsigned long pid_value; + if (fscanf(fp, "%lu", &pid_value) != 1) { + if (feof(fp)) + break; + rc = -errno; + VIR_DEBUG("Failed to read %s: %m\n", keypath); + goto cleanup; + } + if (virHashLookup(pids, (void*)pid_value)) + continue; + + VIR_DEBUG("pid=%lu", pid_value); + /* Cgroups is a Linux concept, so this cast is safe. */ + if (kill((pid_t)pid_value, signum) < 0) { + if (errno != ESRCH) { + rc = -errno; + goto cleanup; + } + /* Leave RC == 0 since we didn't kill one */ + } else { + killedAny = 1; + done = false; + } + + ignore_value(virHashAddEntry(pids, (void*)pid_value, (void*)1)); + } + VIR_FORCE_FCLOSE(fp); + } + } + + rc = killedAny ? 1 : 0; + +cleanup: + VIR_FREE(keypath); + VIR_FORCE_FCLOSE(fp); + + return rc; +} + + +static uint32_t virCgroupPidCode(const void *name, uint32_t seed) +{ + unsigned long pid_value = (unsigned long)(intptr_t)name; + return virHashCodeGen(&pid_value, sizeof(pid_value), seed); +} +static bool virCgroupPidEqual(const void *namea, const void *nameb) +{ + return namea == nameb; +} +static void *virCgroupPidCopy(const void *name) +{ + return (void*)name; +} + +/* + * Returns + * < 0 : errno that occurred + * 0 : no PIDs killed + * 1 : at least one PID killed + */ +int virCgroupKill(virCgroupPtr group, int signum) +{ + VIR_DEBUG("group=%p path=%s signum=%d", group, group->path, signum); + int rc; + /* The 'tasks' file in cgroups can contain duplicated + * pids, so we use a hash to track which we've already + * killed. + */ + virHashTablePtr pids = virHashCreateFull(100, + NULL, + virCgroupPidCode, + virCgroupPidEqual, + virCgroupPidCopy, + NULL); + + rc = virCgroupKillInternal(group, signum, pids); + + virHashFree(pids); + + return rc; +} + + +static int virCgroupKillRecursiveInternal(virCgroupPtr group, int signum, virHashTablePtr pids, bool dormdir) +{ + int rc; + int killedAny = 0; + char *keypath = NULL; + DIR *dp; + virCgroupPtr subgroup = NULL; + struct dirent *ent; + VIR_DEBUG("group=%p path=%s signum=%d pids=%p", group, group->path, signum, pids); + + rc = virCgroupPathOfController(group, -1, "", &keypath); + if (rc != 0) { + VIR_DEBUG("No path of %s, tasks", group->path); + return rc; + } + + if ((rc = virCgroupKillInternal(group, signum, pids)) != 0) + return rc; + + VIR_DEBUG("Iterate over children of %s", keypath); + if (!(dp = opendir(keypath))) { + rc = -errno; + return rc; + } + + while ((ent = readdir(dp))) { + char *subpath; + + if (STREQ(ent->d_name, ".")) + continue; + if (STREQ(ent->d_name, "..")) + continue; + if (ent->d_type != DT_DIR) + continue; + + VIR_DEBUG("Process subdir %s", ent->d_name); + if (virAsprintf(&subpath, "%s/%s", group->path, ent->d_name) < 0) { + rc = -ENOMEM; + goto cleanup; + } + + if ((rc = virCgroupNew(subpath, &subgroup)) != 0) + goto cleanup; + + if ((rc = virCgroupKillRecursiveInternal(subgroup, signum, pids, true)) < 0) + goto cleanup; + if (rc == 1) + killedAny = 1; + + if (dormdir) + virCgroupRemove(subgroup); + + virCgroupFree(&subgroup); + } + + rc = killedAny; + +cleanup: + virCgroupFree(&subgroup); + closedir(dp); + + return rc; +} + +int virCgroupKillRecursive(virCgroupPtr group, int signum) +{ + int rc; + VIR_DEBUG("group=%p path=%s signum=%d", group, group->path, signum); + virHashTablePtr pids = virHashCreateFull(100, + NULL, + virCgroupPidCode, + virCgroupPidEqual, + virCgroupPidCopy, + NULL); + + rc = virCgroupKillRecursiveInternal(group, signum, pids, false); + + virHashFree(pids); + + return rc; +} + + +int virCgroupKillPainfully(virCgroupPtr group) +{ + int i; + int rc; + VIR_DEBUG("cgroup=%p path=%s", group, group->path); + for (i = 0 ; i < 15 ; i++) { + int signum; + if (i == 0) + signum = SIGTERM; + else if (i == 8) + signum = SIGKILL; + else + signum = 0; /* Just check for existence */ + + rc = virCgroupKillRecursive(group, signum); + VIR_DEBUG("Iteration %d rc=%d", i, rc); + /* If rc == -1 we hit error, if 0 we ran out of PIDs */ + if (rc <= 0) + break; + + usleep(200 * 1000); + } + VIR_DEBUG("Complete %d", rc); + return rc; +} + +#else /* !(HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R) */ +int virCgroupKill(virCgroupPtr group ATTRIBUTE_UNUSED, + int signum ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} +int virCgroupKillRecursive(virCgroupPtr group ATTRIBUTE_UNUSED, + int signum ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} + +int virCgroupKillPainfully(virCgroupPtr group ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} +#endif /* HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R */ diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h new file mode 100644 index 0000000..8b6d3b2 --- /dev/null +++ b/src/util/vircgroup.h @@ -0,0 +1,167 @@ +/* + * vircgroup.h: methods for managing control cgroups + * + * Copyright (C) 2011-2012 Red Hat, Inc. + * Copyright IBM Corp. 2008 + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Dan Smith <danms@us.ibm.com> + */ + +#ifndef __VIR_CGROUP_H__ +# define __VIR_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_FREEZER, + VIR_CGROUP_CONTROLLER_BLKIO, + + VIR_CGROUP_CONTROLLER_LAST +}; + +VIR_ENUM_DECL(virCgroupController); + +int virCgroupForDriver(const char *name, + virCgroupPtr *group, + bool privileged, + bool create); + +int virCgroupGetAppRoot(virCgroupPtr *group); + +int virCgroupForDomain(virCgroupPtr driver, + const char *name, + virCgroupPtr *group, + bool create); + +int virCgroupForVcpu(virCgroupPtr driver, + int vcpuid, + virCgroupPtr *group, + bool create); + +int virCgroupForEmulator(virCgroupPtr driver, + virCgroupPtr *group, + bool create); + +int virCgroupPathOfController(virCgroupPtr group, + int controller, + const char *key, + char **path); + +int virCgroupAddTask(virCgroupPtr group, pid_t pid); + +int virCgroupAddTaskController(virCgroupPtr group, + pid_t pid, + int controller); + +int virCgroupMoveTask(virCgroupPtr src_group, + virCgroupPtr dest_group, + int controller); + +int virCgroupSetBlkioWeight(virCgroupPtr group, unsigned int weight); +int virCgroupGetBlkioWeight(virCgroupPtr group, unsigned int *weight); + +int virCgroupSetBlkioDeviceWeight(virCgroupPtr group, + const char *path, + unsigned int weight); + +int virCgroupSetMemory(virCgroupPtr group, unsigned long long kb); +int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb); + +int virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb); +int virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb); +int virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb); +int virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb); +int virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb); +int virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb); +int virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb); + +enum { + VIR_CGROUP_DEVICE_READ = 1, + VIR_CGROUP_DEVICE_WRITE = 2, + VIR_CGROUP_DEVICE_MKNOD = 4, + VIR_CGROUP_DEVICE_RW = VIR_CGROUP_DEVICE_READ | VIR_CGROUP_DEVICE_WRITE, + VIR_CGROUP_DEVICE_RWM = VIR_CGROUP_DEVICE_RW | VIR_CGROUP_DEVICE_MKNOD, +}; + +int virCgroupDenyAllDevices(virCgroupPtr group); + +int virCgroupAllowDevice(virCgroupPtr group, + char type, + int major, + int minor, + int perms); +int virCgroupAllowDeviceMajor(virCgroupPtr group, + char type, + int major, + int perms); +int virCgroupAllowDevicePath(virCgroupPtr group, + const char *path, + int perms); + +int virCgroupDenyDevice(virCgroupPtr group, + char type, + int major, + int minor, + int perms); +int virCgroupDenyDeviceMajor(virCgroupPtr group, + char type, + int major, + int perms); +int virCgroupDenyDevicePath(virCgroupPtr group, + const char *path, + int perms); + +int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares); +int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares); + +int virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period); +int virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period); + +int virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota); +int virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota); + +int virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage); +int virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage); +int virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, + unsigned long long *sys); + +int virCgroupSetFreezerState(virCgroupPtr group, const char *state); +int virCgroupGetFreezerState(virCgroupPtr group, char **state); + +int virCgroupSetCpusetMems(virCgroupPtr group, const char *mems); +int virCgroupGetCpusetMems(virCgroupPtr group, char **mems); + +int virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus); +int virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus); + +int virCgroupRemove(virCgroupPtr group); + +void virCgroupFree(virCgroupPtr *group); +bool virCgroupMounted(virCgroupPtr cgroup, int controller); + +int virCgroupKill(virCgroupPtr group, int signum); +int virCgroupKillRecursive(virCgroupPtr group, int signum); +int virCgroupKillPainfully(virCgroupPtr group); + +#endif /* __VIR_CGROUP_H__ */ -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/Makefile.am | 2 +- src/conf/cpu_conf.h | 2 +- src/conf/domain_conf.c | 3 +- src/conf/domain_conf.h | 2 +- src/conf/network_conf.h | 2 +- src/conf/snapshot_conf.c | 2 +- src/libxl/libxl_conf.h | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_conf.h | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_monitor.h | 2 +- src/qemu/qemu_monitor_json.h | 2 +- src/qemu/qemu_process.c | 2 +- src/util/bitmap.c | 636 ------------------------------------------- src/util/bitmap.h | 109 -------- src/util/dnsmasq.c | 2 +- src/util/processinfo.h | 2 +- src/util/virbitmap.c | 636 +++++++++++++++++++++++++++++++++++++++++++ src/util/virbitmap.h | 109 ++++++++ tests/virbitmaptest.c | 2 +- tools/virsh-domain.c | 2 +- tools/virsh.c | 2 +- 22 files changed, 763 insertions(+), 764 deletions(-) delete mode 100644 src/util/bitmap.c delete mode 100644 src/util/bitmap.h create mode 100644 src/util/virbitmap.c create mode 100644 src/util/virbitmap.h diff --git a/src/Makefile.am b/src/Makefile.am index 149ffc9..25a21e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/bitmap.c util/bitmap.h \ util/buf.c util/buf.h \ util/command.c util/command.h \ util/conf.c util/conf.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/viraudit.c util/viraudit.h \ util/virauth.c util/virauth.h \ util/virauthconfig.c util/virauthconfig.h \ + util/virbitmap.c util/virbitmap.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 879f8eb..38fc675 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -27,7 +27,7 @@ # include "util.h" # include "buf.h" # include "xml.h" -# include "bitmap.h" +# include "virbitmap.h" # define VIR_CPU_VENDOR_ID_LENGTH 12 diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 19af058..c90c6b9 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -44,14 +44,13 @@ #include "nwfilter_conf.h" #include "storage_file.h" #include "virfile.h" -#include "bitmap.h" +#include "virbitmap.h" #include "count-one-bits.h" #include "secret_conf.h" #include "netdev_vport_profile_conf.h" #include "netdev_bandwidth_conf.h" #include "netdev_vlan_conf.h" #include "device_conf.h" -#include "bitmap.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bc9ef88..26d2264 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -46,7 +46,7 @@ # include "virnetdevvlan.h" # include "virobject.h" # include "device_conf.h" -# include "bitmap.h" +# include "virbitmap.h" # include "storage_file.h" /* forward declarations of all device types, required by diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 72cf64b..4d70fe6 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -38,7 +38,7 @@ # include "virnetdevvlan.h" # include "virmacaddr.h" # include "device_conf.h" -# include "bitmap.h" +# include "virbitmap.h" enum virNetworkForwardType { VIR_NETWORK_FORWARD_NONE = 0, diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index bba1bb7..95b7943 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -29,7 +29,7 @@ #include <unistd.h> #include "internal.h" -#include "bitmap.h" +#include "virbitmap.h" #include "buf.h" #include "count-one-bits.h" #include "datatypes.h" diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index 6bcf805..c8808a1 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -34,7 +34,7 @@ # include "domain_event.h" # include "capabilities.h" # include "configmake.h" -# include "bitmap.h" +# include "virbitmap.h" # define LIBXL_VNC_PORT_MIN 5900 diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 104a3f8..45962b0 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -35,7 +35,7 @@ #include "cpu/cpu.h" #include "domain_conf.h" #include "command.h" -#include "bitmap.h" +#include "virbitmap.h" #include "virnodesuspend.h" #include "qemu_monitor.h" diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index cfa6fff..bcf21c3 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -39,7 +39,7 @@ # include "hostusb.h" # include "cpu_conf.h" # include "driver.h" -# include "bitmap.h" +# include "virbitmap.h" # include "command.h" # include "threadpool.h" # include "locking/lock_manager.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 2dd6922..e87397f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -92,7 +92,7 @@ #include "virnodesuspend.h" #include "virtime.h" #include "virtypedparam.h" -#include "bitmap.h" +#include "virbitmap.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index dbfab88..8c42b12 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -28,7 +28,7 @@ # include "internal.h" # include "domain_conf.h" -# include "bitmap.h" +# include "virbitmap.h" # include "virhash.h" # include "json.h" # include "device_conf.h" diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index acca4ec..2b09a8f 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -28,7 +28,7 @@ # include "internal.h" # include "qemu_monitor.h" -# include "bitmap.h" +# include "virbitmap.h" int qemuMonitorJSONIOProcess(qemuMonitorPtr mon, const char *data, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index cc0e947..969cbc7 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -69,7 +69,7 @@ #include "virprocess.h" #include "virtime.h" #include "virnetdevtap.h" -#include "bitmap.h" +#include "virbitmap.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/util/bitmap.c b/src/util/bitmap.c deleted file mode 100644 index c29f5f3..0000000 --- a/src/util/bitmap.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * bitmap.h: Simple bitmap operations - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * Copyright (C) 2010 Novell, 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Jim Fehlig <jfehlig@novell.com> - */ - -#include <config.h> - -#include <limits.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <sys/types.h> - -#include "bitmap.h" -#include "memory.h" -#include "buf.h" -#include "util.h" -#include "c-ctype.h" -#include "count-one-bits.h" - - -struct _virBitmap { - size_t max_bit; - size_t map_len; - unsigned long *map; -}; - - -#define VIR_BITMAP_BITS_PER_UNIT ((int) sizeof(unsigned long) * CHAR_BIT) -#define VIR_BITMAP_UNIT_OFFSET(b) ((b) / VIR_BITMAP_BITS_PER_UNIT) -#define VIR_BITMAP_BIT_OFFSET(b) ((b) % VIR_BITMAP_BITS_PER_UNIT) -#define VIR_BITMAP_BIT(b) (1UL << VIR_BITMAP_BIT_OFFSET(b)) - - -/** - * virBitmapNew: - * @size: number of bits - * - * Allocate a bitmap capable of containing @size bits. - * - * Returns a pointer to the allocated bitmap or NULL if - * memory cannot be allocated. - */ -virBitmapPtr virBitmapNew(size_t size) -{ - virBitmapPtr bitmap; - size_t sz; - - if (SIZE_MAX - VIR_BITMAP_BITS_PER_UNIT < size || size == 0) - return NULL; - - sz = (size + VIR_BITMAP_BITS_PER_UNIT - 1) / - VIR_BITMAP_BITS_PER_UNIT; - - if (VIR_ALLOC(bitmap) < 0) - return NULL; - - if (VIR_ALLOC_N(bitmap->map, sz) < 0) { - VIR_FREE(bitmap); - return NULL; - } - - bitmap->max_bit = size; - bitmap->map_len = sz; - return bitmap; -} - -/** - * virBitmapFree: - * @bitmap: previously allocated bitmap - * - * Free @bitmap previously allocated by virBitmapNew. - */ -void virBitmapFree(virBitmapPtr bitmap) -{ - if (bitmap) { - VIR_FREE(bitmap->map); - VIR_FREE(bitmap); - } -} - - -int virBitmapCopy(virBitmapPtr dst, virBitmapPtr src) -{ - if (dst->max_bit != src->max_bit) { - errno = EINVAL; - return -1; - } - - memcpy(dst->map, src->map, src->map_len * sizeof(src->map[0])); - - return 0; -} - - -/** - * virBitmapSetBit: - * @bitmap: Pointer to bitmap - * @b: bit position to set - * - * Set bit position @b in @bitmap - * - * Returns 0 on if bit is successfully set, -1 on error. - */ -int virBitmapSetBit(virBitmapPtr bitmap, size_t b) -{ - if (bitmap->max_bit <= b) - return -1; - - bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] |= VIR_BITMAP_BIT(b); - return 0; -} - -/** - * virBitmapClearBit: - * @bitmap: Pointer to bitmap - * @b: bit position to clear - * - * Clear bit position @b in @bitmap - * - * Returns 0 on if bit is successfully clear, -1 on error. - */ -int virBitmapClearBit(virBitmapPtr bitmap, size_t b) -{ - if (bitmap->max_bit <= b) - return -1; - - bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &= ~VIR_BITMAP_BIT(b); - return 0; -} - -/* Helper function. caller must ensure b < bitmap->max_bit */ -static bool virBitmapIsSet(virBitmapPtr bitmap, size_t b) -{ - return !!(bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] & VIR_BITMAP_BIT(b)); -} - -/** - * virBitmapGetBit: - * @bitmap: Pointer to bitmap - * @b: bit position to get - * @result: bool pointer to receive bit setting - * - * Get setting of bit position @b in @bitmap and store in @result - * - * On success, @result will contain the setting of @b and 0 is - * returned. On failure, -1 is returned and @result is unchanged. - */ -int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result) -{ - if (bitmap->max_bit <= b) - return -1; - - *result = virBitmapIsSet(bitmap, b); - return 0; -} - -/** - * virBitmapString: - * @bitmap: Pointer to bitmap - * - * Convert @bitmap to printable string. - * - * Returns pointer to the string or NULL on error. - */ -char *virBitmapString(virBitmapPtr bitmap) -{ - virBuffer buf = VIR_BUFFER_INITIALIZER; - size_t sz; - - virBufferAddLit(&buf, "0x"); - - sz = bitmap->map_len; - - while (sz--) { - virBufferAsprintf(&buf, "%0*lx", - VIR_BITMAP_BITS_PER_UNIT / 4, - bitmap->map[sz]); - } - - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - return NULL; - } - - return virBufferContentAndReset(&buf); -} - -/** - * virBitmapFormat: - * @bitmap: the bitmap - * - * This function is the counterpart of virBitmapParse. This function creates - * a human-readable string representing the bits in bitmap. - * - * See virBitmapParse for the format of @str. - * - * Returns the string on success or NULL otherwise. Caller should call - * VIR_FREE to free the string. - */ -char *virBitmapFormat(virBitmapPtr bitmap) -{ - virBuffer buf = VIR_BUFFER_INITIALIZER; - bool first = true; - int start, cur, prev; - - if (!bitmap) - return NULL; - - cur = virBitmapNextSetBit(bitmap, -1); - if (cur < 0) - return strdup(""); - - start = prev = cur; - while (prev >= 0) { - cur = virBitmapNextSetBit(bitmap, prev); - - if (cur == prev + 1) { - prev = cur; - continue; - } - - /* cur < 0 or cur > prev + 1 */ - - if (!first) - virBufferAddLit(&buf, ","); - else - first = false; - - if (prev == start) - virBufferAsprintf(&buf, "%d", start); - else - virBufferAsprintf(&buf, "%d-%d", start, prev); - - start = prev = cur; - } - - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - return NULL; - } - - return virBufferContentAndReset(&buf); -} - -/** - * virBitmapParse: - * @str: points to a string representing a human-readable bitmap - * @bitmap: a bitmap created from @str - * @bitmapSize: the upper limit of num of bits in created bitmap - * - * This function is the counterpart of virBitmapFormat. This function creates - * a bitmap, in which bits are set according to the content of @str. - * - * @str is a comma separated string of fields N, which means a number of bit - * to set, and ^N, which means to unset the bit, and N-M for ranges of bits - * to set. - * - * Returns the number of bits set in @bitmap, or -1 in case of error. - */ - -int virBitmapParse(const char *str, - char sep, - virBitmapPtr *bitmap, - size_t bitmapSize) -{ - int ret = 0; - bool neg = false; - const char *cur; - char *tmp; - int i, start, last; - - if (!str) - return -1; - - cur = str; - virSkipSpaces(&cur); - - if (*cur == 0) - return -1; - - *bitmap = virBitmapNew(bitmapSize); - if (!*bitmap) - return -1; - - while (*cur != 0 && *cur != sep) { - /* - * 3 constructs are allowed: - * - N : a single CPU number - * - N-M : a range of CPU numbers with N < M - * - ^N : remove a single CPU number from the current set - */ - if (*cur == '^') { - cur++; - neg = true; - } - - if (!c_isdigit(*cur)) - goto parse_error; - - if (virStrToLong_i(cur, &tmp, 10, &start) < 0) - goto parse_error; - if (start < 0) - goto parse_error; - - cur = tmp; - - virSkipSpaces(&cur); - - if (*cur == ',' || *cur == 0 || *cur == sep) { - if (neg) { - if (virBitmapIsSet(*bitmap, start)) { - ignore_value(virBitmapClearBit(*bitmap, start)); - ret--; - } - } else { - if (!virBitmapIsSet(*bitmap, start)) { - ignore_value(virBitmapSetBit(*bitmap, start)); - ret++; - } - } - } else if (*cur == '-') { - if (neg) - goto parse_error; - - cur++; - virSkipSpaces(&cur); - - if (virStrToLong_i(cur, &tmp, 10, &last) < 0) - goto parse_error; - if (last < start) - goto parse_error; - - cur = tmp; - - for (i = start; i <= last; i++) { - if (!virBitmapIsSet(*bitmap, i)) { - ignore_value(virBitmapSetBit(*bitmap, i)); - ret++; - } - } - - virSkipSpaces(&cur); - } - - if (*cur == ',') { - cur++; - virSkipSpaces(&cur); - neg = false; - } else if (*cur == 0 || *cur == sep) { - break; - } else { - goto parse_error; - } - } - - return ret; - -parse_error: - virBitmapFree(*bitmap); - *bitmap = NULL; - return -1; -} - -/** - * virBitmapNewCopy: - * @src: the source bitmap. - * - * Makes a copy of bitmap @src. - * - * returns the copied bitmap on success, or NULL otherwise. Caller - * should call virBitmapFree to free the returned bitmap. - */ -virBitmapPtr virBitmapNewCopy(virBitmapPtr src) -{ - virBitmapPtr dst; - - if ((dst = virBitmapNew(src->max_bit)) == NULL) - return NULL; - - if (virBitmapCopy(dst, src) != 0) { - virBitmapFree(dst); - return NULL; - } - - return dst; -} - -/** - * virBitmapNewData: - * @data: the data - * @len: length of @data in bytes - * - * Allocate a bitmap from a chunk of data containing bits - * information - * - * Returns a pointer to the allocated bitmap or NULL if - * memory cannot be allocated. - */ -virBitmapPtr virBitmapNewData(void *data, int len) -{ - virBitmapPtr bitmap; - int i, j; - unsigned long *p; - unsigned char *bytes = data; - - bitmap = virBitmapNew(len * CHAR_BIT); - if (!bitmap) - return NULL; - - /* le64toh is not provided by gnulib, so we do the conversion by hand */ - p = bitmap->map; - for (i = j = 0; i < len; i++, j++) { - if (j == sizeof(*p)) { - j = 0; - p++; - } - *p |= (unsigned long) bytes[i] << (j * CHAR_BIT); - } - - return bitmap; -} - -/** - * virBitmapToData: - * @data: the data - * @len: len of @data in byte - * - * Convert a bitmap to a chunk of data containing bits information. - * Data consists of sequential bytes, with lower bytes containing - * lower bits. - * - * Returns 0 on success, -1 otherwise. - */ -int virBitmapToData(virBitmapPtr bitmap, unsigned char **data, int *dataLen) -{ - int len; - unsigned long *l; - int i, j; - unsigned char *bytes; - - len = (bitmap->max_bit + CHAR_BIT - 1) / CHAR_BIT; - - if (VIR_ALLOC_N(*data, len) < 0) - return -1; - - bytes = *data; - *dataLen = len; - - /* htole64 is not provided by gnulib, so we do the conversion by hand */ - l = bitmap->map; - for (i = j = 0; i < len; i++, j++) { - if (j == sizeof(*l)) { - j = 0; - l++; - } - bytes[i] = *l >> (j * CHAR_BIT); - } - - return 0; -} - -/** - * virBitmapEqual: - * @b1: bitmap 1 - * @b2: bitmap 2 - * - * Compares two bitmaps, whose lengths can be different from each other. - * - * Returns true if two bitmaps have exactly the same set of bits set, - * otherwise false. - */ -bool virBitmapEqual(virBitmapPtr b1, virBitmapPtr b2) -{ - virBitmapPtr tmp; - int i; - - if (b1->max_bit > b2->max_bit) { - tmp = b1; - b1 = b2; - b2 = tmp; - } - - /* Now b1 is the smaller one, if not equal */ - - for (i = 0; i < b1->map_len; i++) { - if (b1->map[i] != b2->map[i]) - return false; - } - - for (; i < b2->map_len; i++) { - if (b2->map[i]) - return false; - } - - return true; -} - -size_t virBitmapSize(virBitmapPtr bitmap) -{ - return bitmap->max_bit; -} - -/** - * virBitmapSetAll: - * @bitmap: the bitmap - * - * set all bits in @bitmap. - */ -void virBitmapSetAll(virBitmapPtr bitmap) -{ - int tail = bitmap->max_bit % VIR_BITMAP_BITS_PER_UNIT; - - memset(bitmap->map, 0xff, - bitmap->map_len * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT)); - - /* Ensure tail bits are clear. */ - if (tail) - bitmap->map[bitmap->map_len - 1] &= - -1UL >> (VIR_BITMAP_BITS_PER_UNIT - tail); -} - -/** - * virBitmapClearAll: - * @bitmap: the bitmap - * - * clear all bits in @bitmap. - */ -void virBitmapClearAll(virBitmapPtr bitmap) -{ - memset(bitmap->map, 0, - bitmap->map_len * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT)); -} - -/** - * virBitmapIsAllSet: - * @bitmap: the bitmap to check - * - * check if all bits in @bitmap are set. - */ -bool virBitmapIsAllSet(virBitmapPtr bitmap) -{ - int i; - int unusedBits; - size_t sz; - - unusedBits = bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT - bitmap->max_bit; - - sz = bitmap->map_len; - if (unusedBits > 0) - sz--; - - for (i = 0; i < sz; i++) - if (bitmap->map[i] != -1) - return false; - - if (unusedBits > 0) { - if ((bitmap->map[sz] & ((1UL << (VIR_BITMAP_BITS_PER_UNIT - unusedBits)) - 1)) - != ((1UL << (VIR_BITMAP_BITS_PER_UNIT - unusedBits)) - 1)) - return false; - } - - return true; -} - -/** - * virBitmapNextSetBit: - * @bitmap: the bitmap - * @pos: the position after which to search for a set bit - * - * search the first set bit after position @pos in bitmap @bitmap. - * @pos can be -1 to search for the first set bit. Position starts - * at 0. - * - * returns the position of the found bit, or -1 if no bit found. - */ -ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) -{ - size_t nl; - size_t nb; - unsigned long bits; - - if (pos < 0) - pos = -1; - - pos++; - - if (pos >= bitmap->max_bit) - return -1; - - nl = pos / VIR_BITMAP_BITS_PER_UNIT; - nb = pos % VIR_BITMAP_BITS_PER_UNIT; - - bits = bitmap->map[nl] & ~((1UL << nb) - 1); - - while (bits == 0 && ++nl < bitmap->map_len) { - bits = bitmap->map[nl]; - } - - if (bits == 0) - return -1; - - return ffsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT; -} - -/* Return the number of bits currently set in the map. */ -size_t -virBitmapCountBits(virBitmapPtr bitmap) -{ - size_t i; - size_t ret = 0; - - for (i = 0; i < bitmap->map_len; i++) - ret += count_one_bits_l(bitmap->map[i]); - - return ret; -} diff --git a/src/util/bitmap.h b/src/util/bitmap.h deleted file mode 100644 index 346a1fb..0000000 --- a/src/util/bitmap.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * bitmap.h: Simple bitmap operations - * - * Copyright (C) 2012 Red Hat, Inc. - * Copyright (C) 2010 Novell, 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Jim Fehlig <jfehlig@novell.com> - */ - -#ifndef __BITMAP_H__ -# define __BITMAP_H__ - -# include "internal.h" - -# include <sys/types.h> - - -typedef struct _virBitmap virBitmap; -typedef virBitmap *virBitmapPtr; - -/* - * Allocate a bitmap capable of containing @size bits. - */ -virBitmapPtr virBitmapNew(size_t size) ATTRIBUTE_RETURN_CHECK; - -/* - * Free previously allocated bitmap - */ -void virBitmapFree(virBitmapPtr bitmap); - -/* - * Copy all bits from @src to @dst. The bitmap sizes - * must be the same - */ -int virBitmapCopy(virBitmapPtr dst, virBitmapPtr src); - -/* - * Set bit position @b in @bitmap - */ -int virBitmapSetBit(virBitmapPtr bitmap, size_t b) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -/* - * Clear bit position @b in @bitmap - */ -int virBitmapClearBit(virBitmapPtr bitmap, size_t b) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -/* - * Get setting of bit position @b in @bitmap and store in @result - */ -int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; - -char *virBitmapString(virBitmapPtr bitmap) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -char *virBitmapFormat(virBitmapPtr bitmap) - ATTRIBUTE_NONNULL(1); - -int virBitmapParse(const char *str, - char sep, - virBitmapPtr *bitmap, - size_t bitmapSize) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); - -virBitmapPtr virBitmapNewCopy(virBitmapPtr src) ATTRIBUTE_NONNULL(1); - -virBitmapPtr virBitmapNewData(void *data, int len) ATTRIBUTE_NONNULL(1); - -int virBitmapToData(virBitmapPtr bitmap, unsigned char **data, int *dataLen) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -bool virBitmapEqual(virBitmapPtr b1, virBitmapPtr b2) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -size_t virBitmapSize(virBitmapPtr bitmap) - ATTRIBUTE_NONNULL(1); - -void virBitmapSetAll(virBitmapPtr bitmap) - ATTRIBUTE_NONNULL(1); - -void virBitmapClearAll(virBitmapPtr bitmap) - ATTRIBUTE_NONNULL(1); - -bool virBitmapIsAllSet(virBitmapPtr bitmap) - ATTRIBUTE_NONNULL(1); - -ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) - ATTRIBUTE_NONNULL(1); - -size_t virBitmapCountBits(virBitmapPtr bitmap) - ATTRIBUTE_NONNULL(1); - -#endif diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c index e8eab1e..74593c8 100644 --- a/src/util/dnsmasq.c +++ b/src/util/dnsmasq.c @@ -39,7 +39,7 @@ #include "internal.h" #include "datatypes.h" -#include "bitmap.h" +#include "virbitmap.h" #include "dnsmasq.h" #include "util.h" #include "command.h" diff --git a/src/util/processinfo.h b/src/util/processinfo.h index 116c092..0ae23c6 100644 --- a/src/util/processinfo.h +++ b/src/util/processinfo.h @@ -23,7 +23,7 @@ # define __VIR_PROCESSINFO_H__ # include "internal.h" -# include "bitmap.h" +# include "virbitmap.h" int virProcessInfoSetAffinity(pid_t pid, virBitmapPtr map); diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c new file mode 100644 index 0000000..0f13389 --- /dev/null +++ b/src/util/virbitmap.c @@ -0,0 +1,636 @@ +/* + * bitmap.h: Simple bitmap operations + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright (C) 2010 Novell, 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Jim Fehlig <jfehlig@novell.com> + */ + +#include <config.h> + +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> + +#include "virbitmap.h" +#include "memory.h" +#include "buf.h" +#include "util.h" +#include "c-ctype.h" +#include "count-one-bits.h" + + +struct _virBitmap { + size_t max_bit; + size_t map_len; + unsigned long *map; +}; + + +#define VIR_BITMAP_BITS_PER_UNIT ((int) sizeof(unsigned long) * CHAR_BIT) +#define VIR_BITMAP_UNIT_OFFSET(b) ((b) / VIR_BITMAP_BITS_PER_UNIT) +#define VIR_BITMAP_BIT_OFFSET(b) ((b) % VIR_BITMAP_BITS_PER_UNIT) +#define VIR_BITMAP_BIT(b) (1UL << VIR_BITMAP_BIT_OFFSET(b)) + + +/** + * virBitmapNew: + * @size: number of bits + * + * Allocate a bitmap capable of containing @size bits. + * + * Returns a pointer to the allocated bitmap or NULL if + * memory cannot be allocated. + */ +virBitmapPtr virBitmapNew(size_t size) +{ + virBitmapPtr bitmap; + size_t sz; + + if (SIZE_MAX - VIR_BITMAP_BITS_PER_UNIT < size || size == 0) + return NULL; + + sz = (size + VIR_BITMAP_BITS_PER_UNIT - 1) / + VIR_BITMAP_BITS_PER_UNIT; + + if (VIR_ALLOC(bitmap) < 0) + return NULL; + + if (VIR_ALLOC_N(bitmap->map, sz) < 0) { + VIR_FREE(bitmap); + return NULL; + } + + bitmap->max_bit = size; + bitmap->map_len = sz; + return bitmap; +} + +/** + * virBitmapFree: + * @bitmap: previously allocated bitmap + * + * Free @bitmap previously allocated by virBitmapNew. + */ +void virBitmapFree(virBitmapPtr bitmap) +{ + if (bitmap) { + VIR_FREE(bitmap->map); + VIR_FREE(bitmap); + } +} + + +int virBitmapCopy(virBitmapPtr dst, virBitmapPtr src) +{ + if (dst->max_bit != src->max_bit) { + errno = EINVAL; + return -1; + } + + memcpy(dst->map, src->map, src->map_len * sizeof(src->map[0])); + + return 0; +} + + +/** + * virBitmapSetBit: + * @bitmap: Pointer to bitmap + * @b: bit position to set + * + * Set bit position @b in @bitmap + * + * Returns 0 on if bit is successfully set, -1 on error. + */ +int virBitmapSetBit(virBitmapPtr bitmap, size_t b) +{ + if (bitmap->max_bit <= b) + return -1; + + bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] |= VIR_BITMAP_BIT(b); + return 0; +} + +/** + * virBitmapClearBit: + * @bitmap: Pointer to bitmap + * @b: bit position to clear + * + * Clear bit position @b in @bitmap + * + * Returns 0 on if bit is successfully clear, -1 on error. + */ +int virBitmapClearBit(virBitmapPtr bitmap, size_t b) +{ + if (bitmap->max_bit <= b) + return -1; + + bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] &= ~VIR_BITMAP_BIT(b); + return 0; +} + +/* Helper function. caller must ensure b < bitmap->max_bit */ +static bool virBitmapIsSet(virBitmapPtr bitmap, size_t b) +{ + return !!(bitmap->map[VIR_BITMAP_UNIT_OFFSET(b)] & VIR_BITMAP_BIT(b)); +} + +/** + * virBitmapGetBit: + * @bitmap: Pointer to bitmap + * @b: bit position to get + * @result: bool pointer to receive bit setting + * + * Get setting of bit position @b in @bitmap and store in @result + * + * On success, @result will contain the setting of @b and 0 is + * returned. On failure, -1 is returned and @result is unchanged. + */ +int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result) +{ + if (bitmap->max_bit <= b) + return -1; + + *result = virBitmapIsSet(bitmap, b); + return 0; +} + +/** + * virBitmapString: + * @bitmap: Pointer to bitmap + * + * Convert @bitmap to printable string. + * + * Returns pointer to the string or NULL on error. + */ +char *virBitmapString(virBitmapPtr bitmap) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + size_t sz; + + virBufferAddLit(&buf, "0x"); + + sz = bitmap->map_len; + + while (sz--) { + virBufferAsprintf(&buf, "%0*lx", + VIR_BITMAP_BITS_PER_UNIT / 4, + bitmap->map[sz]); + } + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + return NULL; + } + + return virBufferContentAndReset(&buf); +} + +/** + * virBitmapFormat: + * @bitmap: the bitmap + * + * This function is the counterpart of virBitmapParse. This function creates + * a human-readable string representing the bits in bitmap. + * + * See virBitmapParse for the format of @str. + * + * Returns the string on success or NULL otherwise. Caller should call + * VIR_FREE to free the string. + */ +char *virBitmapFormat(virBitmapPtr bitmap) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + bool first = true; + int start, cur, prev; + + if (!bitmap) + return NULL; + + cur = virBitmapNextSetBit(bitmap, -1); + if (cur < 0) + return strdup(""); + + start = prev = cur; + while (prev >= 0) { + cur = virBitmapNextSetBit(bitmap, prev); + + if (cur == prev + 1) { + prev = cur; + continue; + } + + /* cur < 0 or cur > prev + 1 */ + + if (!first) + virBufferAddLit(&buf, ","); + else + first = false; + + if (prev == start) + virBufferAsprintf(&buf, "%d", start); + else + virBufferAsprintf(&buf, "%d-%d", start, prev); + + start = prev = cur; + } + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + return NULL; + } + + return virBufferContentAndReset(&buf); +} + +/** + * virBitmapParse: + * @str: points to a string representing a human-readable bitmap + * @bitmap: a bitmap created from @str + * @bitmapSize: the upper limit of num of bits in created bitmap + * + * This function is the counterpart of virBitmapFormat. This function creates + * a bitmap, in which bits are set according to the content of @str. + * + * @str is a comma separated string of fields N, which means a number of bit + * to set, and ^N, which means to unset the bit, and N-M for ranges of bits + * to set. + * + * Returns the number of bits set in @bitmap, or -1 in case of error. + */ + +int virBitmapParse(const char *str, + char sep, + virBitmapPtr *bitmap, + size_t bitmapSize) +{ + int ret = 0; + bool neg = false; + const char *cur; + char *tmp; + int i, start, last; + + if (!str) + return -1; + + cur = str; + virSkipSpaces(&cur); + + if (*cur == 0) + return -1; + + *bitmap = virBitmapNew(bitmapSize); + if (!*bitmap) + return -1; + + while (*cur != 0 && *cur != sep) { + /* + * 3 constructs are allowed: + * - N : a single CPU number + * - N-M : a range of CPU numbers with N < M + * - ^N : remove a single CPU number from the current set + */ + if (*cur == '^') { + cur++; + neg = true; + } + + if (!c_isdigit(*cur)) + goto parse_error; + + if (virStrToLong_i(cur, &tmp, 10, &start) < 0) + goto parse_error; + if (start < 0) + goto parse_error; + + cur = tmp; + + virSkipSpaces(&cur); + + if (*cur == ',' || *cur == 0 || *cur == sep) { + if (neg) { + if (virBitmapIsSet(*bitmap, start)) { + ignore_value(virBitmapClearBit(*bitmap, start)); + ret--; + } + } else { + if (!virBitmapIsSet(*bitmap, start)) { + ignore_value(virBitmapSetBit(*bitmap, start)); + ret++; + } + } + } else if (*cur == '-') { + if (neg) + goto parse_error; + + cur++; + virSkipSpaces(&cur); + + if (virStrToLong_i(cur, &tmp, 10, &last) < 0) + goto parse_error; + if (last < start) + goto parse_error; + + cur = tmp; + + for (i = start; i <= last; i++) { + if (!virBitmapIsSet(*bitmap, i)) { + ignore_value(virBitmapSetBit(*bitmap, i)); + ret++; + } + } + + virSkipSpaces(&cur); + } + + if (*cur == ',') { + cur++; + virSkipSpaces(&cur); + neg = false; + } else if (*cur == 0 || *cur == sep) { + break; + } else { + goto parse_error; + } + } + + return ret; + +parse_error: + virBitmapFree(*bitmap); + *bitmap = NULL; + return -1; +} + +/** + * virBitmapNewCopy: + * @src: the source bitmap. + * + * Makes a copy of bitmap @src. + * + * returns the copied bitmap on success, or NULL otherwise. Caller + * should call virBitmapFree to free the returned bitmap. + */ +virBitmapPtr virBitmapNewCopy(virBitmapPtr src) +{ + virBitmapPtr dst; + + if ((dst = virBitmapNew(src->max_bit)) == NULL) + return NULL; + + if (virBitmapCopy(dst, src) != 0) { + virBitmapFree(dst); + return NULL; + } + + return dst; +} + +/** + * virBitmapNewData: + * @data: the data + * @len: length of @data in bytes + * + * Allocate a bitmap from a chunk of data containing bits + * information + * + * Returns a pointer to the allocated bitmap or NULL if + * memory cannot be allocated. + */ +virBitmapPtr virBitmapNewData(void *data, int len) +{ + virBitmapPtr bitmap; + int i, j; + unsigned long *p; + unsigned char *bytes = data; + + bitmap = virBitmapNew(len * CHAR_BIT); + if (!bitmap) + return NULL; + + /* le64toh is not provided by gnulib, so we do the conversion by hand */ + p = bitmap->map; + for (i = j = 0; i < len; i++, j++) { + if (j == sizeof(*p)) { + j = 0; + p++; + } + *p |= (unsigned long) bytes[i] << (j * CHAR_BIT); + } + + return bitmap; +} + +/** + * virBitmapToData: + * @data: the data + * @len: len of @data in byte + * + * Convert a bitmap to a chunk of data containing bits information. + * Data consists of sequential bytes, with lower bytes containing + * lower bits. + * + * Returns 0 on success, -1 otherwise. + */ +int virBitmapToData(virBitmapPtr bitmap, unsigned char **data, int *dataLen) +{ + int len; + unsigned long *l; + int i, j; + unsigned char *bytes; + + len = (bitmap->max_bit + CHAR_BIT - 1) / CHAR_BIT; + + if (VIR_ALLOC_N(*data, len) < 0) + return -1; + + bytes = *data; + *dataLen = len; + + /* htole64 is not provided by gnulib, so we do the conversion by hand */ + l = bitmap->map; + for (i = j = 0; i < len; i++, j++) { + if (j == sizeof(*l)) { + j = 0; + l++; + } + bytes[i] = *l >> (j * CHAR_BIT); + } + + return 0; +} + +/** + * virBitmapEqual: + * @b1: bitmap 1 + * @b2: bitmap 2 + * + * Compares two bitmaps, whose lengths can be different from each other. + * + * Returns true if two bitmaps have exactly the same set of bits set, + * otherwise false. + */ +bool virBitmapEqual(virBitmapPtr b1, virBitmapPtr b2) +{ + virBitmapPtr tmp; + int i; + + if (b1->max_bit > b2->max_bit) { + tmp = b1; + b1 = b2; + b2 = tmp; + } + + /* Now b1 is the smaller one, if not equal */ + + for (i = 0; i < b1->map_len; i++) { + if (b1->map[i] != b2->map[i]) + return false; + } + + for (; i < b2->map_len; i++) { + if (b2->map[i]) + return false; + } + + return true; +} + +size_t virBitmapSize(virBitmapPtr bitmap) +{ + return bitmap->max_bit; +} + +/** + * virBitmapSetAll: + * @bitmap: the bitmap + * + * set all bits in @bitmap. + */ +void virBitmapSetAll(virBitmapPtr bitmap) +{ + int tail = bitmap->max_bit % VIR_BITMAP_BITS_PER_UNIT; + + memset(bitmap->map, 0xff, + bitmap->map_len * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT)); + + /* Ensure tail bits are clear. */ + if (tail) + bitmap->map[bitmap->map_len - 1] &= + -1UL >> (VIR_BITMAP_BITS_PER_UNIT - tail); +} + +/** + * virBitmapClearAll: + * @bitmap: the bitmap + * + * clear all bits in @bitmap. + */ +void virBitmapClearAll(virBitmapPtr bitmap) +{ + memset(bitmap->map, 0, + bitmap->map_len * (VIR_BITMAP_BITS_PER_UNIT / CHAR_BIT)); +} + +/** + * virBitmapIsAllSet: + * @bitmap: the bitmap to check + * + * check if all bits in @bitmap are set. + */ +bool virBitmapIsAllSet(virBitmapPtr bitmap) +{ + int i; + int unusedBits; + size_t sz; + + unusedBits = bitmap->map_len * VIR_BITMAP_BITS_PER_UNIT - bitmap->max_bit; + + sz = bitmap->map_len; + if (unusedBits > 0) + sz--; + + for (i = 0; i < sz; i++) + if (bitmap->map[i] != -1) + return false; + + if (unusedBits > 0) { + if ((bitmap->map[sz] & ((1UL << (VIR_BITMAP_BITS_PER_UNIT - unusedBits)) - 1)) + != ((1UL << (VIR_BITMAP_BITS_PER_UNIT - unusedBits)) - 1)) + return false; + } + + return true; +} + +/** + * virBitmapNextSetBit: + * @bitmap: the bitmap + * @pos: the position after which to search for a set bit + * + * search the first set bit after position @pos in bitmap @bitmap. + * @pos can be -1 to search for the first set bit. Position starts + * at 0. + * + * returns the position of the found bit, or -1 if no bit found. + */ +ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) +{ + size_t nl; + size_t nb; + unsigned long bits; + + if (pos < 0) + pos = -1; + + pos++; + + if (pos >= bitmap->max_bit) + return -1; + + nl = pos / VIR_BITMAP_BITS_PER_UNIT; + nb = pos % VIR_BITMAP_BITS_PER_UNIT; + + bits = bitmap->map[nl] & ~((1UL << nb) - 1); + + while (bits == 0 && ++nl < bitmap->map_len) { + bits = bitmap->map[nl]; + } + + if (bits == 0) + return -1; + + return ffsl(bits) - 1 + nl * VIR_BITMAP_BITS_PER_UNIT; +} + +/* Return the number of bits currently set in the map. */ +size_t +virBitmapCountBits(virBitmapPtr bitmap) +{ + size_t i; + size_t ret = 0; + + for (i = 0; i < bitmap->map_len; i++) + ret += count_one_bits_l(bitmap->map[i]); + + return ret; +} diff --git a/src/util/virbitmap.h b/src/util/virbitmap.h new file mode 100644 index 0000000..346a1fb --- /dev/null +++ b/src/util/virbitmap.h @@ -0,0 +1,109 @@ +/* + * bitmap.h: Simple bitmap operations + * + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2010 Novell, 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Jim Fehlig <jfehlig@novell.com> + */ + +#ifndef __BITMAP_H__ +# define __BITMAP_H__ + +# include "internal.h" + +# include <sys/types.h> + + +typedef struct _virBitmap virBitmap; +typedef virBitmap *virBitmapPtr; + +/* + * Allocate a bitmap capable of containing @size bits. + */ +virBitmapPtr virBitmapNew(size_t size) ATTRIBUTE_RETURN_CHECK; + +/* + * Free previously allocated bitmap + */ +void virBitmapFree(virBitmapPtr bitmap); + +/* + * Copy all bits from @src to @dst. The bitmap sizes + * must be the same + */ +int virBitmapCopy(virBitmapPtr dst, virBitmapPtr src); + +/* + * Set bit position @b in @bitmap + */ +int virBitmapSetBit(virBitmapPtr bitmap, size_t b) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +/* + * Clear bit position @b in @bitmap + */ +int virBitmapClearBit(virBitmapPtr bitmap, size_t b) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +/* + * Get setting of bit position @b in @bitmap and store in @result + */ +int virBitmapGetBit(virBitmapPtr bitmap, size_t b, bool *result) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; + +char *virBitmapString(virBitmapPtr bitmap) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +char *virBitmapFormat(virBitmapPtr bitmap) + ATTRIBUTE_NONNULL(1); + +int virBitmapParse(const char *str, + char sep, + virBitmapPtr *bitmap, + size_t bitmapSize) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); + +virBitmapPtr virBitmapNewCopy(virBitmapPtr src) ATTRIBUTE_NONNULL(1); + +virBitmapPtr virBitmapNewData(void *data, int len) ATTRIBUTE_NONNULL(1); + +int virBitmapToData(virBitmapPtr bitmap, unsigned char **data, int *dataLen) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +bool virBitmapEqual(virBitmapPtr b1, virBitmapPtr b2) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +size_t virBitmapSize(virBitmapPtr bitmap) + ATTRIBUTE_NONNULL(1); + +void virBitmapSetAll(virBitmapPtr bitmap) + ATTRIBUTE_NONNULL(1); + +void virBitmapClearAll(virBitmapPtr bitmap) + ATTRIBUTE_NONNULL(1); + +bool virBitmapIsAllSet(virBitmapPtr bitmap) + ATTRIBUTE_NONNULL(1); + +ssize_t virBitmapNextSetBit(virBitmapPtr bitmap, ssize_t pos) + ATTRIBUTE_NONNULL(1); + +size_t virBitmapCountBits(virBitmapPtr bitmap) + ATTRIBUTE_NONNULL(1); + +#endif diff --git a/tests/virbitmaptest.c b/tests/virbitmaptest.c index af94dab..db76672 100644 --- a/tests/virbitmaptest.c +++ b/tests/virbitmaptest.c @@ -21,7 +21,7 @@ #include "testutils.h" -#include "bitmap.h" +#include "virbitmap.h" static int test1(const void *data ATTRIBUTE_UNUSED) { diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 561e0e7..765f30c 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -37,7 +37,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "bitmap.h" +#include "virbitmap.h" #include "buf.h" #include "c-ctype.h" #include "conf/domain_conf.h" diff --git a/tools/virsh.c b/tools/virsh.c index 465cb44..2f7d4a3 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -69,7 +69,7 @@ #include "command.h" #include "virkeycode.h" #include "virnetdevbandwidth.h" -#include "util/bitmap.h" +#include "virbitmap.h" #include "conf/domain_conf.h" #include "virtypedparam.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/Makefile.am | 2 +- src/conf/capabilities.c | 2 +- src/conf/capabilities.h | 2 +- src/conf/cpu_conf.c | 2 +- src/conf/cpu_conf.h | 2 +- src/conf/device_conf.c | 2 +- src/conf/device_conf.h | 2 +- src/conf/domain_conf.c | 2 +- src/conf/interface_conf.c | 2 +- src/conf/netdev_bandwidth_conf.h | 2 +- src/conf/netdev_vlan_conf.h | 2 +- src/conf/netdev_vport_profile_conf.h | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 2 +- src/conf/nwfilter_conf.h | 2 +- src/conf/nwfilter_params.h | 2 +- src/conf/secret_conf.c | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/conf/storage_encryption_conf.h | 2 +- src/cpu/cpu_powerpc.c | 2 +- src/cpu/cpu_x86.c | 2 +- src/esx/esx_vi.c | 2 +- src/esx/esx_vi_methods.c | 2 +- src/esx/esx_vi_types.c | 2 +- src/esx/esx_vi_types.h | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/hyperv/hyperv_wmi.h | 2 +- src/lxc/lxc_fuse.c | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/nwfilter/nwfilter_ebiptables_driver.c | 2 +- src/nwfilter/nwfilter_learnipaddr.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_monitor_text.c | 2 +- src/remote/remote_driver.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/buf.c | 682 ------------------------------ src/util/buf.h | 82 ---- src/util/command.c | 2 +- src/util/command.h | 2 +- src/util/conf.c | 2 +- src/util/logging.c | 2 +- src/util/logging.h | 2 +- src/util/sexpr.h | 2 +- src/util/sysinfo.h | 2 +- src/util/util.c | 2 +- src/util/virbitmap.c | 2 +- src/util/virbuffer.c | 682 ++++++++++++++++++++++++++++++ src/util/virbuffer.h | 82 ++++ src/util/virstring.c | 2 +- src/util/viruri.c | 2 +- src/util/xml.c | 2 +- src/xen/xen_hypervisor.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xend_internal.h | 2 +- src/xen/xm_internal.c | 2 +- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 2 +- tests/cputest.c | 2 +- tests/testutils.c | 2 +- tests/virbuftest.c | 2 +- tools/virsh-domain.c | 2 +- tools/virsh-host.c | 2 +- tools/virsh-interface.c | 2 +- tools/virsh-network.c | 2 +- tools/virsh-nodedev.c | 2 +- tools/virsh-nwfilter.c | 2 +- tools/virsh-pool.c | 2 +- tools/virsh-secret.c | 2 +- tools/virsh-snapshot.c | 2 +- tools/virsh-volume.c | 2 +- tools/virsh.c | 2 +- 82 files changed, 842 insertions(+), 842 deletions(-) delete mode 100644 src/util/buf.c delete mode 100644 src/util/buf.h create mode 100644 src/util/virbuffer.c create mode 100644 src/util/virbuffer.h diff --git a/src/Makefile.am b/src/Makefile.am index 25a21e8..fd21aa6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/buf.c util/buf.h \ util/command.c util/command.h \ util/conf.c util/conf.h \ util/event.c util/event.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virauth.c util/virauth.h \ util/virauthconfig.c util/virauthconfig.h \ util/virbitmap.c util/virbitmap.h \ + util/virbuffer.c util/virbuffer.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index a8ee2cf..3b8fef1 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -26,7 +26,7 @@ #include <strings.h> #include "capabilities.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "uuid.h" diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h index 641f279..4b6c2e5 100644 --- a/src/conf/capabilities.h +++ b/src/conf/capabilities.h @@ -25,7 +25,7 @@ # define __VIR_CAPABILITIES_H # include "internal.h" -# include "buf.h" +# include "virbuffer.h" # include "cpu_conf.h" # include "virmacaddr.h" diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 8cb54a3..190b088 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -26,7 +26,7 @@ #include "virterror_internal.h" #include "memory.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #include "cpu_conf.h" #include "domain_conf.h" diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 38fc675..357057d 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -25,7 +25,7 @@ # define __VIR_CPU_CONF_H__ # include "util.h" -# include "buf.h" +# include "virbuffer.h" # include "xml.h" # include "virbitmap.h" diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 7b97f45..daf57bc 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -27,7 +27,7 @@ #include "xml.h" #include "uuid.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #include "device_conf.h" #define VIR_FROM_THIS VIR_FROM_DEVICE diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 5318738..09d6be9 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -30,7 +30,7 @@ # include "internal.h" # include "util.h" # include "threads.h" -# include "buf.h" +# include "virbuffer.h" enum virDeviceAddressPciMulti { VIR_DEVICE_ADDRESS_PCI_MULTI_DEFAULT = 0, diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c90c6b9..d1fadc3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -39,7 +39,7 @@ #include "xml.h" #include "uuid.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #include "logging.h" #include "nwfilter_conf.h" #include "storage_file.h" diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index fc3602a..738ef33 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -31,7 +31,7 @@ #include "xml.h" #include "uuid.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_INTERFACE diff --git a/src/conf/netdev_bandwidth_conf.h b/src/conf/netdev_bandwidth_conf.h index 0080165..216a540 100644 --- a/src/conf/netdev_bandwidth_conf.h +++ b/src/conf/netdev_bandwidth_conf.h @@ -25,7 +25,7 @@ # include "internal.h" # include "virnetdevbandwidth.h" -# include "buf.h" +# include "virbuffer.h" # include "xml.h" virNetDevBandwidthPtr virNetDevBandwidthParse(xmlNodePtr node, diff --git a/src/conf/netdev_vlan_conf.h b/src/conf/netdev_vlan_conf.h index 81b0d84..19b50cc 100644 --- a/src/conf/netdev_vlan_conf.h +++ b/src/conf/netdev_vlan_conf.h @@ -24,7 +24,7 @@ # include "internal.h" # include "virnetdevvlan.h" -# include "buf.h" +# include "virbuffer.h" # include "xml.h" int virNetDevVlanParse(xmlNodePtr node, xmlXPathContextPtr ctxt, virNetDevVlanPtr def); diff --git a/src/conf/netdev_vport_profile_conf.h b/src/conf/netdev_vport_profile_conf.h index d6d58ef..15ecbd6 100644 --- a/src/conf/netdev_vport_profile_conf.h +++ b/src/conf/netdev_vport_profile_conf.h @@ -25,7 +25,7 @@ # include "internal.h" # include "virnetdevvportprofile.h" -# include "buf.h" +# include "virbuffer.h" # include "xml.h" typedef enum { diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index ff7366d..42cb87e 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -41,7 +41,7 @@ #include "xml.h" #include "uuid.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #include "c-ctype.h" #include "virfile.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 41fa8e4..50fcf0b 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -34,7 +34,7 @@ #include "memory.h" #include "xml.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #include "uuid.h" #include "pci.h" #include "virrandom.h" diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h index 805fbe7..d597064 100644 --- a/src/conf/nwfilter_conf.h +++ b/src/conf/nwfilter_conf.h @@ -31,7 +31,7 @@ # include "util.h" # include "virhash.h" # include "xml.h" -# include "buf.h" +# include "virbuffer.h" # include "virsocketaddr.h" # include "virmacaddr.h" diff --git a/src/conf/nwfilter_params.h b/src/conf/nwfilter_params.h index 6c3ce54..ac57796 100644 --- a/src/conf/nwfilter_params.h +++ b/src/conf/nwfilter_params.h @@ -24,7 +24,7 @@ # define NWFILTER_PARAMS_H # include "virhash.h" -# include "buf.h" +# include "virbuffer.h" # include "virmacaddr.h" enum virNWFilterVarValueType { diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index a6b4934..ec67f57 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -23,7 +23,7 @@ #include <config.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "datatypes.h" #include "logging.h" #include "memory.h" diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 95b7943..38a3e2a 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -30,7 +30,7 @@ #include "internal.h" #include "virbitmap.h" -#include "buf.h" +#include "virbuffer.h" #include "count-one-bits.h" #include "datatypes.h" #include "domain_conf.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index ad0f0c1..b81c08c 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -40,7 +40,7 @@ #include "xml.h" #include "uuid.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "memory.h" #include "virfile.h" diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index a8b1397..0c2bded 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -27,7 +27,7 @@ #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "storage_conf.h" #include "storage_encryption_conf.h" diff --git a/src/conf/storage_encryption_conf.h b/src/conf/storage_encryption_conf.h index e063478..40a8497 100644 --- a/src/conf/storage_encryption_conf.h +++ b/src/conf/storage_encryption_conf.h @@ -24,7 +24,7 @@ # define __VIR_STORAGE_ENCRYPTION_H__ # include "internal.h" -# include "buf.h" +# include "virbuffer.h" # include "util.h" # include <libxml/tree.h> diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index e420ffb..363d6c1 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -32,7 +32,7 @@ #include "cpu.h" #include "cpu_map.h" -#include "buf.h" +#include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_CPU diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index ca8cd92..563cd67 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -31,7 +31,7 @@ #include "cpu.h" #include "cpu_map.h" #include "cpu_x86.h" -#include "buf.h" +#include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_CPU diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 564b35c..d645bfb 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -26,7 +26,7 @@ #include <libxml/parser.h> #include <libxml/xpathInternals.h> -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "logging.h" #include "util.h" diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c index 0f9d612..a3c3c8b 100644 --- a/src/esx/esx_vi_methods.c +++ b/src/esx/esx_vi_methods.c @@ -23,7 +23,7 @@ #include <config.h> -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "logging.h" #include "uuid.h" diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index 0146728..1654e1b 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -27,7 +27,7 @@ #include <libxml/parser.h> #include <libxml/xpathInternals.h> -#include "buf.h" +#include "virbuffer.h" #include "datatypes.h" #include "memory.h" #include "logging.h" diff --git a/src/esx/esx_vi_types.h b/src/esx/esx_vi_types.h index a250bf8..92dc16f 100644 --- a/src/esx/esx_vi_types.h +++ b/src/esx/esx_vi_types.h @@ -23,7 +23,7 @@ #ifndef __ESX_VI_TYPES_H__ # define __ESX_VI_TYPES_H__ -# include "buf.h" +# include "virbuffer.h" typedef enum _esxVI_Type esxVI_Type; typedef struct _esxVI_Object esxVI_Object; diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 4023588..0a6b107 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -31,7 +31,7 @@ #include "memory.h" #include "util.h" #include "uuid.h" -#include "buf.h" +#include "virbuffer.h" #include "hyperv_private.h" #include "hyperv_wmi.h" diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index d9e8578..85a2bbc 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -25,7 +25,7 @@ #ifndef __HYPERV_WMI_H__ # define __HYPERV_WMI_H__ -# include "buf.h" +# include "virbuffer.h" # include "hyperv_private.h" # include "hyperv_wmi_classes.h" # include "openwsman.h" diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c index e0c51aa..4e7df55 100644 --- a/src/lxc/lxc_fuse.c +++ b/src/lxc/lxc_fuse.c @@ -34,7 +34,7 @@ #include "virterror_internal.h" #include "logging.h" #include "virfile.h" -#include "buf.h" +#include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index c62e729..c65f0bb 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -50,7 +50,7 @@ #include "network_conf.h" #include "device_conf.h" #include "driver.h" -#include "buf.h" +#include "virbuffer.h" #include "virpidfile.h" #include "util.h" #include "command.h" diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index c9ca00c..b3499fb 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -36,7 +36,7 @@ #include "memory.h" #include "uuid.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #include "pci.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index cdf0efc..5cfc036 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -30,7 +30,7 @@ #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "logging.h" #include "virterror_internal.h" diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c index 85e0e7e..361bdce 100644 --- a/src/nwfilter/nwfilter_learnipaddr.c +++ b/src/nwfilter/nwfilter_learnipaddr.c @@ -41,7 +41,7 @@ #include "internal.h" #include "intprops.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "logging.h" #include "datatypes.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 2bd9caf..3f89db3 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -47,7 +47,7 @@ #include "openvz_conf.h" #include "openvz_util.h" #include "uuid.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "nodeinfo.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index c5f5ca0..1b213c4 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -49,7 +49,7 @@ #include "datatypes.h" #include "openvz_driver.h" #include "openvz_util.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "openvz_conf.h" #include "nodeinfo.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 63017f4..e54f0f3 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -47,7 +47,7 @@ #include "virauth.h" #include "util.h" #include "datatypes.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "logging.h" #include "driver.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index a1b1d04..4a8b857 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -41,7 +41,7 @@ #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" #include "uuid.h" -#include "buf.h" +#include "virbuffer.h" #include "conf.h" #include "util.h" #include "memory.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e87397f..0ebbf7d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -62,7 +62,7 @@ #include "virterror_internal.h" #include "logging.h" #include "datatypes.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "nodeinfo.h" #include "stats_linux.h" diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index fa10600..a12adb6 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -39,7 +39,7 @@ #include "driver.h" #include "datatypes.h" #include "virterror_internal.h" -#include "buf.h" +#include "virbuffer.h" #ifdef WITH_DTRACE_PROBES # include "libvirt_qemu_probes.h" diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 5cc7e32..f32e88e 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -34,7 +34,7 @@ #include "datatypes.h" #include "domain_event.h" #include "driver.h" -#include "buf.h" +#include "virbuffer.h" #include "remote_driver.h" #include "remote_protocol.h" #include "qemu_protocol.h" diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index 286cc4d..d890569 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -26,7 +26,7 @@ #include "virnetsshsession.h" #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "logging.h" #include "configmake.h" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 888c416..78ebae3 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -40,7 +40,7 @@ #include <locale.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "memory.h" #include "command.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 6ca59e2..8e57370 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -35,7 +35,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "test_driver.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "uuid.h" #include "capabilities.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 6ef6de3..11c915e 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -37,7 +37,7 @@ #include "uml_conf.h" #include "uuid.h" -#include "buf.h" +#include "virbuffer.h" #include "conf.h" #include "util.h" #include "memory.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 887dca6..8dece66 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -46,7 +46,7 @@ #include "uml_driver.h" #include "uml_conf.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "nodeinfo.h" #include "stats_linux.h" diff --git a/src/util/buf.c b/src/util/buf.c deleted file mode 100644 index 030dc97..0000000 --- a/src/util/buf.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * buf.c: buffers for libvirt - * - * Copyright (C) 2005-2008, 2010-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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; /* errno value, or -1 for usage error */ - int indent; - char *content; -}; - -/** - * virBufferFail - * @buf: the buffer - * @error: which error occurred (errno value, or -1 for usage) - * - * Mark the buffer as failed, free the content and set the error flag. - */ -static void -virBufferSetError(virBufferPtr buf, int error) -{ - VIR_FREE(buf->content); - buf->size = 0; - buf->use = 0; - buf->indent = 0; - buf->error = error; -} - -/** - * virBufferAdjustIndent: - * @buf: the buffer - * @indent: adjustment to make - * - * Alter the auto-indent value by adding indent (positive to increase, - * negative to decrease). Automatic indentation is performed by all - * additive functions when the existing buffer is empty or ends with a - * newline (however, note that no indentation is added after newlines - * embedded in an appended string). If @indent would cause overflow, - * the buffer error indicator is set. - */ -void -virBufferAdjustIndent(virBufferPtr buf, int indent) -{ - if (!buf || buf->error) - return; - if (indent > 0 ? INT_MAX - indent < buf->indent - : buf->indent < -indent) { - virBufferSetError(buf, -1); - return; - } - buf->indent += indent; -} - -/** - * virBufferGetIndent: - * @buf: the buffer - * @dynamic: if false, return set value; if true, return 0 unless next - * append would be affected by auto-indent - * - * Return the current auto-indent value, or -1 if there has been an error. - */ -int -virBufferGetIndent(const virBufferPtr buf, bool dynamic) -{ - if (!buf || buf->error) - return -1; - if (dynamic && buf->use && buf->content[buf->use - 1] != '\n') - return 0; - return buf->indent; -} - -/** - * 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) { - virBufferSetError(buf, errno); - return -1; - } - buf->size = size; - return 0; -} - -/** - * virBufferAdd: - * @buf: the buffer to append to - * @str: the string - * @len: the number of bytes to add, or -1 - * - * Add a string range to an XML buffer. If @len == -1, the length of - * str is recomputed to the full string. Auto indentation may be applied. - * - */ -void -virBufferAdd(virBufferPtr buf, const char *str, int len) -{ - unsigned int needSize; - int indent; - - if (!str || !buf || (len == 0 && buf->indent == 0)) - return; - - if (buf->error) - return; - - indent = virBufferGetIndent(buf, true); - - if (len < 0) - len = strlen(str); - - needSize = buf->use + indent + len + 2; - if (needSize > buf->size && - virBufferGrow(buf, needSize - buf->use) < 0) - return; - - memset(&buf->content[buf->use], ' ', indent); - memcpy(&buf->content[buf->use + indent], str, len); - buf->use += indent + len; - buf->content[buf->use] = '\0'; -} - -/** - * virBufferAddChar: - * @buf: the buffer to append to - * @c: the character to add - * - * Add a single character 'c' to a buffer. Auto indentation may be applied. - * - */ -void -virBufferAddChar(virBufferPtr buf, char c) -{ - virBufferAdd(buf, &c, 1); -} - -/** - * virBufferCurrentContent: - * @buf: Buffer - * - * Get the current content from the buffer. The content is only valid - * until the next operation on @buf, and an empty string is returned if - * no content is present yet. - * - * Returns the buffer content or NULL in case of error. - */ -const char * -virBufferCurrentContent(virBufferPtr buf) -{ - if (!buf || buf->error) - return NULL; - return buf->use ? buf->content : ""; -} - -/** - * 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. This - * interface intentionally returns NULL instead of an empty string if - * there is no content. - * - * Returns the buffer content or NULL in case of error. - */ -char * -virBufferContentAndReset(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; -} - -/** - * virBufferFreeAndReset: - * @buf: the buffer to free and reset - * - * Frees the buffer content and resets the buffer structure. - */ -void virBufferFreeAndReset(virBufferPtr buf) -{ - char *str = virBufferContentAndReset(buf); - - VIR_FREE(str); -} - -/** - * virBufferError: - * @buf: the buffer - * - * Check to see if the buffer is in an error state due - * to failed memory allocation or usage error - * - * Return positive errno value or -1 on usage 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; -} - -/** - * virBufferAsprintf: - * @buf: the buffer to append to - * @format: the format - * @...: the variable list of arguments - * - * Do a formatted print to an XML buffer. Auto indentation may be applied. - */ -void -virBufferAsprintf(virBufferPtr buf, const char *format, ...) -{ - va_list argptr; - va_start(argptr, format); - virBufferVasprintf(buf, format, argptr); - va_end(argptr); -} - -/** - * virBufferVasprintf: - * @buf: the buffer to append to - * @format: the format - * @argptr: the variable list of arguments - * - * Do a formatted print to an XML buffer. Auto indentation may be applied. - */ -void -virBufferVasprintf(virBufferPtr buf, const char *format, va_list argptr) -{ - int size, count, grow_size; - va_list copy; - - if ((format == NULL) || (buf == NULL)) - return; - - if (buf->error) - return; - - virBufferAddLit(buf, ""); /* auto-indent */ - - if (buf->size == 0 && - virBufferGrow(buf, 100) < 0) - return; - - va_copy(copy, argptr); - - size = buf->size - buf->use; - if ((count = vsnprintf(&buf->content[buf->use], - size, format, copy)) < 0) { - virBufferSetError(buf, errno); - va_end(copy); - return; - } - va_end(copy); - - /* Grow buffer if necessary and retry */ - if (count >= size) { - buf->content[buf->use] = 0; - - grow_size = (count + 1 > 1000) ? count + 1 : 1000; - if (virBufferGrow(buf, grow_size) < 0) { - return; - } - - size = buf->size - buf->use; - if ((count = vsnprintf(&buf->content[buf->use], - size, format, argptr)) < 0) { - virBufferSetError(buf, errno); - return; - } - } - buf->use += count; -} - -/** - * virBufferEscapeString: - * @buf: the buffer to append to - * @format: a printf like format string but with only one %s parameter - * @str: the string argument which needs to be escaped - * - * Do a formatted print with a single string to an XML buffer. The - * string is escaped for use in XML. If @str is NULL, nothing is - * added (not even the rest of @format). Auto indentation may be - * applied. - */ -void -virBufferEscapeString(virBufferPtr buf, const char *format, const char *str) -{ - int len; - char *escaped, *out; - const char *cur; - - if ((format == NULL) || (buf == NULL) || (str == NULL)) - return; - - if (buf->error) - return; - - len = strlen(str); - if (strcspn(str, "<>&'\"") == len) { - virBufferAsprintf(buf, format, str); - return; - } - - if (xalloc_oversized(6, len) || - VIR_ALLOC_N(escaped, 6 * len + 1) < 0) { - virBufferSetError(buf, errno); - 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; - - virBufferAsprintf(buf, format, escaped); - VIR_FREE(escaped); -} - -/** - * virBufferEscapeSexpr: - * @buf: the buffer to append to - * @format: a printf like format string but with only one %s parameter - * @str: the string argument which needs to be escaped - * - * Do a formatted print with a single string to an sexpr buffer. The - * string is escaped to avoid generating a sexpr that xen will choke - * on. This doesn't fully escape the sexpr, just enough for our code - * to work. Auto indentation may be applied. - */ -void -virBufferEscapeSexpr(virBufferPtr buf, - const char *format, - const char *str) -{ - virBufferEscape(buf, '\\', "\\'", format, str); -} - -/** - * virBufferEscape: - * @buf: the buffer to append to - * @escape: the escape character to inject - * @toescape: NUL-terminated list of characters to escape - * @format: a printf like format string but with only one %s parameter - * @str: the string argument which needs to be escaped - * - * Do a formatted print with a single string to a buffer. Any characters - * in the provided list are escaped with the given escape. Auto indentation - * may be applied. - */ -void -virBufferEscape(virBufferPtr buf, char escape, const char *toescape, - const char *format, const char *str) -{ - int len; - char *escaped, *out; - const char *cur; - - if ((format == NULL) || (buf == NULL) || (str == NULL)) - return; - - if (buf->error) - return; - - len = strlen(str); - if (strcspn(str, toescape) == len) { - virBufferAsprintf(buf, format, str); - return; - } - - if (xalloc_oversized(2, len) || - VIR_ALLOC_N(escaped, 2 * len + 1) < 0) { - virBufferSetError(buf, errno); - return; - } - - cur = str; - out = escaped; - while (*cur != 0) { - /* strchr work-around for gcc 4.3 & 4.4 bug with -Wlogical-op - * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36513 - */ - char needle[2] = { *cur, 0 }; - if (strstr(toescape, needle)) - *out++ = escape; - *out++ = *cur; - cur++; - } - *out = 0; - - virBufferAsprintf(buf, format, escaped); - 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). Auto indentation may be applied. - */ -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; - - virBufferAddLit(buf, ""); /* auto-indent */ - - 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'; -} - -/** - * virBufferEscapeShell: - * @buf: the buffer to append to - * @str: an unquoted string - * - * Quotes a string so that the shell (/bin/sh) will interpret the - * quoted string to mean str. Auto indentation may be applied. - */ -void -virBufferEscapeShell(virBufferPtr buf, const char *str) -{ - int len; - char *escaped, *out; - const char *cur; - - if ((buf == NULL) || (str == NULL)) - return; - - if (buf->error) - return; - - /* Only quote if str includes shell metacharacters. */ - if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) { - virBufferAdd(buf, str, -1); - return; - } - - if (*str) { - len = strlen(str); - if (xalloc_oversized(4, len) || - VIR_ALLOC_N(escaped, 4 * len + 3) < 0) { - virBufferSetError(buf, errno); - return; - } - } else { - virBufferAddLit(buf, "''"); - return; - } - - cur = str; - out = escaped; - - *out++ = '\''; - while (*cur != 0) { - if (*cur == '\'') { - *out++ = '\''; - /* Replace literal ' with a close ', a \', and a open ' */ - *out++ = '\\'; - *out++ = '\''; - } - *out++ = *cur++; - } - *out++ = '\''; - *out = 0; - - virBufferAdd(buf, escaped, -1); - VIR_FREE(escaped); -} - -/** - * virBufferStrcat: - * @buf: the buffer to append to - * @...: the variable list of strings, the last argument must be NULL - * - * Concatenate strings to an XML buffer. Auto indentation may be applied - * after each string argument. - */ -void -virBufferStrcat(virBufferPtr buf, ...) -{ - va_list ap; - char *str; - - if (buf->error) - return; - - va_start(ap, buf); - while ((str = va_arg(ap, char *)) != NULL) - virBufferAdd(buf, str, -1); - va_end(ap); -} - -/** - * virBufferTrim: - * @buf: the buffer to trim - * @str: the optional string, to force an exact trim - * @len: the number of bytes to trim, or -1 to use @str - * - * Trim the tail of a buffer. If @str is provided, the trim only occurs - * if the current tail of the buffer matches @str; a non-negative @len - * further limits how much of the tail is trimmed. If @str is NULL, then - * @len must be non-negative. - * - * Returns -1 if @buf has previously encountered an error or if @len is - * invalid, 0 if there was nothing to trim (@buf was too short or @str - * didn't match), and 1 if the trim was successful. - */ -int -virBufferTrim(virBufferPtr buf, const char *str, int len) -{ - size_t len2 = 0; - - if (!buf || buf->error || (!str && len < 0)) - return -1; - - if (len > 0 && len > buf->use) - return 0; - if (str) { - len2 = strlen(str); - if (len2 > buf->use || - memcmp(&buf->content[buf->use - len2], str, len2) != 0) - return 0; - } - buf->use -= len < 0 ? len2 : len; - buf->content[buf->use] = '\0'; - return 1; -} diff --git a/src/util/buf.h b/src/util/buf.h deleted file mode 100644 index c3a498d..0000000 --- a/src/util/buf.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * buf.h: buffers for libvirt - * - * Copyright (C) 2005-2008, 2011, 2012 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, see - * <http://www.gnu.org/licenses/>. - * - * Daniel Veillard <veillard@redhat.com> - */ - -#ifndef __VIR_BUFFER_H__ -# define __VIR_BUFFER_H__ - -# include "internal.h" - -# include <stdarg.h> - -/** - * virBuffer: - * - * A buffer structure. - */ -typedef struct _virBuffer virBuffer; -typedef virBuffer *virBufferPtr; - -# ifndef __VIR_BUFFER_C__ -# define VIR_BUFFER_INITIALIZER { 0, 0, 0, 0, NULL } - -/* This struct must be kept in sync with the real struct - in the buf.c impl file */ -struct _virBuffer { - unsigned int a; - unsigned int b; - unsigned int c; - int d; - char *e; -}; -# endif - -const char *virBufferCurrentContent(virBufferPtr buf); -char *virBufferContentAndReset(virBufferPtr buf); -void virBufferFreeAndReset(virBufferPtr buf); -int virBufferError(const virBufferPtr buf); -unsigned int virBufferUse(const virBufferPtr buf); -void virBufferAdd(virBufferPtr buf, const char *str, int len); -void virBufferAddChar(virBufferPtr buf, char c); -void virBufferAsprintf(virBufferPtr buf, const char *format, ...) - ATTRIBUTE_FMT_PRINTF(2, 3); -void virBufferVasprintf(virBufferPtr buf, const char *format, va_list ap) - ATTRIBUTE_FMT_PRINTF(2, 0); -void virBufferStrcat(virBufferPtr buf, ...) - ATTRIBUTE_SENTINEL; -void virBufferEscape(virBufferPtr buf, char escape, const char *toescape, - const char *format, const char *str); -void virBufferEscapeString(virBufferPtr buf, const char *format, - const char *str); -void virBufferEscapeSexpr(virBufferPtr buf, const char *format, - const char *str); -void virBufferEscapeShell(virBufferPtr buf, const char *str); -void virBufferURIEncodeString(virBufferPtr buf, const char *str); - -# define virBufferAddLit(buf_, literal_string_) \ - virBufferAdd(buf_, "" literal_string_ "", sizeof(literal_string_) - 1) - -void virBufferAdjustIndent(virBufferPtr buf, int indent); -int virBufferGetIndent(const virBufferPtr buf, bool dynamic); - -int virBufferTrim(virBufferPtr buf, const char *trim, int len); - -#endif /* __VIR_BUFFER_H__ */ diff --git a/src/util/command.c b/src/util/command.c index ebdd636..fbd9ff8 100644 --- a/src/util/command.c +++ b/src/util/command.c @@ -41,7 +41,7 @@ #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" -#include "buf.h" +#include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/command.h b/src/util/command.h index 177a0eb..6c8ab49 100644 --- a/src/util/command.h +++ b/src/util/command.h @@ -24,7 +24,7 @@ # include "internal.h" # include "util.h" -# include "buf.h" +# include "virbuffer.h" typedef struct _virCommand virCommand; typedef virCommand *virCommandPtr; diff --git a/src/util/conf.c b/src/util/conf.c index ba80097..3b97545 100644 --- a/src/util/conf.c +++ b/src/util/conf.c @@ -31,7 +31,7 @@ #include <fcntl.h> #include "virterror_internal.h" -#include "buf.h" +#include "virbuffer.h" #include "conf.h" #include "util.h" #include "c-ctype.h" diff --git a/src/util/logging.c b/src/util/logging.c index e8fed55..0df3549 100644 --- a/src/util/logging.c +++ b/src/util/logging.c @@ -44,7 +44,7 @@ #include "logging.h" #include "memory.h" #include "util.h" -#include "buf.h" +#include "virbuffer.h" #include "threads.h" #include "virfile.h" #include "virtime.h" diff --git a/src/util/logging.h b/src/util/logging.h index 52feecc..028b791 100644 --- a/src/util/logging.h +++ b/src/util/logging.h @@ -23,7 +23,7 @@ # define __VIRTLOG_H_ # include "internal.h" -# include "buf.h" +# include "virbuffer.h" /* * To be made public diff --git a/src/util/sexpr.h b/src/util/sexpr.h index b4b41ed..13ec481 100644 --- a/src/util/sexpr.h +++ b/src/util/sexpr.h @@ -13,7 +13,7 @@ # define _LIBVIR_SEXPR_H_ # include "internal.h" -# include "buf.h" +# include "virbuffer.h" enum sexpr_type { SEXPR_NIL, diff --git a/src/util/sysinfo.h b/src/util/sysinfo.h index 40a100a..0b1f000 100644 --- a/src/util/sysinfo.h +++ b/src/util/sysinfo.h @@ -26,7 +26,7 @@ # include "internal.h" # include "util.h" -# include "buf.h" +# include "virbuffer.h" enum virSysinfoType { VIR_SYSINFO_SMBIOS, diff --git a/src/util/util.c b/src/util/util.c index 05e7ca7..422ee75 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -77,7 +77,7 @@ #include "dirname.h" #include "virterror_internal.h" #include "logging.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "storage_file.h" #include "memory.h" diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index 0f13389..41b74d4 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -32,7 +32,7 @@ #include "virbitmap.h" #include "memory.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "c-ctype.h" #include "count-one-bits.h" diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c new file mode 100644 index 0000000..e4409c6 --- /dev/null +++ b/src/util/virbuffer.c @@ -0,0 +1,682 @@ +/* + * buf.c: buffers for libvirt + * + * Copyright (C) 2005-2008, 2010-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * 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 "virbuffer.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; /* errno value, or -1 for usage error */ + int indent; + char *content; +}; + +/** + * virBufferFail + * @buf: the buffer + * @error: which error occurred (errno value, or -1 for usage) + * + * Mark the buffer as failed, free the content and set the error flag. + */ +static void +virBufferSetError(virBufferPtr buf, int error) +{ + VIR_FREE(buf->content); + buf->size = 0; + buf->use = 0; + buf->indent = 0; + buf->error = error; +} + +/** + * virBufferAdjustIndent: + * @buf: the buffer + * @indent: adjustment to make + * + * Alter the auto-indent value by adding indent (positive to increase, + * negative to decrease). Automatic indentation is performed by all + * additive functions when the existing buffer is empty or ends with a + * newline (however, note that no indentation is added after newlines + * embedded in an appended string). If @indent would cause overflow, + * the buffer error indicator is set. + */ +void +virBufferAdjustIndent(virBufferPtr buf, int indent) +{ + if (!buf || buf->error) + return; + if (indent > 0 ? INT_MAX - indent < buf->indent + : buf->indent < -indent) { + virBufferSetError(buf, -1); + return; + } + buf->indent += indent; +} + +/** + * virBufferGetIndent: + * @buf: the buffer + * @dynamic: if false, return set value; if true, return 0 unless next + * append would be affected by auto-indent + * + * Return the current auto-indent value, or -1 if there has been an error. + */ +int +virBufferGetIndent(const virBufferPtr buf, bool dynamic) +{ + if (!buf || buf->error) + return -1; + if (dynamic && buf->use && buf->content[buf->use - 1] != '\n') + return 0; + return buf->indent; +} + +/** + * 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) { + virBufferSetError(buf, errno); + return -1; + } + buf->size = size; + return 0; +} + +/** + * virBufferAdd: + * @buf: the buffer to append to + * @str: the string + * @len: the number of bytes to add, or -1 + * + * Add a string range to an XML buffer. If @len == -1, the length of + * str is recomputed to the full string. Auto indentation may be applied. + * + */ +void +virBufferAdd(virBufferPtr buf, const char *str, int len) +{ + unsigned int needSize; + int indent; + + if (!str || !buf || (len == 0 && buf->indent == 0)) + return; + + if (buf->error) + return; + + indent = virBufferGetIndent(buf, true); + + if (len < 0) + len = strlen(str); + + needSize = buf->use + indent + len + 2; + if (needSize > buf->size && + virBufferGrow(buf, needSize - buf->use) < 0) + return; + + memset(&buf->content[buf->use], ' ', indent); + memcpy(&buf->content[buf->use + indent], str, len); + buf->use += indent + len; + buf->content[buf->use] = '\0'; +} + +/** + * virBufferAddChar: + * @buf: the buffer to append to + * @c: the character to add + * + * Add a single character 'c' to a buffer. Auto indentation may be applied. + * + */ +void +virBufferAddChar(virBufferPtr buf, char c) +{ + virBufferAdd(buf, &c, 1); +} + +/** + * virBufferCurrentContent: + * @buf: Buffer + * + * Get the current content from the buffer. The content is only valid + * until the next operation on @buf, and an empty string is returned if + * no content is present yet. + * + * Returns the buffer content or NULL in case of error. + */ +const char * +virBufferCurrentContent(virBufferPtr buf) +{ + if (!buf || buf->error) + return NULL; + return buf->use ? buf->content : ""; +} + +/** + * 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. This + * interface intentionally returns NULL instead of an empty string if + * there is no content. + * + * Returns the buffer content or NULL in case of error. + */ +char * +virBufferContentAndReset(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; +} + +/** + * virBufferFreeAndReset: + * @buf: the buffer to free and reset + * + * Frees the buffer content and resets the buffer structure. + */ +void virBufferFreeAndReset(virBufferPtr buf) +{ + char *str = virBufferContentAndReset(buf); + + VIR_FREE(str); +} + +/** + * virBufferError: + * @buf: the buffer + * + * Check to see if the buffer is in an error state due + * to failed memory allocation or usage error + * + * Return positive errno value or -1 on usage 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; +} + +/** + * virBufferAsprintf: + * @buf: the buffer to append to + * @format: the format + * @...: the variable list of arguments + * + * Do a formatted print to an XML buffer. Auto indentation may be applied. + */ +void +virBufferAsprintf(virBufferPtr buf, const char *format, ...) +{ + va_list argptr; + va_start(argptr, format); + virBufferVasprintf(buf, format, argptr); + va_end(argptr); +} + +/** + * virBufferVasprintf: + * @buf: the buffer to append to + * @format: the format + * @argptr: the variable list of arguments + * + * Do a formatted print to an XML buffer. Auto indentation may be applied. + */ +void +virBufferVasprintf(virBufferPtr buf, const char *format, va_list argptr) +{ + int size, count, grow_size; + va_list copy; + + if ((format == NULL) || (buf == NULL)) + return; + + if (buf->error) + return; + + virBufferAddLit(buf, ""); /* auto-indent */ + + if (buf->size == 0 && + virBufferGrow(buf, 100) < 0) + return; + + va_copy(copy, argptr); + + size = buf->size - buf->use; + if ((count = vsnprintf(&buf->content[buf->use], + size, format, copy)) < 0) { + virBufferSetError(buf, errno); + va_end(copy); + return; + } + va_end(copy); + + /* Grow buffer if necessary and retry */ + if (count >= size) { + buf->content[buf->use] = 0; + + grow_size = (count + 1 > 1000) ? count + 1 : 1000; + if (virBufferGrow(buf, grow_size) < 0) { + return; + } + + size = buf->size - buf->use; + if ((count = vsnprintf(&buf->content[buf->use], + size, format, argptr)) < 0) { + virBufferSetError(buf, errno); + return; + } + } + buf->use += count; +} + +/** + * virBufferEscapeString: + * @buf: the buffer to append to + * @format: a printf like format string but with only one %s parameter + * @str: the string argument which needs to be escaped + * + * Do a formatted print with a single string to an XML buffer. The + * string is escaped for use in XML. If @str is NULL, nothing is + * added (not even the rest of @format). Auto indentation may be + * applied. + */ +void +virBufferEscapeString(virBufferPtr buf, const char *format, const char *str) +{ + int len; + char *escaped, *out; + const char *cur; + + if ((format == NULL) || (buf == NULL) || (str == NULL)) + return; + + if (buf->error) + return; + + len = strlen(str); + if (strcspn(str, "<>&'\"") == len) { + virBufferAsprintf(buf, format, str); + return; + } + + if (xalloc_oversized(6, len) || + VIR_ALLOC_N(escaped, 6 * len + 1) < 0) { + virBufferSetError(buf, errno); + 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; + + virBufferAsprintf(buf, format, escaped); + VIR_FREE(escaped); +} + +/** + * virBufferEscapeSexpr: + * @buf: the buffer to append to + * @format: a printf like format string but with only one %s parameter + * @str: the string argument which needs to be escaped + * + * Do a formatted print with a single string to an sexpr buffer. The + * string is escaped to avoid generating a sexpr that xen will choke + * on. This doesn't fully escape the sexpr, just enough for our code + * to work. Auto indentation may be applied. + */ +void +virBufferEscapeSexpr(virBufferPtr buf, + const char *format, + const char *str) +{ + virBufferEscape(buf, '\\', "\\'", format, str); +} + +/** + * virBufferEscape: + * @buf: the buffer to append to + * @escape: the escape character to inject + * @toescape: NUL-terminated list of characters to escape + * @format: a printf like format string but with only one %s parameter + * @str: the string argument which needs to be escaped + * + * Do a formatted print with a single string to a buffer. Any characters + * in the provided list are escaped with the given escape. Auto indentation + * may be applied. + */ +void +virBufferEscape(virBufferPtr buf, char escape, const char *toescape, + const char *format, const char *str) +{ + int len; + char *escaped, *out; + const char *cur; + + if ((format == NULL) || (buf == NULL) || (str == NULL)) + return; + + if (buf->error) + return; + + len = strlen(str); + if (strcspn(str, toescape) == len) { + virBufferAsprintf(buf, format, str); + return; + } + + if (xalloc_oversized(2, len) || + VIR_ALLOC_N(escaped, 2 * len + 1) < 0) { + virBufferSetError(buf, errno); + return; + } + + cur = str; + out = escaped; + while (*cur != 0) { + /* strchr work-around for gcc 4.3 & 4.4 bug with -Wlogical-op + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36513 + */ + char needle[2] = { *cur, 0 }; + if (strstr(toescape, needle)) + *out++ = escape; + *out++ = *cur; + cur++; + } + *out = 0; + + virBufferAsprintf(buf, format, escaped); + 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). Auto indentation may be applied. + */ +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; + + virBufferAddLit(buf, ""); /* auto-indent */ + + 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'; +} + +/** + * virBufferEscapeShell: + * @buf: the buffer to append to + * @str: an unquoted string + * + * Quotes a string so that the shell (/bin/sh) will interpret the + * quoted string to mean str. Auto indentation may be applied. + */ +void +virBufferEscapeShell(virBufferPtr buf, const char *str) +{ + int len; + char *escaped, *out; + const char *cur; + + if ((buf == NULL) || (str == NULL)) + return; + + if (buf->error) + return; + + /* Only quote if str includes shell metacharacters. */ + if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) { + virBufferAdd(buf, str, -1); + return; + } + + if (*str) { + len = strlen(str); + if (xalloc_oversized(4, len) || + VIR_ALLOC_N(escaped, 4 * len + 3) < 0) { + virBufferSetError(buf, errno); + return; + } + } else { + virBufferAddLit(buf, "''"); + return; + } + + cur = str; + out = escaped; + + *out++ = '\''; + while (*cur != 0) { + if (*cur == '\'') { + *out++ = '\''; + /* Replace literal ' with a close ', a \', and a open ' */ + *out++ = '\\'; + *out++ = '\''; + } + *out++ = *cur++; + } + *out++ = '\''; + *out = 0; + + virBufferAdd(buf, escaped, -1); + VIR_FREE(escaped); +} + +/** + * virBufferStrcat: + * @buf: the buffer to append to + * @...: the variable list of strings, the last argument must be NULL + * + * Concatenate strings to an XML buffer. Auto indentation may be applied + * after each string argument. + */ +void +virBufferStrcat(virBufferPtr buf, ...) +{ + va_list ap; + char *str; + + if (buf->error) + return; + + va_start(ap, buf); + while ((str = va_arg(ap, char *)) != NULL) + virBufferAdd(buf, str, -1); + va_end(ap); +} + +/** + * virBufferTrim: + * @buf: the buffer to trim + * @str: the optional string, to force an exact trim + * @len: the number of bytes to trim, or -1 to use @str + * + * Trim the tail of a buffer. If @str is provided, the trim only occurs + * if the current tail of the buffer matches @str; a non-negative @len + * further limits how much of the tail is trimmed. If @str is NULL, then + * @len must be non-negative. + * + * Returns -1 if @buf has previously encountered an error or if @len is + * invalid, 0 if there was nothing to trim (@buf was too short or @str + * didn't match), and 1 if the trim was successful. + */ +int +virBufferTrim(virBufferPtr buf, const char *str, int len) +{ + size_t len2 = 0; + + if (!buf || buf->error || (!str && len < 0)) + return -1; + + if (len > 0 && len > buf->use) + return 0; + if (str) { + len2 = strlen(str); + if (len2 > buf->use || + memcmp(&buf->content[buf->use - len2], str, len2) != 0) + return 0; + } + buf->use -= len < 0 ? len2 : len; + buf->content[buf->use] = '\0'; + return 1; +} diff --git a/src/util/virbuffer.h b/src/util/virbuffer.h new file mode 100644 index 0000000..c3a498d --- /dev/null +++ b/src/util/virbuffer.h @@ -0,0 +1,82 @@ +/* + * buf.h: buffers for libvirt + * + * Copyright (C) 2005-2008, 2011, 2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + */ + +#ifndef __VIR_BUFFER_H__ +# define __VIR_BUFFER_H__ + +# include "internal.h" + +# include <stdarg.h> + +/** + * virBuffer: + * + * A buffer structure. + */ +typedef struct _virBuffer virBuffer; +typedef virBuffer *virBufferPtr; + +# ifndef __VIR_BUFFER_C__ +# define VIR_BUFFER_INITIALIZER { 0, 0, 0, 0, NULL } + +/* This struct must be kept in sync with the real struct + in the buf.c impl file */ +struct _virBuffer { + unsigned int a; + unsigned int b; + unsigned int c; + int d; + char *e; +}; +# endif + +const char *virBufferCurrentContent(virBufferPtr buf); +char *virBufferContentAndReset(virBufferPtr buf); +void virBufferFreeAndReset(virBufferPtr buf); +int virBufferError(const virBufferPtr buf); +unsigned int virBufferUse(const virBufferPtr buf); +void virBufferAdd(virBufferPtr buf, const char *str, int len); +void virBufferAddChar(virBufferPtr buf, char c); +void virBufferAsprintf(virBufferPtr buf, const char *format, ...) + ATTRIBUTE_FMT_PRINTF(2, 3); +void virBufferVasprintf(virBufferPtr buf, const char *format, va_list ap) + ATTRIBUTE_FMT_PRINTF(2, 0); +void virBufferStrcat(virBufferPtr buf, ...) + ATTRIBUTE_SENTINEL; +void virBufferEscape(virBufferPtr buf, char escape, const char *toescape, + const char *format, const char *str); +void virBufferEscapeString(virBufferPtr buf, const char *format, + const char *str); +void virBufferEscapeSexpr(virBufferPtr buf, const char *format, + const char *str); +void virBufferEscapeShell(virBufferPtr buf, const char *str); +void virBufferURIEncodeString(virBufferPtr buf, const char *str); + +# define virBufferAddLit(buf_, literal_string_) \ + virBufferAdd(buf_, "" literal_string_ "", sizeof(literal_string_) - 1) + +void virBufferAdjustIndent(virBufferPtr buf, int indent); +int virBufferGetIndent(const virBufferPtr buf, bool dynamic); + +int virBufferTrim(virBufferPtr buf, const char *trim, int len); + +#endif /* __VIR_BUFFER_H__ */ diff --git a/src/util/virstring.c b/src/util/virstring.c index 1917e9a..228c3fb 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -23,7 +23,7 @@ #include "virstring.h" #include "memory.h" -#include "buf.h" +#include "virbuffer.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/viruri.c b/src/util/viruri.c index 26dbf24..dd3b878 100644 --- a/src/util/viruri.c +++ b/src/util/viruri.c @@ -25,7 +25,7 @@ #include "memory.h" #include "util.h" #include "virterror_internal.h" -#include "buf.h" +#include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_URI diff --git a/src/util/xml.c b/src/util/xml.c index 84db865..5b08b1f 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "xml.h" -#include "buf.h" +#include "virbuffer.h" #include "util.h" #include "memory.h" #include "virfile.h" diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 237a6ab..1aa2b73 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -74,7 +74,7 @@ #include "stats_linux.h" #include "block_stats.h" #include "xend_internal.h" -#include "buf.h" +#include "virbuffer.h" #include "capabilities.h" #include "memory.h" #include "threads.h" diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 922c571..9407e95 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -37,7 +37,7 @@ #include "util.h" #include "sexpr.h" #include "xen_sxpr.h" -#include "buf.h" +#include "virbuffer.h" #include "uuid.h" #include "xen_driver.h" #include "xen_hypervisor.h" diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h index 5942788..06c75e1 100644 --- a/src/xen/xend_internal.h +++ b/src/xen/xend_internal.h @@ -23,7 +23,7 @@ # include "capabilities.h" # include "domain_conf.h" # include "driver.h" -# include "buf.h" +# include "virbuffer.h" # include "viruri.h" int diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 9da2974..2cd4b95 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -43,7 +43,7 @@ #include "xen_sxpr.h" #include "xen_xm.h" #include "virhash.h" -#include "buf.h" +#include "virbuffer.h" #include "uuid.h" #include "util.h" #include "memory.h" diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 5a93aea..f00dcfd 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -34,7 +34,7 @@ #include "util.h" #include "uuid.h" #include "memory.h" -#include "buf.h" +#include "virbuffer.h" #include "viruri.h" #include "xenapi_driver.h" #include "xenapi_driver_private.h" diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 8c906f4..dbdb22d 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -32,7 +32,7 @@ #include "util.h" #include "uuid.h" #include "memory.h" -#include "buf.h" +#include "virbuffer.h" #include "logging.h" #include "viruri.h" #include "xenapi_driver_private.h" diff --git a/tests/cputest.c b/tests/cputest.c index 3cdc769..f6110c1 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -33,7 +33,7 @@ #include "internal.h" #include "xml.h" #include "memory.h" -#include "buf.h" +#include "virbuffer.h" #include "testutils.h" #include "cpu_conf.h" #include "cpu/cpu.h" diff --git a/tests/testutils.c b/tests/testutils.c index 3d2e491..e8b48e8 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -43,7 +43,7 @@ #include "util.h" #include "threads.h" #include "virterror_internal.h" -#include "buf.h" +#include "virbuffer.h" #include "logging.h" #include "command.h" #include "virrandom.h" diff --git a/tests/virbuftest.c b/tests/virbuftest.c index 35ba997..53b9bbe 100644 --- a/tests/virbuftest.c +++ b/tests/virbuftest.c @@ -7,7 +7,7 @@ #include "internal.h" #include "util.h" #include "testutils.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #define TEST_ERROR(...) \ diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 765f30c..76d9d51 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -38,7 +38,7 @@ #include "internal.h" #include "virbitmap.h" -#include "buf.h" +#include "virbuffer.h" #include "c-ctype.h" #include "conf/domain_conf.h" #include "console.h" diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 3d13e01..f687780 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -32,7 +32,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "virsh-domain.h" diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index 3a6285b..956fee8 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -32,7 +32,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-network.c b/tools/virsh-network.c index fd9d563..c5d494a 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -32,7 +32,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 8cf96be..52cd874 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -32,7 +32,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index 5e79191..3108d1b 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -32,7 +32,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 5fee2cd..4a78467 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -32,7 +32,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index 52879e1..ee79b97 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -33,7 +33,7 @@ #include "internal.h" #include "base64.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index 8ec6456..d6a381d 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -34,7 +34,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "virsh-domain.h" diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 21a2df0..1bad6b1 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -34,7 +34,7 @@ #include <libxml/xmlsave.h> #include "internal.h" -#include "buf.h" +#include "virbuffer.h" #include "memory.h" #include "util.h" #include "virfile.h" diff --git a/tools/virsh.c b/tools/virsh.c index 2f7d4a3..82c03e4 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -56,7 +56,7 @@ #include "internal.h" #include "virterror_internal.h" #include "base64.h" -#include "buf.h" +#include "virbuffer.h" #include "console.h" #include "util.h" #include "memory.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- cfg.mk | 4 +- daemon/remote.c | 2 +- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/fdstream.h | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_controller.c | 2 +- src/lxc/lxc_process.c | 2 +- src/network/bridge_driver.c | 2 +- src/network/bridge_driver.h | 2 +- src/nwfilter/nwfilter_ebiptables_driver.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/openvz/openvz_util.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_utils.c | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_capabilities.h | 2 +- src/qemu/qemu_command.h | 2 +- src/qemu/qemu_conf.h | 2 +- src/remote/remote_driver.c | 2 +- src/rpc/virnetsocket.h | 2 +- src/security/security_apparmor.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/storage/storage_backend.h | 2 +- src/storage/storage_backend_disk.c | 2 +- src/storage/storage_backend_fs.c | 2 +- src/storage/storage_backend_iscsi.c | 2 +- src/storage/storage_backend_logical.c | 2 +- src/storage/storage_backend_scsi.c | 2 +- src/storage/storage_backend_sheepdog.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_conf.h | 2 +- src/util/command.c | 2523 ----------------------------- src/util/command.h | 166 -- src/util/dnsmasq.c | 2 +- src/util/ebtables.c | 2 +- src/util/hooks.c | 2 +- src/util/iptables.c | 2 +- src/util/pci.c | 2 +- src/util/storage_file.c | 2 +- src/util/sysinfo.c | 2 +- src/util/util.c | 2 +- src/util/vircommand.c | 2523 +++++++++++++++++++++++++++++ src/util/vircommand.h | 166 ++ src/util/virfile.c | 2 +- src/util/virnetdev.c | 2 +- src/util/virnetdevbandwidth.c | 2 +- src/util/virnetdevopenvswitch.c | 2 +- src/util/virnetdevveth.c | 2 +- src/util/virnodesuspend.c | 2 +- src/vmware/vmware_conf.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/xen/xen_driver.c | 2 +- tests/commandtest.c | 2 +- tests/networkxml2conftest.c | 2 +- tests/reconnect.c | 2 +- tests/statstest.c | 2 +- tests/testutils.c | 2 +- tests/virnettlscontexttest.c | 2 +- tools/virsh.c | 2 +- 63 files changed, 2749 insertions(+), 2749 deletions(-) delete mode 100644 src/util/command.c delete mode 100644 src/util/command.h create mode 100644 src/util/vircommand.c create mode 100644 src/util/vircommand.h diff --git a/cfg.mk b/cfg.mk index 1fe007e..9fbf799 100644 --- a/cfg.mk +++ b/cfg.mk @@ -745,7 +745,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco # List all syntax-check exemptions: exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$ -_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon +_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon exclude_file_name_regexp--sc_avoid_write = \ ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$ @@ -778,7 +778,7 @@ exclude_file_name_regexp--sc_prohibit_close = \ exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ (^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$) -_src2=src/(util/command|libvirt|lxc/lxc_controller|locking/lock_daemon) +_src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon) exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$) diff --git a/daemon/remote.c b/daemon/remote.c index 41b8ea8..1746280 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -39,7 +39,7 @@ #include "stream.h" #include "uuid.h" #include "libvirt/libvirt-qemu.h" -#include "command.h" +#include "vircommand.h" #include "intprops.h" #include "virnetserverservice.h" #include "virnetserver.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index 19ed187..843db7c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/command.c src/util/conf.c src/util/dnsmasq.c src/util/event_poll.c @@ -157,6 +156,7 @@ src/util/viraudit.c src/util/virauth.c src/util/virauthconfig.c src/util/vircgroup.c +src/util/vircommand.c src/util/virdbus.c src/util/virfile.c src/util/virhash.c diff --git a/src/Makefile.am b/src/Makefile.am index fd21aa6..7e16d68 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/command.c util/command.h \ util/conf.c util/conf.h \ util/event.c util/event.h \ util/event_poll.c util/event_poll.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virauthconfig.c util/virauthconfig.h \ util/virbitmap.c util/virbitmap.h \ util/virbuffer.c util/virbuffer.h \ + util/vircommand.c util/vircommand.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/fdstream.h b/src/fdstream.h index 65457d8..d6f5a7a 100644 --- a/src/fdstream.h +++ b/src/fdstream.h @@ -24,7 +24,7 @@ # define __VIR_FDSTREAM_H_ # include "internal.h" -# include "command.h" +# include "vircommand.h" /* internal callback, the generic one is used up by daemon stream driver */ /* the close callback is called with fdstream private data locked */ diff --git a/src/libvirt.c b/src/libvirt.c index 4215971..e28ed05 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -56,7 +56,7 @@ #include "intprops.h" #include "conf.h" #include "rpc/virnettlscontext.h" -#include "command.h" +#include "vircommand.h" #include "virrandom.h" #include "viruri.h" #include "threads.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 302f81c..1423073 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -39,7 +39,7 @@ #include "virfile.h" #include "memory.h" #include "uuid.h" -#include "command.h" +#include "vircommand.h" #include "libxl.h" #include "libxl_driver.h" #include "libxl_conf.h" diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 3014564..33ebf1f 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -61,7 +61,7 @@ #include "virnetdevveth.h" #include "uuid.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #include "virnetdev.h" #include "virprocess.h" diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 5510b9a..c9cac5d 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -67,7 +67,7 @@ #include "util.h" #include "virfile.h" #include "virpidfile.h" -#include "command.h" +#include "vircommand.h" #include "processinfo.h" #include "nodeinfo.h" #include "virrandom.h" diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 3e7fcb8..7f66dc7 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -42,7 +42,7 @@ #include "domain_audit.h" #include "virterror_internal.h" #include "logging.h" -#include "command.h" +#include "vircommand.h" #include "hooks.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index c65f0bb..319ff8c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -53,7 +53,7 @@ #include "virbuffer.h" #include "virpidfile.h" #include "util.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "uuid.h" #include "iptables.h" diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index 43fefc0..fea27e0 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -30,7 +30,7 @@ # include "internal.h" # include "network_conf.h" # include "domain_conf.h" -# include "command.h" +# include "vircommand.h" # include "dnsmasq.h" int networkRegister(void); diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index 5cfc036..6966acf 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -40,7 +40,7 @@ #include "nwfilter_gentech_driver.h" #include "nwfilter_ebiptables_driver.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #include "configmake.h" #include "intprops.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 3f89db3..c9189ef 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -52,7 +52,7 @@ #include "util.h" #include "nodeinfo.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #define VIR_FROM_THIS VIR_FROM_OPENVZ diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 1b213c4..75d52e2 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -57,7 +57,7 @@ #include "virfile.h" #include "virtypedparam.h" #include "logging.h" -#include "command.h" +#include "vircommand.h" #include "viruri.h" #include "stats_linux.h" diff --git a/src/openvz/openvz_util.c b/src/openvz/openvz_util.c index 111045f..4163e19 100644 --- a/src/openvz/openvz_util.c +++ b/src/openvz/openvz_util.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" -#include "command.h" +#include "vircommand.h" #include "datatypes.h" #include "memory.h" diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 60507e7..648cb48 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -46,7 +46,7 @@ #include "memory.h" #include "util.h" #include "logging.h" -#include "command.h" +#include "vircommand.h" #include "configmake.h" #include "storage_file.h" #include "nodeinfo.h" diff --git a/src/parallels/parallels_utils.c b/src/parallels/parallels_utils.c index 521fd97..e47ff76 100644 --- a/src/parallels/parallels_utils.c +++ b/src/parallels/parallels_utils.c @@ -24,7 +24,7 @@ #include <stdarg.h> -#include "command.h" +#include "vircommand.h" #include "virterror_internal.h" #include "memory.h" #include "json.h" diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 45962b0..f68e081 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -34,7 +34,7 @@ #include "nodeinfo.h" #include "cpu/cpu.h" #include "domain_conf.h" -#include "command.h" +#include "vircommand.h" #include "virbitmap.h" #include "virnodesuspend.h" #include "qemu_monitor.h" diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index bf4eef8..cd7ee92 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -26,7 +26,7 @@ # include "virobject.h" # include "capabilities.h" -# include "command.h" +# include "vircommand.h" # include "virobject.h" # include "qemu_monitor.h" diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 0dde4be..b3ac4a6 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -25,7 +25,7 @@ # define __QEMU_COMMAND_H__ # include "domain_conf.h" -# include "command.h" +# include "vircommand.h" # include "capabilities.h" # include "qemu_conf.h" # include "qemu_domain.h" diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index bcf21c3..eafaf9f 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -40,7 +40,7 @@ # include "cpu_conf.h" # include "driver.h" # include "virbitmap.h" -# include "command.h" +# include "vircommand.h" # include "threadpool.h" # include "locking/lock_manager.h" # include "qemu_capabilities.h" diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index f32e88e..8b77e7d 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -41,7 +41,7 @@ #include "memory.h" #include "util.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #include "intprops.h" #include "virtypedparam.h" #include "viruri.h" diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h index e024640..fcd54dd 100644 --- a/src/rpc/virnetsocket.h +++ b/src/rpc/virnetsocket.h @@ -25,7 +25,7 @@ # define __VIR_NET_SOCKET_H__ # include "virsocketaddr.h" -# include "command.h" +# include "vircommand.h" # include "virnettlscontext.h" # include "virobject.h" # ifdef HAVE_SASL diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index b0cdb65..ff8aea1 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -47,7 +47,7 @@ #include "hostusb.h" #include "virfile.h" #include "configmake.h" -#include "command.h" +#include "vircommand.h" #include "logging.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 78ebae3..bfd6305 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -43,7 +43,7 @@ #include "virbuffer.h" #include "util.h" #include "memory.h" -#include "command.h" +#include "vircommand.h" #include "security_driver.h" #include "security_apparmor.h" diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h index c991015..56b6797 100644 --- a/src/storage/storage_backend.h +++ b/src/storage/storage_backend.h @@ -26,7 +26,7 @@ # include "internal.h" # include "storage_conf.h" -# include "command.h" +# include "vircommand.h" typedef char * (*virStorageBackendFindPoolSources)(virConnectPtr conn, const char *srcSpec, unsigned int flags); typedef int (*virStorageBackendCheckPool)(virConnectPtr conn, virStoragePoolObjPtr pool, bool *active); diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c index 06b5909..c6aa407 100644 --- a/src/storage/storage_backend_disk.c +++ b/src/storage/storage_backend_disk.c @@ -31,7 +31,7 @@ #include "storage_backend_disk.h" #include "util.h" #include "memory.h" -#include "command.h" +#include "vircommand.h" #include "configmake.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index fcc46b7..cdf93af 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -45,7 +45,7 @@ #include "storage_backend_fs.h" #include "storage_conf.h" #include "storage_file.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "xml.h" #include "virfile.h" diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index b080250..c468b1b 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -41,7 +41,7 @@ #include "memory.h" #include "logging.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #include "virrandom.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c index fd5cbd1..53e6c61 100644 --- a/src/storage/storage_backend_logical.c +++ b/src/storage/storage_backend_logical.c @@ -34,7 +34,7 @@ #include "virterror_internal.h" #include "storage_backend_logical.h" #include "storage_conf.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "logging.h" #include "virfile.h" diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c index 4e832eb..6515e57 100644 --- a/src/storage/storage_backend_scsi.c +++ b/src/storage/storage_backend_scsi.c @@ -33,7 +33,7 @@ #include "memory.h" #include "logging.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c index 66d8fb4..ecca7a8 100644 --- a/src/storage/storage_backend_sheepdog.c +++ b/src/storage/storage_backend_sheepdog.c @@ -29,7 +29,7 @@ #include "virterror_internal.h" #include "storage_backend_sheepdog.h" #include "storage_conf.h" -#include "util/command.h" +#include "vircommand.h" #include "util.h" #include "memory.h" #include "logging.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 11c915e..6aec8fc 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -45,7 +45,7 @@ #include "logging.h" #include "domain_nwfilter.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #include "virnetdevtap.h" #include "virnodesuspend.h" diff --git a/src/uml/uml_conf.h b/src/uml/uml_conf.h index 9bddedc..09a0305 100644 --- a/src/uml/uml_conf.h +++ b/src/uml/uml_conf.h @@ -31,7 +31,7 @@ # include "domain_event.h" # include "virterror_internal.h" # include "threads.h" -# include "command.h" +# include "vircommand.h" # include "virhash.h" # define umlDebug(fmt, ...) do {} while(0) diff --git a/src/util/command.c b/src/util/command.c deleted file mode 100644 index fbd9ff8..0000000 --- a/src/util/command.c +++ /dev/null @@ -1,2523 +0,0 @@ -/* - * command.c: Child command execution - * - * Copyright (C) 2010-2012 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <config.h> - -#include <poll.h> -#include <signal.h> -#include <stdarg.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <fcntl.h> - -#if HAVE_CAPNG -# include <cap-ng.h> -#endif - -#include "command.h" -#include "memory.h" -#include "virterror_internal.h" -#include "util.h" -#include "logging.h" -#include "virfile.h" -#include "virpidfile.h" -#include "virprocess.h" -#include "virbuffer.h" - -#define VIR_FROM_THIS VIR_FROM_NONE - -/* Flags for virExecWithHook */ -enum { - VIR_EXEC_NONE = 0, - VIR_EXEC_NONBLOCK = (1 << 0), - VIR_EXEC_DAEMON = (1 << 1), - VIR_EXEC_CLEAR_CAPS = (1 << 2), - VIR_EXEC_RUN_SYNC = (1 << 3), -}; - -struct _virCommand { - int has_error; /* ENOMEM on allocation failure, -1 for anything else. */ - - char **args; - size_t nargs; - size_t maxargs; - - char **env; - size_t nenv; - size_t maxenv; - - char *pwd; - - int *preserve; /* FDs to pass to child. */ - int preserve_size; - int *transfer; /* FDs to close in parent. */ - int transfer_size; - - unsigned int flags; - - char *inbuf; - char **outbuf; - char **errbuf; - - int infd; - int outfd; - int errfd; - int *outfdptr; - int *errfdptr; - - bool handshake; - int handshakeWait[2]; - int handshakeNotify[2]; - - virExecHook hook; - void *opaque; - - pid_t pid; - char *pidfile; - bool reap; - - unsigned long long capabilities; -}; - -/* - * virCommandFDIsSet: - * @fd: FD to test - * @set: the set - * @set_size: actual size of @set - * - * Check if FD is already in @set or not. - * - * Returns true if @set contains @fd, - * false otherwise. - */ -static bool -virCommandFDIsSet(int fd, - const int *set, - int set_size) -{ - int i = 0; - - while (i < set_size) - if (set[i++] == fd) - return true; - - return false; -} - -/* - * virCommandFDSet: - * @fd: FD to be put into @set - * @set: the set - * @set_size: actual size of @set - * - * This is practically generalized implementation - * of FD_SET() as we do not want to be limited - * by FD_SETSIZE. - * - * Returns: 0 on success, - * -1 on usage error, - * ENOMEM on OOM - */ -static int -virCommandFDSet(int fd, - int **set, - int *set_size) -{ - if (fd < 0 || !set || !set_size) - return -1; - - if (virCommandFDIsSet(fd, *set, *set_size)) - return 0; - - if (VIR_REALLOC_N(*set, *set_size + 1) < 0) { - return ENOMEM; - } - - (*set)[*set_size] = fd; - (*set_size)++; - - return 0; -} - -#ifndef WIN32 - -static int virClearCapabilities(void) ATTRIBUTE_UNUSED; - -# if HAVE_CAPNG -static int virClearCapabilities(void) -{ - int ret; - - capng_clear(CAPNG_SELECT_BOTH); - - if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot clear process capabilities %d"), ret); - return -1; - } - - return 0; -} - -/** - * virSetCapabilities: - * @capabilities - capability flag to set. - * In case of 0, this function is identical to - * virClearCapabilities() - * - */ -static int virSetCapabilities(unsigned long long capabilities) -{ - int ret, i; - - capng_clear(CAPNG_SELECT_BOTH); - - for (i = 0; i <= CAP_LAST_CAP; i++) { - if (capabilities & (1ULL << i)) - capng_update(CAPNG_ADD, CAPNG_BOUNDING_SET, i); - } - - if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot apply process capabilities %d"), ret); - return -1; - } - - return 0; -} -# else -static int virClearCapabilities(void) -{ -// VIR_WARN("libcap-ng support not compiled in, unable to clear " -// "capabilities"); - return 0; -} - -static int -virSetCapabilities(unsigned long long capabilities ATTRIBUTE_UNUSED) -{ - return 0; -} -# endif - -/** - * virFork: - * @pid - a pointer to a pid_t that will receive the return value from - * fork() - * - * fork a new process while avoiding various race/deadlock conditions - * - * on return from virFork(), if *pid < 0, the fork failed and there is - * no new process. Otherwise, just like fork(), if *pid == 0, it is the - * child process returning, and if *pid > 0, it is the parent. - * - * Even if *pid >= 0, if the return value from virFork() is < 0, it - * indicates a failure that occurred in the parent or child process - * after the fork. In this case, the child process should call - * _exit(EXIT_FAILURE) after doing any additional error reporting. - */ -int -virFork(pid_t *pid) -{ - sigset_t oldmask, newmask; - struct sigaction sig_action; - int saved_errno, ret = -1; - - *pid = -1; - - /* - * 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) { - saved_errno = errno; - virReportSystemError(errno, - "%s", _("cannot block signals")); - goto cleanup; - } - - /* Ensure we hold the logging lock, to protect child processes - * from deadlocking on another thread's inherited mutex state */ - virLogLock(); - - *pid = fork(); - saved_errno = errno; /* save for caller */ - - /* Unlock for both parent and child process */ - virLogUnlock(); - - if (*pid < 0) { - /* attempt to restore signal mask, but ignore failure, to - avoid obscuring the fork failure */ - ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL)); - virReportSystemError(saved_errno, - "%s", _("cannot fork child process")); - goto cleanup; - } - - if (*pid) { - - /* parent process */ - - /* Restore our original signal mask now that the child is - safely running */ - if (pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0) { - saved_errno = errno; /* save for caller */ - virReportSystemError(errno, "%s", _("cannot unblock signals")); - goto cleanup; - } - ret = 0; - - } else { - - /* child process */ - - int logprio; - int i; - - /* Remove any error callback so errors in child now - get sent to stderr where they stand a fighting chance - of being seen / logged */ - virSetErrorFunc(NULL, NULL); - virSetErrorLogPriorityFunc(NULL); - - /* Make sure any hook logging is sent to stderr, since child - * process may close the logfile FDs */ - logprio = virLogGetDefaultPriority(); - virLogReset(); - virLogSetDefaultPriority(logprio); - - /* 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) { - saved_errno = errno; /* save for caller */ - virReportSystemError(errno, "%s", _("cannot unblock signals")); - goto cleanup; - } - ret = 0; - } - -cleanup: - if (ret < 0) - errno = saved_errno; - return ret; -} - -/* - * Ensure that *null is an fd visiting /dev/null. Return 0 on - * success, -1 on failure. Allows for lazy opening of shared - * /dev/null fd only as required. - */ -static int -getDevNull(int *null) -{ - if (*null == -1 && (*null = open("/dev/null", O_RDWR|O_CLOEXEC)) < 0) { - virReportSystemError(errno, - _("cannot open %s"), - "/dev/null"); - return -1; - } - return 0; -} - -/* Ensure that STD is an inheritable copy of FD. Return 0 on success, - * -1 on failure. */ -static int -prepareStdFd(int fd, int std) -{ - if (fd == std) - return virSetInherit(fd, true); - if (dup2(fd, std) != std) - return -1; - return 0; -} - -/* - * @argv argv to exec - * @envp optional environment 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 - * @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) - * @capabilities capabilities to keep - */ -static int -virExecWithHook(const char *const*argv, - const char *const*envp, - const int *keepfd, - int keepfd_size, - pid_t *retpid, - int infd, int *outfd, int *errfd, - unsigned int flags, - virExecHook hook, - void *data, - char *pidfile, - unsigned long long capabilities) -{ - pid_t pid; - int null = -1, i, openmax; - int pipeout[2] = {-1,-1}; - int pipeerr[2] = {-1,-1}; - int childout = -1; - int childerr = -1; - int tmpfd; - const char *binary = NULL; - int forkRet; - - if (argv[0][0] != '/') { - if (!(binary = virFindFileInPath(argv[0]))) { - virReportSystemError(ENOENT, - _("Cannot find '%s' in path"), - argv[0]); - return -1; - } - } else { - binary = argv[0]; - } - - if (infd < 0) { - if (getDevNull(&null) < 0) - goto cleanup; - infd = null; - } - - if (outfd != NULL) { - if (*outfd == -1) { - if (pipe2(pipeout, O_CLOEXEC) < 0) { - virReportSystemError(errno, - "%s", _("cannot create pipe")); - goto cleanup; - } - - if ((flags & VIR_EXEC_NONBLOCK) && - virSetNonBlock(pipeout[0]) == -1) { - virReportSystemError(errno, - "%s", _("Failed to set non-blocking file descriptor flag")); - goto cleanup; - } - - childout = pipeout[1]; - } else { - childout = *outfd; - } - } else { - if (getDevNull(&null) < 0) - goto cleanup; - childout = null; - } - - if (errfd != NULL) { - if (errfd == outfd) { - childerr = childout; - } else if (*errfd == -1) { - if (pipe2(pipeerr, O_CLOEXEC) < 0) { - virReportSystemError(errno, - "%s", _("Failed to create pipe")); - goto cleanup; - } - - if ((flags & VIR_EXEC_NONBLOCK) && - virSetNonBlock(pipeerr[0]) == -1) { - virReportSystemError(errno, - "%s", _("Failed to set non-blocking file descriptor flag")); - goto cleanup; - } - - childerr = pipeerr[1]; - } else { - childerr = *errfd; - } - } else { - if (getDevNull(&null) < 0) - goto cleanup; - childerr = null; - } - - forkRet = virFork(&pid); - - if (pid < 0) { - goto cleanup; - } - - if (pid) { /* parent */ - if (forkRet < 0) { - goto cleanup; - } - - VIR_FORCE_CLOSE(null); - if (outfd && *outfd == -1) { - VIR_FORCE_CLOSE(pipeout[1]); - *outfd = pipeout[0]; - } - if (errfd && *errfd == -1) { - VIR_FORCE_CLOSE(pipeerr[1]); - *errfd = pipeerr[0]; - } - - *retpid = pid; - - if (binary != argv[0]) - VIR_FREE(binary); - - return 0; - } - - /* child */ - - if (forkRet < 0) { - /* The fork was successful, but after that there was an error - * in the child (which was already logged). - */ - goto fork_error; - } - - openmax = sysconf(_SC_OPEN_MAX); - for (i = 3; i < openmax; i++) { - if (i == infd || i == childout || i == childerr) - continue; - if (!keepfd || !virCommandFDIsSet(i, keepfd, keepfd_size)) { - tmpfd = i; - VIR_MASS_CLOSE(tmpfd); - } else if (virSetInherit(i, true) < 0) { - virReportSystemError(errno, _("failed to preserve fd %d"), i); - goto fork_error; - } - } - - if (prepareStdFd(infd, STDIN_FILENO) < 0) { - virReportSystemError(errno, - "%s", _("failed to setup stdin file handle")); - goto fork_error; - } - if (childout > 0 && prepareStdFd(childout, STDOUT_FILENO) < 0) { - virReportSystemError(errno, - "%s", _("failed to setup stdout file handle")); - goto fork_error; - } - if (childerr > 0 && prepareStdFd(childerr, STDERR_FILENO) < 0) { - virReportSystemError(errno, - "%s", _("failed to setup stderr file handle")); - goto fork_error; - } - - if (infd != STDIN_FILENO && infd != null && infd != childerr && - infd != childout) - VIR_FORCE_CLOSE(infd); - if (childout > STDERR_FILENO && childout != null && childout != childerr) - VIR_FORCE_CLOSE(childout); - if (childerr > STDERR_FILENO && childerr != null) - VIR_FORCE_CLOSE(childerr); - VIR_FORCE_CLOSE(null); - - /* Initialize full logging for a while */ - virLogSetFromEnv(); - - /* 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(errno, - "%s", _("cannot become session leader")); - goto fork_error; - } - - if (chdir("/") < 0) { - virReportSystemError(errno, - "%s", _("cannot change to root directory")); - goto fork_error; - } - - pid = fork(); - if (pid < 0) { - virReportSystemError(errno, - "%s", _("cannot fork child process")); - goto fork_error; - } - - if (pid > 0) { - if (pidfile && (virPidFileWritePath(pidfile,pid) < 0)) { - kill(pid, SIGTERM); - usleep(500*1000); - kill(pid, SIGTERM); - virReportSystemError(errno, - _("could not write pidfile %s for %d"), - pidfile, pid); - goto fork_error; - } - _exit(0); - } - } - - if (hook) { - /* virFork reset all signal handlers to the defaults. - * This is good for the child process, but our hook - * risks running something that generates SIGPIPE, - * so we need to temporarily block that again - */ - struct sigaction waxon, waxoff; - memset(&waxoff, 0, sizeof(waxoff)); - waxoff.sa_handler = SIG_IGN; - sigemptyset(&waxoff.sa_mask); - memset(&waxon, 0, sizeof(waxon)); - if (sigaction(SIGPIPE, &waxoff, &waxon) < 0) { - virReportSystemError(errno, "%s", - _("Could not disable SIGPIPE")); - goto fork_error; - } - - if ((hook)(data) != 0) { - VIR_DEBUG("Hook function failed."); - goto fork_error; - } - - if (sigaction(SIGPIPE, &waxon, NULL) < 0) { - virReportSystemError(errno, "%s", - _("Could not re-enable SIGPIPE")); - goto fork_error; - } - } - - /* The steps above may need todo something privileged, so - * we delay clearing capabilities until the last minute */ - if (capabilities || (flags & VIR_EXEC_CLEAR_CAPS)) - if (virSetCapabilities(capabilities) < 0) - goto fork_error; - - /* Close logging again to ensure no FDs leak to child */ - virLogReset(); - - if (envp) - execve(binary, (char **) argv, (char**)envp); - else - execv(binary, (char **) argv); - - virReportSystemError(errno, - _("cannot execute binary %s"), - argv[0]); - - fork_error: - virDispatchError(NULL); - _exit(EXIT_FAILURE); - - cleanup: - /* This is cleanup of parent process only - child - should never jump here on error */ - - if (binary != argv[0]) - VIR_FREE(binary); - - /* NB we don't virReportError() on any failures here - because the code which jumped here already raised - an error condition which we must not overwrite */ - VIR_FORCE_CLOSE(pipeerr[0]); - VIR_FORCE_CLOSE(pipeerr[1]); - VIR_FORCE_CLOSE(pipeout[0]); - VIR_FORCE_CLOSE(pipeout[1]); - VIR_FORCE_CLOSE(null); - return -1; -} - -/** - * virRun: - * @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(const char *const*argv, int *status) -{ - int ret; - virCommandPtr cmd = virCommandNewArgs(argv); - - ret = virCommandRun(cmd, status); - virCommandFree(cmd); - return ret; -} - -#else /* WIN32 */ - -int -virRun(const char *const *argv ATTRIBUTE_UNUSED, - int *status) -{ - if (status) - *status = ENOTSUP; - else - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virRun is not implemented for WIN32")); - return -1; -} - -static int -virExecWithHook(const char *const*argv ATTRIBUTE_UNUSED, - const char *const*envp ATTRIBUTE_UNUSED, - const int *keepfd ATTRIBUTE_UNUSED, - int keepfd_size ATTRIBUTE_UNUSED, - pid_t *retpid ATTRIBUTE_UNUSED, - int infd ATTRIBUTE_UNUSED, - int *outfd ATTRIBUTE_UNUSED, - int *errfd ATTRIBUTE_UNUSED, - int flags_unused ATTRIBUTE_UNUSED, - virExecHook hook ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, - char *pidfile ATTRIBUTE_UNUSED, - unsigned long long capabilities ATTRIBUTE_UNUSED) -{ - /* XXX: Some day we can implement pieces of virCommand/virExec on - * top of _spawn() or CreateProcess(), but we can't implement - * everything, since mingw completely lacks fork(), so we cannot - * run hook code in the child. */ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virExec is not implemented for WIN32")); - return -1; -} - -int -virFork(pid_t *pid) -{ - *pid = -1; - errno = ENOTSUP; - - return -1; -} - -#endif /* WIN32 */ - - -/** - * virCommandNew: - * @binary: program to run - * - * Create a new command for named binary. If @binary is relative, - * it will be found via a PATH search of the parent's PATH (and not - * any altered PATH set by virCommandAddEnv* commands). - */ -virCommandPtr -virCommandNew(const char *binary) -{ - const char *const args[] = { binary, NULL }; - - return virCommandNewArgs(args); -} - -/** - * virCommandNewArgs: - * @args: array of arguments - * - * Create a new command with a NULL terminated - * set of args, taking binary from args[0]. More arguments can - * be added later. @args[0] is handled like @binary of virCommandNew. - */ -virCommandPtr -virCommandNewArgs(const char *const*args) -{ - virCommandPtr cmd; - - if (VIR_ALLOC(cmd) < 0) - return NULL; - - cmd->handshakeWait[0] = -1; - cmd->handshakeWait[1] = -1; - cmd->handshakeNotify[0] = -1; - cmd->handshakeNotify[1] = -1; - - cmd->infd = cmd->outfd = cmd->errfd = -1; - cmd->pid = -1; - - virCommandAddArgSet(cmd, args); - - return cmd; -} - -/** - * virCommandNewArgList: - * @binary: program to run - * @...: additional arguments - * - * Create a new command with a NULL terminated - * list of args, starting with the binary to run. More arguments can - * be added later. @binary is handled as in virCommandNew. - */ -virCommandPtr -virCommandNewArgList(const char *binary, ...) -{ - virCommandPtr cmd = virCommandNew(binary); - va_list list; - const char *arg; - - if (!cmd || cmd->has_error) - return cmd; - - va_start(list, binary); - while ((arg = va_arg(list, const char *)) != NULL) - virCommandAddArg(cmd, arg); - va_end(list); - return cmd; -} - -/** - * virCommandNewVAList: - * @binary: program to run - * @va_list: additional arguments - * - * Create a new command with a NULL terminated - * variable argument list. @binary is handled as in virCommandNew. - */ -virCommandPtr -virCommandNewVAList(const char *binary, va_list list) -{ - virCommandPtr cmd = virCommandNew(binary); - const char *arg; - - if (!cmd || cmd->has_error) - return cmd; - - while ((arg = va_arg(list, const char *)) != NULL) - virCommandAddArg(cmd, arg); - return cmd; -} - - -/* - * Preserve the specified file descriptor in the child, instead of - * closing it. FD must not be one of the three standard streams. If - * transfer is true, then fd will be closed in the parent after a call - * to Run/RunAsync/Free, otherwise caller is still responsible for fd. - * Returns true if a transferring caller should close FD now, and - * false if the transfer is successfully recorded. - */ -static bool -virCommandKeepFD(virCommandPtr cmd, int fd, bool transfer) -{ - int ret = 0; - - if (!cmd) - return fd > STDERR_FILENO; - - if (fd <= STDERR_FILENO || - (ret = virCommandFDSet(fd, &cmd->preserve, &cmd->preserve_size)) || - (transfer && (ret = virCommandFDSet(fd, &cmd->transfer, - &cmd->transfer_size)))) { - if (!cmd->has_error) - cmd->has_error = ret ? ret : -1 ; - VIR_DEBUG("cannot preserve %d", fd); - return fd > STDERR_FILENO; - } - - return false; -} - -/** - * virCommandPreserveFD: - * @cmd: the command to modify - * @fd: fd to mark for inheritance into child - * - * Preserve the specified file descriptor - * in the child, instead of closing it on exec. - * The parent is still responsible for managing fd. - */ -void -virCommandPreserveFD(virCommandPtr cmd, int fd) -{ - virCommandKeepFD(cmd, fd, false); -} - -/** - * virCommandTransferFD: - * @cmd: the command to modify - * @fd: fd to reassign to the child - * - * Transfer the specified file descriptor - * to the child, instead of closing it on exec. - * The parent should no longer use fd, and the parent's copy will - * be automatically closed no later than during Run/RunAsync/Free. - */ -void -virCommandTransferFD(virCommandPtr cmd, int fd) -{ - if (virCommandKeepFD(cmd, fd, true)) - VIR_FORCE_CLOSE(fd); -} - - -/** - * virCommandSetPidFile: - * @cmd: the command to modify - * @pidfile: filename to use - * - * Save the child PID in a pidfile. The pidfile will be populated - * before the exec of the child. - */ -void -virCommandSetPidFile(virCommandPtr cmd, const char *pidfile) -{ - if (!cmd || cmd->has_error) - return; - - VIR_FREE(cmd->pidfile); - if (!(cmd->pidfile = strdup(pidfile))) { - cmd->has_error = ENOMEM; - } -} - - -/** - * virCommandClearCaps: - * @cmd: the command to modify - * - * Remove all capabilities from the child, after any hooks have been run. - */ -void -virCommandClearCaps(virCommandPtr cmd) -{ - if (!cmd || cmd->has_error) - return; - - cmd->flags |= VIR_EXEC_CLEAR_CAPS; -} - -/** - * virCommandAllowCap: - * @cmd: the command to modify - * @capability: what to allow - * - * Allow specific capabilities - */ -void -virCommandAllowCap(virCommandPtr cmd, - int capability) -{ - if (!cmd || cmd->has_error) - return; - - cmd->capabilities |= (1ULL << capability); -} - - - -/** - * virCommandDaemonize: - * @cmd: the command to modify - * - * Daemonize the child process. The child will have a current working - * directory of /, and must be started with virCommandRun, which will - * complete as soon as the daemon grandchild has started. - */ -void -virCommandDaemonize(virCommandPtr cmd) -{ - if (!cmd || cmd->has_error) - return; - - cmd->flags |= VIR_EXEC_DAEMON; -} - -/** - * virCommandNonblockingFDs: - * @cmd: the command to modify - * - * Set FDs created by virCommandSetOutputFD and virCommandSetErrorFD - * as non-blocking in the parent. - */ -void -virCommandNonblockingFDs(virCommandPtr cmd) -{ - if (!cmd || cmd->has_error) - return; - - cmd->flags |= VIR_EXEC_NONBLOCK; -} - -/* Add an environment variable to the cmd->env list. 'env' is a - * string like "name=value". If the named environment variable is - * already set, then it is replaced in the list. - */ -static inline void -virCommandAddEnv(virCommandPtr cmd, char *env) -{ - size_t namelen; - size_t i; - - /* Search for the name in the existing environment. */ - namelen = strcspn(env, "="); - for (i = 0; i < cmd->nenv; ++i) { - /* + 1 because we want to match the '=' character too. */ - if (STREQLEN(cmd->env[i], env, namelen + 1)) { - VIR_FREE(cmd->env[i]); - cmd->env[i] = env; - return; - } - } - - /* Arg plus trailing NULL. */ - if (VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 1 + 1) < 0) { - VIR_FREE(env); - cmd->has_error = ENOMEM; - return; - } - - cmd->env[cmd->nenv++] = env; -} - -/** - * virCommandAddEnvFormat: - * @cmd: the command to modify - * @format: format of arguments, end result must be in name=value format - * @...: arguments to be formatted - * - * Add an environment variable to the child created by a printf-style format. - */ -void -virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...) -{ - char *env; - va_list list; - - if (!cmd || cmd->has_error) - return; - - va_start(list, format); - if (virVasprintf(&env, format, list) < 0) { - cmd->has_error = ENOMEM; - va_end(list); - return; - } - va_end(list); - - virCommandAddEnv(cmd, env); -} - -/** - * virCommandAddEnvPair: - * @cmd: the command to modify - * @name: variable name, must not contain = - * @value: value to assign to name - * - * Add an environment variable to the child - * using separate name & value strings - */ -void -virCommandAddEnvPair(virCommandPtr cmd, const char *name, const char *value) -{ - virCommandAddEnvFormat(cmd, "%s=%s", name, value); -} - - -/** - * virCommandAddEnvString: - * @cmd: the command to modify - * @str: name=value format - * - * Add an environment variable to the child - * using a preformatted env string FOO=BAR - */ -void -virCommandAddEnvString(virCommandPtr cmd, const char *str) -{ - char *env; - - if (!cmd || cmd->has_error) - return; - - if (!(env = strdup(str))) { - cmd->has_error = ENOMEM; - return; - } - - virCommandAddEnv(cmd, env); -} - - -/** - * virCommandAddEnvBuffer: - * @cmd: the command to modify - * @buf: buffer that contains name=value string, which will be reset on return - * - * Convert a buffer containing preformatted name=value into an - * environment variable of the child. - * Correctly transfers memory errors or contents from buf to cmd. - */ -void -virCommandAddEnvBuffer(virCommandPtr cmd, virBufferPtr buf) -{ - if (!cmd || cmd->has_error) { - virBufferFreeAndReset(buf); - return; - } - - if (virBufferError(buf)) { - cmd->has_error = ENOMEM; - virBufferFreeAndReset(buf); - return; - } - if (!virBufferUse(buf)) { - cmd->has_error = EINVAL; - return; - } - - virCommandAddEnv(cmd, virBufferContentAndReset(buf)); -} - - -/** - * virCommandAddEnvPass: - * @cmd: the command to modify - * @name: the name to look up in current environment - * - * Pass an environment variable to the child - * using current process' value - */ -void -virCommandAddEnvPass(virCommandPtr cmd, const char *name) -{ - char *value; - if (!cmd || cmd->has_error) - return; - - value = getenv(name); - if (value) - virCommandAddEnvPair(cmd, name, value); -} - - -/** - * virCommandAddEnvPassCommon: - * @cmd: the command to modify - * - * Set LC_ALL to C, and propagate other essential environment - * variables (such as PATH) from the parent process. - */ -void -virCommandAddEnvPassCommon(virCommandPtr cmd) -{ - if (!cmd || cmd->has_error) - return; - - /* Attempt to Pre-allocate; allocation failure will be detected - * later during virCommandAdd*. */ - ignore_value(VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 9)); - - virCommandAddEnvPair(cmd, "LC_ALL", "C"); - - virCommandAddEnvPass(cmd, "LD_PRELOAD"); - virCommandAddEnvPass(cmd, "LD_LIBRARY_PATH"); - virCommandAddEnvPass(cmd, "PATH"); - virCommandAddEnvPass(cmd, "HOME"); - virCommandAddEnvPass(cmd, "USER"); - virCommandAddEnvPass(cmd, "LOGNAME"); - virCommandAddEnvPass(cmd, "TMPDIR"); -} - -/** - * virCommandAddArg: - * @cmd: the command to modify - * @val: the argument to add - * - * Add a command line argument to the child - */ -void -virCommandAddArg(virCommandPtr cmd, const char *val) -{ - char *arg; - - if (!cmd || cmd->has_error) - return; - - if (!(arg = strdup(val))) { - cmd->has_error = ENOMEM; - return; - } - - /* Arg plus trailing NULL. */ - if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) { - VIR_FREE(arg); - cmd->has_error = ENOMEM; - return; - } - - cmd->args[cmd->nargs++] = arg; -} - - -/** - * virCommandAddArgBuffer: - * @cmd: the command to modify - * @buf: buffer that contains argument string, which will be reset on return - * - * Convert a buffer into a command line argument to the child. - * Correctly transfers memory errors or contents from buf to cmd. - */ -void -virCommandAddArgBuffer(virCommandPtr cmd, virBufferPtr buf) -{ - if (!cmd || cmd->has_error) { - virBufferFreeAndReset(buf); - return; - } - - /* Arg plus trailing NULL. */ - if (virBufferError(buf) || - VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) { - cmd->has_error = ENOMEM; - virBufferFreeAndReset(buf); - return; - } - - cmd->args[cmd->nargs] = virBufferContentAndReset(buf); - if (!cmd->args[cmd->nargs]) - cmd->args[cmd->nargs] = strdup(""); - if (!cmd->args[cmd->nargs]) { - cmd->has_error = ENOMEM; - return; - } - cmd->nargs++; -} - - -/** - * virCommandAddArgFormat: - * @cmd: the command to modify - * @format: format of arguments, end result must be in name=value format - * @...: arguments to be formatted - * - * Add a command line argument created by a printf-style format. - */ -void -virCommandAddArgFormat(virCommandPtr cmd, const char *format, ...) -{ - char *arg; - va_list list; - - if (!cmd || cmd->has_error) - return; - - va_start(list, format); - if (virVasprintf(&arg, format, list) < 0) { - cmd->has_error = ENOMEM; - va_end(list); - return; - } - va_end(list); - - /* Arg plus trailing NULL. */ - if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) { - VIR_FREE(arg); - cmd->has_error = ENOMEM; - return; - } - - cmd->args[cmd->nargs++] = arg; -} - -/** - * virCommandAddArgPair: - * @cmd: the command to modify - * @name: left half of argument - * @value: right half of argument - * - * Add "NAME=VAL" as a single command line argument to the child - */ -void -virCommandAddArgPair(virCommandPtr cmd, const char *name, const char *val) -{ - virCommandAddArgFormat(cmd, "%s=%s", name, val); -} - -/** - * virCommandAddArgSet: - * @cmd: the command to modify - * @vals: array of arguments to add - * - * Add a NULL terminated list of args - */ -void -virCommandAddArgSet(virCommandPtr cmd, const char *const*vals) -{ - int narg = 0; - - if (!cmd || cmd->has_error) - return; - - if (vals[0] == NULL) { - cmd->has_error = EINVAL; - return; - } - - while (vals[narg] != NULL) - narg++; - - /* narg plus trailing NULL. */ - if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) { - cmd->has_error = ENOMEM; - return; - } - - narg = 0; - while (vals[narg] != NULL) { - char *arg = strdup(vals[narg++]); - if (!arg) { - cmd->has_error = ENOMEM; - return; - } - cmd->args[cmd->nargs++] = arg; - } -} - -/** - * virCommandAddArgList: - * @cmd: the command to modify - * @...: list of arguments to add - * - * Add a NULL terminated list of args. - */ -void -virCommandAddArgList(virCommandPtr cmd, ...) -{ - va_list list; - int narg = 0; - - if (!cmd || cmd->has_error) - return; - - va_start(list, cmd); - while (va_arg(list, const char *) != NULL) - narg++; - va_end(list); - - /* narg plus trailing NULL. */ - if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) { - cmd->has_error = ENOMEM; - return; - } - - va_start(list, cmd); - while (1) { - char *arg = va_arg(list, char *); - if (!arg) - break; - arg = strdup(arg); - if (!arg) { - cmd->has_error = ENOMEM; - va_end(list); - return; - } - cmd->args[cmd->nargs++] = arg; - } - va_end(list); -} - -/** - * virCommandSetWorkingDirectory: - * @cmd: the command to modify - * @pwd: directory to use - * - * Set the working directory of a non-daemon child process, rather - * than the parent's working directory. Daemons automatically get / - * without using this call. - */ -void -virCommandSetWorkingDirectory(virCommandPtr cmd, const char *pwd) -{ - if (!cmd || cmd->has_error) - return; - - if (cmd->pwd) { - cmd->has_error = -1; - VIR_DEBUG("cannot set directory twice"); - } else { - cmd->pwd = strdup(pwd); - if (!cmd->pwd) - cmd->has_error = ENOMEM; - } -} - - -/** - * virCommandSetInputBuffer: - * @cmd: the command to modify - * @inbuf: string to feed to stdin - * - * Feed the child's stdin from a string buffer. This requires the use - * of virCommandRun(). - */ -void -virCommandSetInputBuffer(virCommandPtr cmd, const char *inbuf) -{ - if (!cmd || cmd->has_error) - return; - - if (cmd->infd != -1 || cmd->inbuf) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify input twice"); - return; - } - - cmd->inbuf = strdup(inbuf); - if (!cmd->inbuf) - cmd->has_error = ENOMEM; -} - - -/** - * virCommandSetOutputBuffer: - * @cmd: the command to modify - * @outbuf: address of variable to store malloced result buffer - * - * Capture the child's stdout to a string buffer. *outbuf is - * guaranteed to be allocated after successful virCommandRun or - * virCommandWait, and is best-effort allocated after failed - * virCommandRun; caller is responsible for freeing *outbuf. - * This requires the use of virCommandRun. - */ -void -virCommandSetOutputBuffer(virCommandPtr cmd, char **outbuf) -{ - *outbuf = NULL; - if (!cmd || cmd->has_error) - return; - - if (cmd->outfdptr) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify output twice"); - return; - } - - cmd->outbuf = outbuf; - cmd->outfdptr = &cmd->outfd; -} - - -/** - * virCommandSetErrorBuffer: - * @cmd: the command to modify - * @errbuf: address of variable to store malloced result buffer - * - * Capture the child's stderr to a string buffer. *errbuf is - * guaranteed to be allocated after successful virCommandRun or - * virCommandWait, and is best-effort allocated after failed - * virCommandRun; caller is responsible for freeing *errbuf. - * This requires the use of virCommandRun. It is possible to - * pass the same pointer as for virCommandSetOutputBuffer(), in - * which case the child process will interleave all output into - * a single string. - */ -void -virCommandSetErrorBuffer(virCommandPtr cmd, char **errbuf) -{ - *errbuf = NULL; - if (!cmd || cmd->has_error) - return; - - if (cmd->errfdptr) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify stderr twice"); - return; - } - - cmd->errbuf = errbuf; - cmd->errfdptr = &cmd->errfd; -} - - -/** - * virCommandSetInputFD: - * @cmd: the command to modify - * @infd: the descriptor to use - * - * Attach a file descriptor to the child's stdin - */ -void -virCommandSetInputFD(virCommandPtr cmd, int infd) -{ - if (!cmd || cmd->has_error) - return; - - if (cmd->infd != -1 || cmd->inbuf) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify input twice"); - return; - } - if (infd < 0) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify invalid input fd"); - return; - } - - cmd->infd = infd; -} - - -/** - * virCommandSetOutputFD: - * @cmd: the command to modify - * @outfd: location of output fd - * - * Attach a file descriptor to the child's stdout. If *@outfd is -1 on - * entry, then a pipe will be created and returned in this variable when - * the child is run. Otherwise, *@outfd is used as the output. - */ -void -virCommandSetOutputFD(virCommandPtr cmd, int *outfd) -{ - if (!cmd || cmd->has_error) - return; - - if (cmd->outfdptr) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify output twice"); - return; - } - - cmd->outfdptr = outfd; -} - - -/** - * virCommandSetErrorFD: - * @cmd: the command to modify - * @errfd: location of error fd - * - * Attach a file descriptor to the child's stderr. If *@errfd is -1 on - * entry, then a pipe will be created and returned in this variable when - * the child is run. Otherwise, *@errfd is used for error collection, - * and may be the same as outfd given to virCommandSetOutputFD(). - */ -void -virCommandSetErrorFD(virCommandPtr cmd, int *errfd) -{ - if (!cmd || cmd->has_error) - return; - - if (cmd->errfdptr) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify stderr twice"); - return; - } - - cmd->errfdptr = errfd; -} - - -/** - * virCommandSetPreExecHook: - * @cmd: the command to modify - * @hook: the hook to run - * @opaque: argument to pass to the hook - * - * Run HOOK(OPAQUE) in the child as the last thing before changing - * directories, dropping capabilities, and executing the new process. - * Force the child to fail if HOOK does not return zero. - * - * Since @hook runs in the child, it should be careful to avoid - * any functions that are not async-signal-safe. - */ -void -virCommandSetPreExecHook(virCommandPtr cmd, virExecHook hook, void *opaque) -{ - if (!cmd || cmd->has_error) - return; - - if (cmd->hook) { - cmd->has_error = -1; - VIR_DEBUG("cannot specify hook twice"); - return; - } - cmd->hook = hook; - cmd->opaque = opaque; -} - - -/** - * virCommandWriteArgLog: - * @cmd: the command to log - * @logfd: where to log the results - * - * Call after adding all arguments and environment settings, but before - * Run/RunAsync, to immediately output the environment and arguments of - * cmd to logfd. If virCommandRun cannot succeed (because of an - * out-of-memory condition while building cmd), nothing will be logged. - */ -void -virCommandWriteArgLog(virCommandPtr cmd, int logfd) -{ - int ioError = 0; - size_t i; - - /* Any errors will be reported later by virCommandRun, which means - * no command will be run, so there is nothing to log. */ - if (!cmd || cmd->has_error) - return; - - for (i = 0 ; i < cmd->nenv ; i++) { - if (safewrite(logfd, cmd->env[i], strlen(cmd->env[i])) < 0) - ioError = errno; - if (safewrite(logfd, " ", 1) < 0) - ioError = errno; - } - for (i = 0 ; i < cmd->nargs ; i++) { - if (safewrite(logfd, cmd->args[i], strlen(cmd->args[i])) < 0) - ioError = errno; - if (safewrite(logfd, i == cmd->nargs - 1 ? "\n" : " ", 1) < 0) - ioError = errno; - } - - if (ioError) { - char ebuf[1024]; - VIR_WARN("Unable to write command %s args to logfile: %s", - cmd->args[0], virStrerror(ioError, ebuf, sizeof(ebuf))); - } -} - - -/** - * virCommandToString: - * @cmd: the command to convert - * - * Call after adding all arguments and environment settings, but - * before Run/RunAsync, to return a string representation of the - * environment and arguments of cmd, suitably quoted for pasting into - * a shell. If virCommandRun cannot succeed (because of an - * out-of-memory condition while building cmd), NULL will be returned. - * Caller is responsible for freeing the resulting string. - */ -char * -virCommandToString(virCommandPtr cmd) -{ - size_t i; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - /* Cannot assume virCommandRun will be called; so report the error - * now. If virCommandRun is called, it will report the same error. */ - if (!cmd ||cmd->has_error == ENOMEM) { - virReportOOMError(); - return NULL; - } - if (cmd->has_error) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return NULL; - } - - for (i = 0; i < cmd->nenv; i++) { - /* In shell, a='b c' has a different meaning than 'a=b c', so - * we must determine where the '=' lives. */ - char *eq = strchr(cmd->env[i], '='); - - if (!eq) { - virBufferFreeAndReset(&buf); - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return NULL; - } - eq++; - virBufferAdd(&buf, cmd->env[i], eq - cmd->env[i]); - virBufferEscapeShell(&buf, eq); - virBufferAddChar(&buf, ' '); - } - virBufferEscapeShell(&buf, cmd->args[0]); - for (i = 1; i < cmd->nargs; i++) { - virBufferAddChar(&buf, ' '); - virBufferEscapeShell(&buf, cmd->args[i]); - } - - if (virBufferError(&buf)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return NULL; - } - - return virBufferContentAndReset(&buf); -} - - -/* - * Manage input and output to the child process. - */ -static int -virCommandProcessIO(virCommandPtr cmd, int *inpipe) -{ - int infd = -1, outfd = -1, errfd = -1; - size_t inlen = 0, outlen = 0, errlen = 0; - size_t inoff = 0; - int ret = 0; - - /* With an input buffer, feed data to child - * via pipe */ - if (cmd->inbuf) { - inlen = strlen(cmd->inbuf); - infd = *inpipe; - } - - /* With out/err buffer, the outfd/errfd have been filled with an - * FD for us. Guarantee an allocated string with partial results - * even if we encounter a later failure, as well as freeing any - * results accumulated over a prior run of the same command. */ - if (cmd->outbuf) { - outfd = cmd->outfd; - if (VIR_REALLOC_N(*cmd->outbuf, 1) < 0) { - virReportOOMError(); - ret = -1; - } - } - if (cmd->errbuf) { - errfd = cmd->errfd; - if (VIR_REALLOC_N(*cmd->errbuf, 1) < 0) { - virReportOOMError(); - ret = -1; - } - } - if (ret == -1) - goto cleanup; - ret = -1; - - for (;;) { - int i; - struct pollfd fds[3]; - int nfds = 0; - - if (infd != -1) { - fds[nfds].fd = infd; - fds[nfds].events = POLLOUT; - fds[nfds].revents = 0; - nfds++; - } - if (outfd != -1) { - fds[nfds].fd = outfd; - fds[nfds].events = POLLIN; - fds[nfds].revents = 0; - nfds++; - } - if (errfd != -1) { - fds[nfds].fd = errfd; - fds[nfds].events = POLLIN; - fds[nfds].revents = 0; - nfds++; - } - - if (nfds == 0) - break; - - if (poll(fds, nfds, -1) < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - virReportSystemError(errno, "%s", - _("unable to poll on child")); - goto cleanup; - } - - for (i = 0; i < nfds ; i++) { - if (fds[i].revents & (POLLIN | POLLHUP | POLLERR) && - (fds[i].fd == errfd || fds[i].fd == outfd)) { - char data[1024]; - char **buf; - size_t *len; - int done; - if (fds[i].fd == outfd) { - buf = cmd->outbuf; - len = &outlen; - } else { - buf = cmd->errbuf; - len = &errlen; - } - /* Silence a false positive from clang. */ - sa_assert(buf); - - done = read(fds[i].fd, data, sizeof(data)); - if (done < 0) { - if (errno != EINTR && - errno != EAGAIN) { - virReportSystemError(errno, "%s", - (fds[i].fd == outfd) ? - _("unable to read child stdout") : - _("unable to read child stderr")); - goto cleanup; - } - } else if (done == 0) { - if (fds[i].fd == outfd) - outfd = -1; - else - errfd = -1; - } else { - if (VIR_REALLOC_N(*buf, *len + done + 1) < 0) { - virReportOOMError(); - goto cleanup; - } - memcpy(*buf + *len, data, done); - *len += done; - } - } - - if (fds[i].revents & (POLLOUT | POLLERR) && - fds[i].fd == infd) { - int done; - - /* Coverity 5.3.0 can't see that we only get here if - * infd is in the set because it was non-negative. */ - sa_assert(infd != -1); - done = write(infd, cmd->inbuf + inoff, - inlen - inoff); - if (done < 0) { - if (errno == EPIPE) { - VIR_DEBUG("child closed stdin early, ignoring EPIPE " - "on fd %d", infd); - if (VIR_CLOSE(*inpipe) < 0) - VIR_DEBUG("ignoring failed close on fd %d", infd); - infd = -1; - } else if (errno != EINTR && errno != EAGAIN) { - virReportSystemError(errno, "%s", - _("unable to write to child input")); - goto cleanup; - } - } else { - inoff += done; - if (inoff == inlen) { - if (VIR_CLOSE(*inpipe) < 0) - VIR_DEBUG("ignoring failed close on fd %d", infd); - infd = -1; - } - } - } - } - } - - ret = 0; -cleanup: - if (cmd->outbuf && *cmd->outbuf) - (*cmd->outbuf)[outlen] = '\0'; - if (cmd->errbuf && *cmd->errbuf) - (*cmd->errbuf)[errlen] = '\0'; - return ret; -} - -/** - * virCommandExec: - * @cmd: command to run - * - * Exec the command, replacing the current process. Meant to be called - * in the hook after already forking / cloning, so does not attempt to - * daemonize or preserve any FDs. - * - * Returns -1 on any error executing the command. - * Will not return on success. - */ -#ifndef WIN32 -int virCommandExec(virCommandPtr cmd) -{ - if (!cmd ||cmd->has_error == ENOMEM) { - virReportOOMError(); - return -1; - } - if (cmd->has_error) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return -1; - } - - return execve(cmd->args[0], cmd->args, cmd->env); -} -#else -int virCommandExec(virCommandPtr cmd ATTRIBUTE_UNUSED) -{ - /* Mingw execve() has a broken signature. Disable this - * function until gnulib fixes the signature, since we - * don't really need this on Win32 anyway. - */ - virReportSystemError(ENOSYS, "%s", - _("Executing new processes is not supported on Win32 platform")); - return -1; -} -#endif - -/** - * virCommandRun: - * @cmd: command to run - * @exitstatus: optional status collection - * - * Run the command and wait for completion. - * Returns -1 on any error executing the - * command. Returns 0 if the command executed, - * with the exit status set. If @exitstatus is NULL, then the - * child must exit with status 0 for this to succeed. - */ -int -virCommandRun(virCommandPtr cmd, int *exitstatus) -{ - int ret = 0; - char *outbuf = NULL; - char *errbuf = NULL; - int infd[2] = { -1, -1 }; - struct stat st; - bool string_io; - bool async_io = false; - char *str; - int tmpfd; - - if (!cmd ||cmd->has_error == ENOMEM) { - virReportOOMError(); - return -1; - } - if (cmd->has_error) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return -1; - } - - /* Avoid deadlock, by requiring that any open fd not under our - * control must be visiting a regular file, or that we are - * daemonized and no string io is required. */ - string_io = cmd->inbuf || cmd->outbuf || cmd->errbuf; - if (cmd->infd != -1 && - (fstat(cmd->infd, &st) < 0 || !S_ISREG(st.st_mode))) - async_io = true; - if (cmd->outfdptr && cmd->outfdptr != &cmd->outfd && - (*cmd->outfdptr == -1 || - fstat(*cmd->outfdptr, &st) < 0 || !S_ISREG(st.st_mode))) - async_io = true; - if (cmd->errfdptr && cmd->errfdptr != &cmd->errfd && - (*cmd->errfdptr == -1 || - fstat(*cmd->errfdptr, &st) < 0 || !S_ISREG(st.st_mode))) - async_io = true; - if (async_io) { - if (!(cmd->flags & VIR_EXEC_DAEMON) || string_io) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot mix caller fds with blocking execution")); - return -1; - } - } else { - if ((cmd->flags & VIR_EXEC_DAEMON) && string_io) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot mix string I/O with daemon")); - return -1; - } - } - - /* If we have an input buffer, we need - * a pipe to feed the data to the child */ - if (cmd->inbuf) { - if (pipe2(infd, O_CLOEXEC) < 0) { - virReportSystemError(errno, "%s", - _("unable to open pipe")); - cmd->has_error = -1; - return -1; - } - cmd->infd = infd[0]; - } - - /* If caller requested the same string for stdout and stderr, then - * merge those into one string. */ - if (cmd->outbuf && cmd->outbuf == cmd->errbuf) { - cmd->errfdptr = &cmd->outfd; - cmd->errbuf = NULL; - } - - /* If caller hasn't requested capture of stdout/err, then capture - * it ourselves so we can log it. But the intermediate child for - * a daemon has no expected output, and we don't want our - * capturing pipes passed on to the daemon grandchild. - */ - if (!(cmd->flags & VIR_EXEC_DAEMON)) { - if (!cmd->outfdptr) { - cmd->outfdptr = &cmd->outfd; - cmd->outbuf = &outbuf; - string_io = true; - } - if (!cmd->errfdptr) { - cmd->errfdptr = &cmd->errfd; - cmd->errbuf = &errbuf; - string_io = true; - } - } - - cmd->flags |= VIR_EXEC_RUN_SYNC; - if (virCommandRunAsync(cmd, NULL) < 0) { - if (cmd->inbuf) { - tmpfd = infd[0]; - if (VIR_CLOSE(infd[0]) < 0) - VIR_DEBUG("ignoring failed close on fd %d", tmpfd); - tmpfd = infd[1]; - if (VIR_CLOSE(infd[1]) < 0) - VIR_DEBUG("ignoring failed close on fd %d", tmpfd); - } - cmd->has_error = -1; - return -1; - } - - tmpfd = infd[0]; - if (VIR_CLOSE(infd[0]) < 0) - VIR_DEBUG("ignoring failed close on fd %d", tmpfd); - if (string_io) - ret = virCommandProcessIO(cmd, &infd[1]); - - if (virCommandWait(cmd, exitstatus) < 0) - ret = -1; - - str = (exitstatus ? virProcessTranslateStatus(*exitstatus) - : (char *) "status 0"); - VIR_DEBUG("Result %s, stdout: '%s' stderr: '%s'", - NULLSTR(str), - cmd->outbuf ? NULLSTR(*cmd->outbuf) : "(null)", - cmd->errbuf ? NULLSTR(*cmd->errbuf) : "(null)"); - if (exitstatus) - VIR_FREE(str); - - /* Reset any capturing, in case caller runs - * this identical command again */ - if (cmd->inbuf) { - tmpfd = infd[1]; - if (VIR_CLOSE(infd[1]) < 0) - VIR_DEBUG("ignoring failed close on fd %d", tmpfd); - } - if (cmd->outbuf == &outbuf) { - tmpfd = cmd->outfd; - if (VIR_CLOSE(cmd->outfd) < 0) - VIR_DEBUG("ignoring failed close on fd %d", tmpfd); - cmd->outfdptr = NULL; - cmd->outbuf = NULL; - VIR_FREE(outbuf); - } - if (cmd->errbuf == &errbuf) { - tmpfd = cmd->errfd; - if (VIR_CLOSE(cmd->errfd) < 0) - VIR_DEBUG("ignoring failed close on fd %d", tmpfd); - cmd->errfdptr = NULL; - cmd->errbuf = NULL; - VIR_FREE(errbuf); - } - - return ret; -} - - -/* - * Perform all virCommand-specific actions, along with the user hook. - */ -static int -virCommandHook(void *data) -{ - virCommandPtr cmd = data; - int res = 0; - - if (cmd->hook) { - VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque); - res = cmd->hook(cmd->opaque); - VIR_DEBUG("Done hook %d", res); - } - if (res == 0 && cmd->pwd) { - VIR_DEBUG("Running child in %s", cmd->pwd); - res = chdir(cmd->pwd); - if (res < 0) { - virReportSystemError(errno, - _("Unable to change to %s"), cmd->pwd); - } - } - if (cmd->handshake) { - char c = res < 0 ? '0' : '1'; - int rv; - VIR_DEBUG("Notifying parent for handshake start on %d", - cmd->handshakeWait[1]); - if (safewrite(cmd->handshakeWait[1], &c, sizeof(c)) != sizeof(c)) { - virReportSystemError(errno, "%s", - _("Unable to notify parent process")); - return -1; - } - - /* On failure we pass the error message back to parent, - * so they don't have to dig through stderr logs - */ - if (res < 0) { - virErrorPtr err = virGetLastError(); - const char *msg = err ? err->message : - _("Unknown failure during hook execution"); - size_t len = strlen(msg) + 1; - if (safewrite(cmd->handshakeWait[1], msg, len) != len) { - virReportSystemError(errno, "%s", - _("Unable to send error to parent")); - return -1; - } - return -1; - } - - VIR_DEBUG("Waiting on parent for handshake complete on %d", - cmd->handshakeNotify[0]); - if ((rv = saferead(cmd->handshakeNotify[0], &c, - sizeof(c))) != sizeof(c)) { - if (rv < 0) - virReportSystemError(errno, "%s", - _("Unable to wait on parent process")); - else - virReportSystemError(EIO, "%s", - _("libvirtd quit during handshake")); - return -1; - } - if (c != '1') { - virReportSystemError(EINVAL, - _("Unexpected confirm code '%c' from parent"), - c); - return -1; - } - VIR_FORCE_CLOSE(cmd->handshakeWait[1]); - VIR_FORCE_CLOSE(cmd->handshakeNotify[0]); - } - - VIR_DEBUG("Hook is done %d", res); - - return res; -} - - -/** - * virCommandRunAsync: - * @cmd: command to start - * @pid: optional variable to track child pid - * - * Run the command asynchronously - * Returns -1 on any error executing the - * command. Returns 0 if the command executed. - * - * There are two approaches to child process cleanup. - * 1. Use auto-cleanup, by passing NULL for pid. The child will be - * auto-reaped by virCommandFree, unless you reap it earlier via - * virCommandWait or virCommandAbort. Good for where cmd is in - * scope for the duration of the child process. - * 2. Use manual cleanup, by passing the address of a pid_t variable - * for pid. While cmd is still in scope, you may reap the child via - * virCommandWait or virCommandAbort. But after virCommandFree, if - * you have not yet reaped the child, then it continues to run until - * you call virProcessWait or virProcessAbort. - */ -int -virCommandRunAsync(virCommandPtr cmd, pid_t *pid) -{ - int ret; - char *str; - int i; - bool synchronous = false; - - if (!cmd || cmd->has_error == ENOMEM) { - virReportOOMError(); - return -1; - } - if (cmd->has_error) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return -1; - } - - synchronous = cmd->flags & VIR_EXEC_RUN_SYNC; - cmd->flags &= ~VIR_EXEC_RUN_SYNC; - - /* Buffer management can only be requested via virCommandRun. */ - if ((cmd->inbuf && cmd->infd == -1) || - (cmd->outbuf && cmd->outfdptr != &cmd->outfd) || - (cmd->errbuf && cmd->errfdptr != &cmd->errfd)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot mix string I/O with asynchronous command")); - return -1; - } - - if (cmd->pid != -1) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("command is already running as pid %lld"), - (long long) cmd->pid); - return -1; - } - - if (!synchronous && (cmd->flags & VIR_EXEC_DAEMON)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("daemonized command cannot use virCommandRunAsync")); - return -1; - } - if (cmd->pwd && (cmd->flags & VIR_EXEC_DAEMON)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("daemonized command cannot set working directory %s"), - cmd->pwd); - return -1; - } - if (cmd->pidfile && !(cmd->flags & VIR_EXEC_DAEMON)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("creation of pid file requires daemonized command")); - return -1; - } - - str = virCommandToString(cmd); - VIR_DEBUG("About to run %s", str ? str : cmd->args[0]); - VIR_FREE(str); - - ret = virExecWithHook((const char *const *)cmd->args, - (const char *const *)cmd->env, - cmd->preserve, - cmd->preserve_size, - &cmd->pid, - cmd->infd, - cmd->outfdptr, - cmd->errfdptr, - cmd->flags, - virCommandHook, - cmd, - cmd->pidfile, - cmd->capabilities); - - VIR_DEBUG("Command result %d, with PID %d", - ret, (int)cmd->pid); - - for (i = 0; i < cmd->transfer_size; i++) { - VIR_FORCE_CLOSE(cmd->transfer[i]); - } - cmd->transfer_size = 0; - VIR_FREE(cmd->transfer); - - if (ret == 0 && pid) - *pid = cmd->pid; - else - cmd->reap = true; - - return ret; -} - - -/** - * virCommandWait: - * @cmd: command to wait on - * @exitstatus: optional status collection - * - * Wait for the command previously started with virCommandRunAsync() - * to complete. Return -1 on any error waiting for - * completion. Returns 0 if the command - * finished with the exit status set. If @exitstatus is NULL, then the - * child must exit with status 0 for this to succeed. - */ -int -virCommandWait(virCommandPtr cmd, int *exitstatus) -{ - int ret; - int status = 0; - - if (!cmd ||cmd->has_error == ENOMEM) { - virReportOOMError(); - return -1; - } - if (cmd->has_error) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return -1; - } - - if (cmd->pid == -1) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("command is not yet running")); - return -1; - } - - /* If virProcessWait reaps pid but then returns failure because - * exitstatus was NULL, then a second virCommandWait would risk - * calling waitpid on an unrelated process. Besides, that error - * message is not as detailed as what we can provide. So, we - * guarantee that virProcessWait only fails due to failure to wait, - * and repeat the exitstatus check code ourselves. */ - ret = virProcessWait(cmd->pid, exitstatus ? exitstatus : &status); - if (ret == 0) { - cmd->pid = -1; - cmd->reap = false; - if (status) { - char *str = virCommandToString(cmd); - char *st = virProcessTranslateStatus(status); - bool haveErrMsg = cmd->errbuf && *cmd->errbuf && (*cmd->errbuf)[0]; - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Child process (%s) unexpected %s%s%s"), - str ? str : cmd->args[0], NULLSTR(st), - haveErrMsg ? ": " : "", - haveErrMsg ? *cmd->errbuf : ""); - VIR_FREE(str); - VIR_FREE(st); - return -1; - } - } - - return ret; -} - - -#ifndef WIN32 -/** - * virCommandAbort: - * @cmd: command to abort - * - * Abort an async command if it is running, without issuing - * any errors or affecting errno. Designed for error paths - * where some but not all paths to the cleanup code might - * have started the child process. - */ -void -virCommandAbort(virCommandPtr cmd) -{ - if (!cmd || cmd->pid == -1) - return; - virProcessAbort(cmd->pid); - cmd->pid = -1; - cmd->reap = false; -} -#else /* WIN32 */ -void -virCommandAbort(virCommandPtr cmd ATTRIBUTE_UNUSED) -{ - /* Mingw lacks WNOHANG and kill(). But since we haven't ported - * virExecWithHook to mingw yet, there's no process to be killed, - * making this implementation trivially correct for now :) */ -} -#endif - - -/** - * virCommandRequireHandshake: - * @cmd: command to modify - * - * Request that the child perform a handshake with - * the parent when the hook function has completed - * execution. The child will not exec() until the - * parent has notified - */ -void virCommandRequireHandshake(virCommandPtr cmd) -{ - if (!cmd || cmd->has_error) - return; - - if (cmd->handshake) { - cmd->has_error = -1; - VIR_DEBUG("Cannot require handshake twice"); - return; - } - - if (pipe2(cmd->handshakeWait, O_CLOEXEC) < 0) { - cmd->has_error = errno; - return; - } - if (pipe2(cmd->handshakeNotify, O_CLOEXEC) < 0) { - VIR_FORCE_CLOSE(cmd->handshakeWait[0]); - VIR_FORCE_CLOSE(cmd->handshakeWait[1]); - cmd->has_error = errno; - return; - } - - VIR_DEBUG("Transfer handshake wait=%d notify=%d, " - "keep handshake wait=%d notify=%d", - cmd->handshakeWait[1], cmd->handshakeNotify[0], - cmd->handshakeWait[0], cmd->handshakeNotify[1]); - virCommandTransferFD(cmd, cmd->handshakeWait[1]); - virCommandTransferFD(cmd, cmd->handshakeNotify[0]); - cmd->handshake = true; -} - -/** - * virCommandHandshakeWait: - * @cmd: command to wait on - * - * Wait for the child to complete execution of its - * hook function. To be called in the parent. - */ -int virCommandHandshakeWait(virCommandPtr cmd) -{ - char c; - int rv; - if (!cmd ||cmd->has_error == ENOMEM) { - virReportOOMError(); - return -1; - } - if (cmd->has_error || !cmd->handshake) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return -1; - } - - if (cmd->handshakeWait[0] == -1) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Handshake is already complete")); - return -1; - } - - VIR_DEBUG("Wait for handshake on %d", cmd->handshakeWait[0]); - if ((rv = saferead(cmd->handshakeWait[0], &c, sizeof(c))) != sizeof(c)) { - if (rv < 0) - virReportSystemError(errno, "%s", - _("Unable to wait for child process")); - else - virReportSystemError(EIO, "%s", - _("Child quit during startup handshake")); - VIR_FORCE_CLOSE(cmd->handshakeWait[0]); - return -1; - } - if (c != '1') { - char *msg; - ssize_t len; - if (VIR_ALLOC_N(msg, 1024) < 0) { - virReportOOMError(); - VIR_FORCE_CLOSE(cmd->handshakeWait[0]); - return -1; - } - /* Close the handshakeNotify fd before trying to read anything - * further on the handshakeWait pipe; so that a child waiting - * on our acknowledgment will die rather than deadlock. */ - VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); - - if ((len = saferead(cmd->handshakeWait[0], msg, 1024)) < 0) { - VIR_FORCE_CLOSE(cmd->handshakeWait[0]); - VIR_FREE(msg); - virReportSystemError(errno, "%s", - _("No error message from child failure")); - return -1; - } - VIR_FORCE_CLOSE(cmd->handshakeWait[0]); - msg[len-1] = '\0'; - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", msg); - VIR_FREE(msg); - return -1; - } - VIR_FORCE_CLOSE(cmd->handshakeWait[0]); - return 0; -} - -/** - * virCommandHandshakeNotify: - * @cmd: command to resume - * - * Notify the child that it is OK to exec() the - * real binary now. To be called in the parent. - */ -int virCommandHandshakeNotify(virCommandPtr cmd) -{ - char c = '1'; - if (!cmd ||cmd->has_error == ENOMEM) { - virReportOOMError(); - return -1; - } - if (cmd->has_error || !cmd->handshake) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid use of command API")); - return -1; - } - - if (cmd->handshakeNotify[1] == -1) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Handshake is already complete")); - return -1; - } - - VIR_DEBUG("Notify handshake on %d", cmd->handshakeNotify[1]); - if (safewrite(cmd->handshakeNotify[1], &c, sizeof(c)) != sizeof(c)) { - virReportSystemError(errno, "%s", _("Unable to notify child process")); - VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); - return -1; - } - VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); - return 0; -} - - -/** - * virCommandFree: - * @cmd: optional command to free - * - * Release all resources. The only exception is that if you called - * virCommandRunAsync with a non-null pid, then the asynchronous child - * is not reaped, and you must call virProcessWait() or virProcessAbort() yourself. - */ -void -virCommandFree(virCommandPtr cmd) -{ - int i; - if (!cmd) - return; - - for (i = 0; i < cmd->transfer_size; i++) { - VIR_FORCE_CLOSE(cmd->transfer[i]); - } - - VIR_FREE(cmd->inbuf); - VIR_FORCE_CLOSE(cmd->outfd); - VIR_FORCE_CLOSE(cmd->errfd); - - for (i = 0 ; i < cmd->nargs ; i++) - VIR_FREE(cmd->args[i]); - VIR_FREE(cmd->args); - - for (i = 0 ; i < cmd->nenv ; i++) - VIR_FREE(cmd->env[i]); - VIR_FREE(cmd->env); - - VIR_FREE(cmd->pwd); - - if (cmd->handshake) { - /* The other 2 fds in these arrays are closed - * due to use with virCommandTransferFD - */ - VIR_FORCE_CLOSE(cmd->handshakeWait[0]); - VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); - } - - VIR_FREE(cmd->pidfile); - - if (cmd->reap) - virCommandAbort(cmd); - - VIR_FREE(cmd->transfer); - VIR_FREE(cmd->preserve); - - VIR_FREE(cmd); -} diff --git a/src/util/command.h b/src/util/command.h deleted file mode 100644 index 6c8ab49..0000000 --- a/src/util/command.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * command.h: Child command execution - * - * Copyright (C) 2010-2011 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#ifndef __VIR_COMMAND_H__ -# define __VIR_COMMAND_H__ - -# include "internal.h" -# include "util.h" -# include "virbuffer.h" - -typedef struct _virCommand virCommand; -typedef virCommand *virCommandPtr; - -/* This will execute in the context of the first child - * after fork() but before execve(). As such, it is unsafe to - * call any function that is not async-signal-safe. */ -typedef int (*virExecHook)(void *data); - -int virFork(pid_t *pid) ATTRIBUTE_RETURN_CHECK; - -int virRun(const char *const*argv, int *status) ATTRIBUTE_RETURN_CHECK; - -virCommandPtr virCommandNew(const char *binary) ATTRIBUTE_NONNULL(1); - -virCommandPtr virCommandNewArgs(const char *const*args) ATTRIBUTE_NONNULL(1); - -virCommandPtr virCommandNewArgList(const char *binary, ...) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; - -virCommandPtr virCommandNewVAList(const char *binary, va_list list) - ATTRIBUTE_NONNULL(1); - -/* All error report from these setup APIs is - * delayed until the Run/RunAsync methods - */ - -void virCommandPreserveFD(virCommandPtr cmd, - int fd); - -void virCommandTransferFD(virCommandPtr cmd, - int fd); - -void virCommandSetPidFile(virCommandPtr cmd, - const char *pidfile) ATTRIBUTE_NONNULL(2); - -void virCommandClearCaps(virCommandPtr cmd); - -void virCommandAllowCap(virCommandPtr cmd, - int capability); - -void virCommandDaemonize(virCommandPtr cmd); - -void virCommandNonblockingFDs(virCommandPtr cmd); - -void virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...) - ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); - -void virCommandAddEnvPair(virCommandPtr cmd, - const char *name, - const char *value) ATTRIBUTE_NONNULL(2); - -void virCommandAddEnvString(virCommandPtr cmd, - const char *str) ATTRIBUTE_NONNULL(2); - -void virCommandAddEnvBuffer(virCommandPtr cmd, - virBufferPtr buf); - -void virCommandAddEnvPass(virCommandPtr cmd, - const char *name) ATTRIBUTE_NONNULL(2); - -void virCommandAddEnvPassCommon(virCommandPtr cmd); - -void virCommandAddArg(virCommandPtr cmd, - const char *val) ATTRIBUTE_NONNULL(2); - -void virCommandAddArgBuffer(virCommandPtr cmd, - virBufferPtr buf); - -void virCommandAddArgFormat(virCommandPtr cmd, - const char *format, ...) - ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); - -void virCommandAddArgPair(virCommandPtr cmd, - const char *name, - const char *val) - ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); - -void virCommandAddArgSet(virCommandPtr cmd, - const char *const*vals) ATTRIBUTE_NONNULL(2); - -void virCommandAddArgList(virCommandPtr cmd, - ... /* const char *arg, ..., NULL */) - ATTRIBUTE_SENTINEL; - -void virCommandSetWorkingDirectory(virCommandPtr cmd, - const char *pwd) ATTRIBUTE_NONNULL(2); - -void virCommandSetInputBuffer(virCommandPtr cmd, - const char *inbuf) ATTRIBUTE_NONNULL(2); - -void virCommandSetOutputBuffer(virCommandPtr cmd, - char **outbuf) ATTRIBUTE_NONNULL(2); - -void virCommandSetErrorBuffer(virCommandPtr cmd, - char **errbuf) ATTRIBUTE_NONNULL(2); - -void virCommandSetInputFD(virCommandPtr cmd, - int infd); - -void virCommandSetOutputFD(virCommandPtr cmd, - int *outfd) ATTRIBUTE_NONNULL(2); - -void virCommandSetErrorFD(virCommandPtr cmd, - int *errfd) ATTRIBUTE_NONNULL(2); - -void virCommandSetPreExecHook(virCommandPtr cmd, - virExecHook hook, - void *opaque) ATTRIBUTE_NONNULL(2); - -void virCommandWriteArgLog(virCommandPtr cmd, - int logfd); - -char *virCommandToString(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; - -int virCommandExec(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; - -int virCommandRun(virCommandPtr cmd, - int *exitstatus) ATTRIBUTE_RETURN_CHECK; - -int virCommandRunAsync(virCommandPtr cmd, - pid_t *pid) ATTRIBUTE_RETURN_CHECK; - -int virCommandWait(virCommandPtr cmd, - int *exitstatus) ATTRIBUTE_RETURN_CHECK; - -void virCommandRequireHandshake(virCommandPtr cmd); - -int virCommandHandshakeWait(virCommandPtr cmd) - ATTRIBUTE_RETURN_CHECK; - -int virCommandHandshakeNotify(virCommandPtr cmd) - ATTRIBUTE_RETURN_CHECK; - -void virCommandAbort(virCommandPtr cmd); - -void virCommandFree(virCommandPtr cmd); - -#endif /* __VIR_COMMAND_H__ */ diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c index 74593c8..6e9c9dd 100644 --- a/src/util/dnsmasq.c +++ b/src/util/dnsmasq.c @@ -42,7 +42,7 @@ #include "virbitmap.h" #include "dnsmasq.h" #include "util.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/src/util/ebtables.c b/src/util/ebtables.c index f1b2986..4b427ee 100644 --- a/src/util/ebtables.c +++ b/src/util/ebtables.c @@ -41,7 +41,7 @@ #include "internal.h" #include "ebtables.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/src/util/hooks.c b/src/util/hooks.c index 8817a4e..a6c056d 100644 --- a/src/util/hooks.c +++ b/src/util/hooks.c @@ -37,7 +37,7 @@ #include "memory.h" #include "virfile.h" #include "configmake.h" -#include "command.h" +#include "vircommand.h" #define VIR_FROM_THIS VIR_FROM_HOOK diff --git a/src/util/iptables.c b/src/util/iptables.c index 00a1c29..25253ff 100644 --- a/src/util/iptables.c +++ b/src/util/iptables.c @@ -39,7 +39,7 @@ #include "internal.h" #include "iptables.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/src/util/pci.c b/src/util/pci.c index 5971764..bf46fca 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -36,7 +36,7 @@ #include "logging.h" #include "memory.h" -#include "command.h" +#include "vircommand.h" #include "virterror_internal.h" #include "virfile.h" diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 3f85e0e..eebf59a 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -24,7 +24,6 @@ #include <config.h> #include "storage_file.h" -#include <command.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> @@ -41,6 +40,7 @@ #include "logging.h" #include "virfile.h" #include "c-ctype.h" +#include "vircommand.h" #include "virhash.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/util/sysinfo.c b/src/util/sysinfo.c index bac4b23..e21cbfd 100644 --- a/src/util/sysinfo.c +++ b/src/util/sysinfo.c @@ -35,7 +35,7 @@ #include "util.h" #include "logging.h" #include "memory.h" -#include "command.h" +#include "vircommand.h" #define VIR_FROM_THIS VIR_FROM_SYSINFO diff --git a/src/util/util.c b/src/util/util.c index 422ee75..f8ba7b4 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -84,7 +84,7 @@ #include "threads.h" #include "verify.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #include "nonblocking.h" #include "passfd.h" #include "virprocess.h" diff --git a/src/util/vircommand.c b/src/util/vircommand.c new file mode 100644 index 0000000..3046658 --- /dev/null +++ b/src/util/vircommand.c @@ -0,0 +1,2523 @@ +/* + * vircommand.c: Child command execution + * + * Copyright (C) 2010-2012 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <poll.h> +#include <signal.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <fcntl.h> + +#if HAVE_CAPNG +# include <cap-ng.h> +#endif + +#include "vircommand.h" +#include "memory.h" +#include "virterror_internal.h" +#include "util.h" +#include "logging.h" +#include "virfile.h" +#include "virpidfile.h" +#include "virprocess.h" +#include "virbuffer.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +/* Flags for virExecWithHook */ +enum { + VIR_EXEC_NONE = 0, + VIR_EXEC_NONBLOCK = (1 << 0), + VIR_EXEC_DAEMON = (1 << 1), + VIR_EXEC_CLEAR_CAPS = (1 << 2), + VIR_EXEC_RUN_SYNC = (1 << 3), +}; + +struct _virCommand { + int has_error; /* ENOMEM on allocation failure, -1 for anything else. */ + + char **args; + size_t nargs; + size_t maxargs; + + char **env; + size_t nenv; + size_t maxenv; + + char *pwd; + + int *preserve; /* FDs to pass to child. */ + int preserve_size; + int *transfer; /* FDs to close in parent. */ + int transfer_size; + + unsigned int flags; + + char *inbuf; + char **outbuf; + char **errbuf; + + int infd; + int outfd; + int errfd; + int *outfdptr; + int *errfdptr; + + bool handshake; + int handshakeWait[2]; + int handshakeNotify[2]; + + virExecHook hook; + void *opaque; + + pid_t pid; + char *pidfile; + bool reap; + + unsigned long long capabilities; +}; + +/* + * virCommandFDIsSet: + * @fd: FD to test + * @set: the set + * @set_size: actual size of @set + * + * Check if FD is already in @set or not. + * + * Returns true if @set contains @fd, + * false otherwise. + */ +static bool +virCommandFDIsSet(int fd, + const int *set, + int set_size) +{ + int i = 0; + + while (i < set_size) + if (set[i++] == fd) + return true; + + return false; +} + +/* + * virCommandFDSet: + * @fd: FD to be put into @set + * @set: the set + * @set_size: actual size of @set + * + * This is practically generalized implementation + * of FD_SET() as we do not want to be limited + * by FD_SETSIZE. + * + * Returns: 0 on success, + * -1 on usage error, + * ENOMEM on OOM + */ +static int +virCommandFDSet(int fd, + int **set, + int *set_size) +{ + if (fd < 0 || !set || !set_size) + return -1; + + if (virCommandFDIsSet(fd, *set, *set_size)) + return 0; + + if (VIR_REALLOC_N(*set, *set_size + 1) < 0) { + return ENOMEM; + } + + (*set)[*set_size] = fd; + (*set_size)++; + + return 0; +} + +#ifndef WIN32 + +static int virClearCapabilities(void) ATTRIBUTE_UNUSED; + +# if HAVE_CAPNG +static int virClearCapabilities(void) +{ + int ret; + + capng_clear(CAPNG_SELECT_BOTH); + + if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot clear process capabilities %d"), ret); + return -1; + } + + return 0; +} + +/** + * virSetCapabilities: + * @capabilities - capability flag to set. + * In case of 0, this function is identical to + * virClearCapabilities() + * + */ +static int virSetCapabilities(unsigned long long capabilities) +{ + int ret, i; + + capng_clear(CAPNG_SELECT_BOTH); + + for (i = 0; i <= CAP_LAST_CAP; i++) { + if (capabilities & (1ULL << i)) + capng_update(CAPNG_ADD, CAPNG_BOUNDING_SET, i); + } + + if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot apply process capabilities %d"), ret); + return -1; + } + + return 0; +} +# else +static int virClearCapabilities(void) +{ +// VIR_WARN("libcap-ng support not compiled in, unable to clear " +// "capabilities"); + return 0; +} + +static int +virSetCapabilities(unsigned long long capabilities ATTRIBUTE_UNUSED) +{ + return 0; +} +# endif + +/** + * virFork: + * @pid - a pointer to a pid_t that will receive the return value from + * fork() + * + * fork a new process while avoiding various race/deadlock conditions + * + * on return from virFork(), if *pid < 0, the fork failed and there is + * no new process. Otherwise, just like fork(), if *pid == 0, it is the + * child process returning, and if *pid > 0, it is the parent. + * + * Even if *pid >= 0, if the return value from virFork() is < 0, it + * indicates a failure that occurred in the parent or child process + * after the fork. In this case, the child process should call + * _exit(EXIT_FAILURE) after doing any additional error reporting. + */ +int +virFork(pid_t *pid) +{ + sigset_t oldmask, newmask; + struct sigaction sig_action; + int saved_errno, ret = -1; + + *pid = -1; + + /* + * 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) { + saved_errno = errno; + virReportSystemError(errno, + "%s", _("cannot block signals")); + goto cleanup; + } + + /* Ensure we hold the logging lock, to protect child processes + * from deadlocking on another thread's inherited mutex state */ + virLogLock(); + + *pid = fork(); + saved_errno = errno; /* save for caller */ + + /* Unlock for both parent and child process */ + virLogUnlock(); + + if (*pid < 0) { + /* attempt to restore signal mask, but ignore failure, to + avoid obscuring the fork failure */ + ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL)); + virReportSystemError(saved_errno, + "%s", _("cannot fork child process")); + goto cleanup; + } + + if (*pid) { + + /* parent process */ + + /* Restore our original signal mask now that the child is + safely running */ + if (pthread_sigmask(SIG_SETMASK, &oldmask, NULL) != 0) { + saved_errno = errno; /* save for caller */ + virReportSystemError(errno, "%s", _("cannot unblock signals")); + goto cleanup; + } + ret = 0; + + } else { + + /* child process */ + + int logprio; + int i; + + /* Remove any error callback so errors in child now + get sent to stderr where they stand a fighting chance + of being seen / logged */ + virSetErrorFunc(NULL, NULL); + virSetErrorLogPriorityFunc(NULL); + + /* Make sure any hook logging is sent to stderr, since child + * process may close the logfile FDs */ + logprio = virLogGetDefaultPriority(); + virLogReset(); + virLogSetDefaultPriority(logprio); + + /* 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) { + saved_errno = errno; /* save for caller */ + virReportSystemError(errno, "%s", _("cannot unblock signals")); + goto cleanup; + } + ret = 0; + } + +cleanup: + if (ret < 0) + errno = saved_errno; + return ret; +} + +/* + * Ensure that *null is an fd visiting /dev/null. Return 0 on + * success, -1 on failure. Allows for lazy opening of shared + * /dev/null fd only as required. + */ +static int +getDevNull(int *null) +{ + if (*null == -1 && (*null = open("/dev/null", O_RDWR|O_CLOEXEC)) < 0) { + virReportSystemError(errno, + _("cannot open %s"), + "/dev/null"); + return -1; + } + return 0; +} + +/* Ensure that STD is an inheritable copy of FD. Return 0 on success, + * -1 on failure. */ +static int +prepareStdFd(int fd, int std) +{ + if (fd == std) + return virSetInherit(fd, true); + if (dup2(fd, std) != std) + return -1; + return 0; +} + +/* + * @argv argv to exec + * @envp optional environment 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 + * @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) + * @capabilities capabilities to keep + */ +static int +virExecWithHook(const char *const*argv, + const char *const*envp, + const int *keepfd, + int keepfd_size, + pid_t *retpid, + int infd, int *outfd, int *errfd, + unsigned int flags, + virExecHook hook, + void *data, + char *pidfile, + unsigned long long capabilities) +{ + pid_t pid; + int null = -1, i, openmax; + int pipeout[2] = {-1,-1}; + int pipeerr[2] = {-1,-1}; + int childout = -1; + int childerr = -1; + int tmpfd; + const char *binary = NULL; + int forkRet; + + if (argv[0][0] != '/') { + if (!(binary = virFindFileInPath(argv[0]))) { + virReportSystemError(ENOENT, + _("Cannot find '%s' in path"), + argv[0]); + return -1; + } + } else { + binary = argv[0]; + } + + if (infd < 0) { + if (getDevNull(&null) < 0) + goto cleanup; + infd = null; + } + + if (outfd != NULL) { + if (*outfd == -1) { + if (pipe2(pipeout, O_CLOEXEC) < 0) { + virReportSystemError(errno, + "%s", _("cannot create pipe")); + goto cleanup; + } + + if ((flags & VIR_EXEC_NONBLOCK) && + virSetNonBlock(pipeout[0]) == -1) { + virReportSystemError(errno, + "%s", _("Failed to set non-blocking file descriptor flag")); + goto cleanup; + } + + childout = pipeout[1]; + } else { + childout = *outfd; + } + } else { + if (getDevNull(&null) < 0) + goto cleanup; + childout = null; + } + + if (errfd != NULL) { + if (errfd == outfd) { + childerr = childout; + } else if (*errfd == -1) { + if (pipe2(pipeerr, O_CLOEXEC) < 0) { + virReportSystemError(errno, + "%s", _("Failed to create pipe")); + goto cleanup; + } + + if ((flags & VIR_EXEC_NONBLOCK) && + virSetNonBlock(pipeerr[0]) == -1) { + virReportSystemError(errno, + "%s", _("Failed to set non-blocking file descriptor flag")); + goto cleanup; + } + + childerr = pipeerr[1]; + } else { + childerr = *errfd; + } + } else { + if (getDevNull(&null) < 0) + goto cleanup; + childerr = null; + } + + forkRet = virFork(&pid); + + if (pid < 0) { + goto cleanup; + } + + if (pid) { /* parent */ + if (forkRet < 0) { + goto cleanup; + } + + VIR_FORCE_CLOSE(null); + if (outfd && *outfd == -1) { + VIR_FORCE_CLOSE(pipeout[1]); + *outfd = pipeout[0]; + } + if (errfd && *errfd == -1) { + VIR_FORCE_CLOSE(pipeerr[1]); + *errfd = pipeerr[0]; + } + + *retpid = pid; + + if (binary != argv[0]) + VIR_FREE(binary); + + return 0; + } + + /* child */ + + if (forkRet < 0) { + /* The fork was successful, but after that there was an error + * in the child (which was already logged). + */ + goto fork_error; + } + + openmax = sysconf(_SC_OPEN_MAX); + for (i = 3; i < openmax; i++) { + if (i == infd || i == childout || i == childerr) + continue; + if (!keepfd || !virCommandFDIsSet(i, keepfd, keepfd_size)) { + tmpfd = i; + VIR_MASS_CLOSE(tmpfd); + } else if (virSetInherit(i, true) < 0) { + virReportSystemError(errno, _("failed to preserve fd %d"), i); + goto fork_error; + } + } + + if (prepareStdFd(infd, STDIN_FILENO) < 0) { + virReportSystemError(errno, + "%s", _("failed to setup stdin file handle")); + goto fork_error; + } + if (childout > 0 && prepareStdFd(childout, STDOUT_FILENO) < 0) { + virReportSystemError(errno, + "%s", _("failed to setup stdout file handle")); + goto fork_error; + } + if (childerr > 0 && prepareStdFd(childerr, STDERR_FILENO) < 0) { + virReportSystemError(errno, + "%s", _("failed to setup stderr file handle")); + goto fork_error; + } + + if (infd != STDIN_FILENO && infd != null && infd != childerr && + infd != childout) + VIR_FORCE_CLOSE(infd); + if (childout > STDERR_FILENO && childout != null && childout != childerr) + VIR_FORCE_CLOSE(childout); + if (childerr > STDERR_FILENO && childerr != null) + VIR_FORCE_CLOSE(childerr); + VIR_FORCE_CLOSE(null); + + /* Initialize full logging for a while */ + virLogSetFromEnv(); + + /* 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(errno, + "%s", _("cannot become session leader")); + goto fork_error; + } + + if (chdir("/") < 0) { + virReportSystemError(errno, + "%s", _("cannot change to root directory")); + goto fork_error; + } + + pid = fork(); + if (pid < 0) { + virReportSystemError(errno, + "%s", _("cannot fork child process")); + goto fork_error; + } + + if (pid > 0) { + if (pidfile && (virPidFileWritePath(pidfile,pid) < 0)) { + kill(pid, SIGTERM); + usleep(500*1000); + kill(pid, SIGTERM); + virReportSystemError(errno, + _("could not write pidfile %s for %d"), + pidfile, pid); + goto fork_error; + } + _exit(0); + } + } + + if (hook) { + /* virFork reset all signal handlers to the defaults. + * This is good for the child process, but our hook + * risks running something that generates SIGPIPE, + * so we need to temporarily block that again + */ + struct sigaction waxon, waxoff; + memset(&waxoff, 0, sizeof(waxoff)); + waxoff.sa_handler = SIG_IGN; + sigemptyset(&waxoff.sa_mask); + memset(&waxon, 0, sizeof(waxon)); + if (sigaction(SIGPIPE, &waxoff, &waxon) < 0) { + virReportSystemError(errno, "%s", + _("Could not disable SIGPIPE")); + goto fork_error; + } + + if ((hook)(data) != 0) { + VIR_DEBUG("Hook function failed."); + goto fork_error; + } + + if (sigaction(SIGPIPE, &waxon, NULL) < 0) { + virReportSystemError(errno, "%s", + _("Could not re-enable SIGPIPE")); + goto fork_error; + } + } + + /* The steps above may need todo something privileged, so + * we delay clearing capabilities until the last minute */ + if (capabilities || (flags & VIR_EXEC_CLEAR_CAPS)) + if (virSetCapabilities(capabilities) < 0) + goto fork_error; + + /* Close logging again to ensure no FDs leak to child */ + virLogReset(); + + if (envp) + execve(binary, (char **) argv, (char**)envp); + else + execv(binary, (char **) argv); + + virReportSystemError(errno, + _("cannot execute binary %s"), + argv[0]); + + fork_error: + virDispatchError(NULL); + _exit(EXIT_FAILURE); + + cleanup: + /* This is cleanup of parent process only - child + should never jump here on error */ + + if (binary != argv[0]) + VIR_FREE(binary); + + /* NB we don't virReportError() on any failures here + because the code which jumped here already raised + an error condition which we must not overwrite */ + VIR_FORCE_CLOSE(pipeerr[0]); + VIR_FORCE_CLOSE(pipeerr[1]); + VIR_FORCE_CLOSE(pipeout[0]); + VIR_FORCE_CLOSE(pipeout[1]); + VIR_FORCE_CLOSE(null); + return -1; +} + +/** + * virRun: + * @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(const char *const*argv, int *status) +{ + int ret; + virCommandPtr cmd = virCommandNewArgs(argv); + + ret = virCommandRun(cmd, status); + virCommandFree(cmd); + return ret; +} + +#else /* WIN32 */ + +int +virRun(const char *const *argv ATTRIBUTE_UNUSED, + int *status) +{ + if (status) + *status = ENOTSUP; + else + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virRun is not implemented for WIN32")); + return -1; +} + +static int +virExecWithHook(const char *const*argv ATTRIBUTE_UNUSED, + const char *const*envp ATTRIBUTE_UNUSED, + const int *keepfd ATTRIBUTE_UNUSED, + int keepfd_size ATTRIBUTE_UNUSED, + pid_t *retpid ATTRIBUTE_UNUSED, + int infd ATTRIBUTE_UNUSED, + int *outfd ATTRIBUTE_UNUSED, + int *errfd ATTRIBUTE_UNUSED, + int flags_unused ATTRIBUTE_UNUSED, + virExecHook hook ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED, + char *pidfile ATTRIBUTE_UNUSED, + unsigned long long capabilities ATTRIBUTE_UNUSED) +{ + /* XXX: Some day we can implement pieces of virCommand/virExec on + * top of _spawn() or CreateProcess(), but we can't implement + * everything, since mingw completely lacks fork(), so we cannot + * run hook code in the child. */ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virExec is not implemented for WIN32")); + return -1; +} + +int +virFork(pid_t *pid) +{ + *pid = -1; + errno = ENOTSUP; + + return -1; +} + +#endif /* WIN32 */ + + +/** + * virCommandNew: + * @binary: program to run + * + * Create a new command for named binary. If @binary is relative, + * it will be found via a PATH search of the parent's PATH (and not + * any altered PATH set by virCommandAddEnv* commands). + */ +virCommandPtr +virCommandNew(const char *binary) +{ + const char *const args[] = { binary, NULL }; + + return virCommandNewArgs(args); +} + +/** + * virCommandNewArgs: + * @args: array of arguments + * + * Create a new command with a NULL terminated + * set of args, taking binary from args[0]. More arguments can + * be added later. @args[0] is handled like @binary of virCommandNew. + */ +virCommandPtr +virCommandNewArgs(const char *const*args) +{ + virCommandPtr cmd; + + if (VIR_ALLOC(cmd) < 0) + return NULL; + + cmd->handshakeWait[0] = -1; + cmd->handshakeWait[1] = -1; + cmd->handshakeNotify[0] = -1; + cmd->handshakeNotify[1] = -1; + + cmd->infd = cmd->outfd = cmd->errfd = -1; + cmd->pid = -1; + + virCommandAddArgSet(cmd, args); + + return cmd; +} + +/** + * virCommandNewArgList: + * @binary: program to run + * @...: additional arguments + * + * Create a new command with a NULL terminated + * list of args, starting with the binary to run. More arguments can + * be added later. @binary is handled as in virCommandNew. + */ +virCommandPtr +virCommandNewArgList(const char *binary, ...) +{ + virCommandPtr cmd = virCommandNew(binary); + va_list list; + const char *arg; + + if (!cmd || cmd->has_error) + return cmd; + + va_start(list, binary); + while ((arg = va_arg(list, const char *)) != NULL) + virCommandAddArg(cmd, arg); + va_end(list); + return cmd; +} + +/** + * virCommandNewVAList: + * @binary: program to run + * @va_list: additional arguments + * + * Create a new command with a NULL terminated + * variable argument list. @binary is handled as in virCommandNew. + */ +virCommandPtr +virCommandNewVAList(const char *binary, va_list list) +{ + virCommandPtr cmd = virCommandNew(binary); + const char *arg; + + if (!cmd || cmd->has_error) + return cmd; + + while ((arg = va_arg(list, const char *)) != NULL) + virCommandAddArg(cmd, arg); + return cmd; +} + + +/* + * Preserve the specified file descriptor in the child, instead of + * closing it. FD must not be one of the three standard streams. If + * transfer is true, then fd will be closed in the parent after a call + * to Run/RunAsync/Free, otherwise caller is still responsible for fd. + * Returns true if a transferring caller should close FD now, and + * false if the transfer is successfully recorded. + */ +static bool +virCommandKeepFD(virCommandPtr cmd, int fd, bool transfer) +{ + int ret = 0; + + if (!cmd) + return fd > STDERR_FILENO; + + if (fd <= STDERR_FILENO || + (ret = virCommandFDSet(fd, &cmd->preserve, &cmd->preserve_size)) || + (transfer && (ret = virCommandFDSet(fd, &cmd->transfer, + &cmd->transfer_size)))) { + if (!cmd->has_error) + cmd->has_error = ret ? ret : -1 ; + VIR_DEBUG("cannot preserve %d", fd); + return fd > STDERR_FILENO; + } + + return false; +} + +/** + * virCommandPreserveFD: + * @cmd: the command to modify + * @fd: fd to mark for inheritance into child + * + * Preserve the specified file descriptor + * in the child, instead of closing it on exec. + * The parent is still responsible for managing fd. + */ +void +virCommandPreserveFD(virCommandPtr cmd, int fd) +{ + virCommandKeepFD(cmd, fd, false); +} + +/** + * virCommandTransferFD: + * @cmd: the command to modify + * @fd: fd to reassign to the child + * + * Transfer the specified file descriptor + * to the child, instead of closing it on exec. + * The parent should no longer use fd, and the parent's copy will + * be automatically closed no later than during Run/RunAsync/Free. + */ +void +virCommandTransferFD(virCommandPtr cmd, int fd) +{ + if (virCommandKeepFD(cmd, fd, true)) + VIR_FORCE_CLOSE(fd); +} + + +/** + * virCommandSetPidFile: + * @cmd: the command to modify + * @pidfile: filename to use + * + * Save the child PID in a pidfile. The pidfile will be populated + * before the exec of the child. + */ +void +virCommandSetPidFile(virCommandPtr cmd, const char *pidfile) +{ + if (!cmd || cmd->has_error) + return; + + VIR_FREE(cmd->pidfile); + if (!(cmd->pidfile = strdup(pidfile))) { + cmd->has_error = ENOMEM; + } +} + + +/** + * virCommandClearCaps: + * @cmd: the command to modify + * + * Remove all capabilities from the child, after any hooks have been run. + */ +void +virCommandClearCaps(virCommandPtr cmd) +{ + if (!cmd || cmd->has_error) + return; + + cmd->flags |= VIR_EXEC_CLEAR_CAPS; +} + +/** + * virCommandAllowCap: + * @cmd: the command to modify + * @capability: what to allow + * + * Allow specific capabilities + */ +void +virCommandAllowCap(virCommandPtr cmd, + int capability) +{ + if (!cmd || cmd->has_error) + return; + + cmd->capabilities |= (1ULL << capability); +} + + + +/** + * virCommandDaemonize: + * @cmd: the command to modify + * + * Daemonize the child process. The child will have a current working + * directory of /, and must be started with virCommandRun, which will + * complete as soon as the daemon grandchild has started. + */ +void +virCommandDaemonize(virCommandPtr cmd) +{ + if (!cmd || cmd->has_error) + return; + + cmd->flags |= VIR_EXEC_DAEMON; +} + +/** + * virCommandNonblockingFDs: + * @cmd: the command to modify + * + * Set FDs created by virCommandSetOutputFD and virCommandSetErrorFD + * as non-blocking in the parent. + */ +void +virCommandNonblockingFDs(virCommandPtr cmd) +{ + if (!cmd || cmd->has_error) + return; + + cmd->flags |= VIR_EXEC_NONBLOCK; +} + +/* Add an environment variable to the cmd->env list. 'env' is a + * string like "name=value". If the named environment variable is + * already set, then it is replaced in the list. + */ +static inline void +virCommandAddEnv(virCommandPtr cmd, char *env) +{ + size_t namelen; + size_t i; + + /* Search for the name in the existing environment. */ + namelen = strcspn(env, "="); + for (i = 0; i < cmd->nenv; ++i) { + /* + 1 because we want to match the '=' character too. */ + if (STREQLEN(cmd->env[i], env, namelen + 1)) { + VIR_FREE(cmd->env[i]); + cmd->env[i] = env; + return; + } + } + + /* Arg plus trailing NULL. */ + if (VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 1 + 1) < 0) { + VIR_FREE(env); + cmd->has_error = ENOMEM; + return; + } + + cmd->env[cmd->nenv++] = env; +} + +/** + * virCommandAddEnvFormat: + * @cmd: the command to modify + * @format: format of arguments, end result must be in name=value format + * @...: arguments to be formatted + * + * Add an environment variable to the child created by a printf-style format. + */ +void +virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...) +{ + char *env; + va_list list; + + if (!cmd || cmd->has_error) + return; + + va_start(list, format); + if (virVasprintf(&env, format, list) < 0) { + cmd->has_error = ENOMEM; + va_end(list); + return; + } + va_end(list); + + virCommandAddEnv(cmd, env); +} + +/** + * virCommandAddEnvPair: + * @cmd: the command to modify + * @name: variable name, must not contain = + * @value: value to assign to name + * + * Add an environment variable to the child + * using separate name & value strings + */ +void +virCommandAddEnvPair(virCommandPtr cmd, const char *name, const char *value) +{ + virCommandAddEnvFormat(cmd, "%s=%s", name, value); +} + + +/** + * virCommandAddEnvString: + * @cmd: the command to modify + * @str: name=value format + * + * Add an environment variable to the child + * using a preformatted env string FOO=BAR + */ +void +virCommandAddEnvString(virCommandPtr cmd, const char *str) +{ + char *env; + + if (!cmd || cmd->has_error) + return; + + if (!(env = strdup(str))) { + cmd->has_error = ENOMEM; + return; + } + + virCommandAddEnv(cmd, env); +} + + +/** + * virCommandAddEnvBuffer: + * @cmd: the command to modify + * @buf: buffer that contains name=value string, which will be reset on return + * + * Convert a buffer containing preformatted name=value into an + * environment variable of the child. + * Correctly transfers memory errors or contents from buf to cmd. + */ +void +virCommandAddEnvBuffer(virCommandPtr cmd, virBufferPtr buf) +{ + if (!cmd || cmd->has_error) { + virBufferFreeAndReset(buf); + return; + } + + if (virBufferError(buf)) { + cmd->has_error = ENOMEM; + virBufferFreeAndReset(buf); + return; + } + if (!virBufferUse(buf)) { + cmd->has_error = EINVAL; + return; + } + + virCommandAddEnv(cmd, virBufferContentAndReset(buf)); +} + + +/** + * virCommandAddEnvPass: + * @cmd: the command to modify + * @name: the name to look up in current environment + * + * Pass an environment variable to the child + * using current process' value + */ +void +virCommandAddEnvPass(virCommandPtr cmd, const char *name) +{ + char *value; + if (!cmd || cmd->has_error) + return; + + value = getenv(name); + if (value) + virCommandAddEnvPair(cmd, name, value); +} + + +/** + * virCommandAddEnvPassCommon: + * @cmd: the command to modify + * + * Set LC_ALL to C, and propagate other essential environment + * variables (such as PATH) from the parent process. + */ +void +virCommandAddEnvPassCommon(virCommandPtr cmd) +{ + if (!cmd || cmd->has_error) + return; + + /* Attempt to Pre-allocate; allocation failure will be detected + * later during virCommandAdd*. */ + ignore_value(VIR_RESIZE_N(cmd->env, cmd->maxenv, cmd->nenv, 9)); + + virCommandAddEnvPair(cmd, "LC_ALL", "C"); + + virCommandAddEnvPass(cmd, "LD_PRELOAD"); + virCommandAddEnvPass(cmd, "LD_LIBRARY_PATH"); + virCommandAddEnvPass(cmd, "PATH"); + virCommandAddEnvPass(cmd, "HOME"); + virCommandAddEnvPass(cmd, "USER"); + virCommandAddEnvPass(cmd, "LOGNAME"); + virCommandAddEnvPass(cmd, "TMPDIR"); +} + +/** + * virCommandAddArg: + * @cmd: the command to modify + * @val: the argument to add + * + * Add a command line argument to the child + */ +void +virCommandAddArg(virCommandPtr cmd, const char *val) +{ + char *arg; + + if (!cmd || cmd->has_error) + return; + + if (!(arg = strdup(val))) { + cmd->has_error = ENOMEM; + return; + } + + /* Arg plus trailing NULL. */ + if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) { + VIR_FREE(arg); + cmd->has_error = ENOMEM; + return; + } + + cmd->args[cmd->nargs++] = arg; +} + + +/** + * virCommandAddArgBuffer: + * @cmd: the command to modify + * @buf: buffer that contains argument string, which will be reset on return + * + * Convert a buffer into a command line argument to the child. + * Correctly transfers memory errors or contents from buf to cmd. + */ +void +virCommandAddArgBuffer(virCommandPtr cmd, virBufferPtr buf) +{ + if (!cmd || cmd->has_error) { + virBufferFreeAndReset(buf); + return; + } + + /* Arg plus trailing NULL. */ + if (virBufferError(buf) || + VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) { + cmd->has_error = ENOMEM; + virBufferFreeAndReset(buf); + return; + } + + cmd->args[cmd->nargs] = virBufferContentAndReset(buf); + if (!cmd->args[cmd->nargs]) + cmd->args[cmd->nargs] = strdup(""); + if (!cmd->args[cmd->nargs]) { + cmd->has_error = ENOMEM; + return; + } + cmd->nargs++; +} + + +/** + * virCommandAddArgFormat: + * @cmd: the command to modify + * @format: format of arguments, end result must be in name=value format + * @...: arguments to be formatted + * + * Add a command line argument created by a printf-style format. + */ +void +virCommandAddArgFormat(virCommandPtr cmd, const char *format, ...) +{ + char *arg; + va_list list; + + if (!cmd || cmd->has_error) + return; + + va_start(list, format); + if (virVasprintf(&arg, format, list) < 0) { + cmd->has_error = ENOMEM; + va_end(list); + return; + } + va_end(list); + + /* Arg plus trailing NULL. */ + if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, 1 + 1) < 0) { + VIR_FREE(arg); + cmd->has_error = ENOMEM; + return; + } + + cmd->args[cmd->nargs++] = arg; +} + +/** + * virCommandAddArgPair: + * @cmd: the command to modify + * @name: left half of argument + * @value: right half of argument + * + * Add "NAME=VAL" as a single command line argument to the child + */ +void +virCommandAddArgPair(virCommandPtr cmd, const char *name, const char *val) +{ + virCommandAddArgFormat(cmd, "%s=%s", name, val); +} + +/** + * virCommandAddArgSet: + * @cmd: the command to modify + * @vals: array of arguments to add + * + * Add a NULL terminated list of args + */ +void +virCommandAddArgSet(virCommandPtr cmd, const char *const*vals) +{ + int narg = 0; + + if (!cmd || cmd->has_error) + return; + + if (vals[0] == NULL) { + cmd->has_error = EINVAL; + return; + } + + while (vals[narg] != NULL) + narg++; + + /* narg plus trailing NULL. */ + if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) { + cmd->has_error = ENOMEM; + return; + } + + narg = 0; + while (vals[narg] != NULL) { + char *arg = strdup(vals[narg++]); + if (!arg) { + cmd->has_error = ENOMEM; + return; + } + cmd->args[cmd->nargs++] = arg; + } +} + +/** + * virCommandAddArgList: + * @cmd: the command to modify + * @...: list of arguments to add + * + * Add a NULL terminated list of args. + */ +void +virCommandAddArgList(virCommandPtr cmd, ...) +{ + va_list list; + int narg = 0; + + if (!cmd || cmd->has_error) + return; + + va_start(list, cmd); + while (va_arg(list, const char *) != NULL) + narg++; + va_end(list); + + /* narg plus trailing NULL. */ + if (VIR_RESIZE_N(cmd->args, cmd->maxargs, cmd->nargs, narg + 1) < 0) { + cmd->has_error = ENOMEM; + return; + } + + va_start(list, cmd); + while (1) { + char *arg = va_arg(list, char *); + if (!arg) + break; + arg = strdup(arg); + if (!arg) { + cmd->has_error = ENOMEM; + va_end(list); + return; + } + cmd->args[cmd->nargs++] = arg; + } + va_end(list); +} + +/** + * virCommandSetWorkingDirectory: + * @cmd: the command to modify + * @pwd: directory to use + * + * Set the working directory of a non-daemon child process, rather + * than the parent's working directory. Daemons automatically get / + * without using this call. + */ +void +virCommandSetWorkingDirectory(virCommandPtr cmd, const char *pwd) +{ + if (!cmd || cmd->has_error) + return; + + if (cmd->pwd) { + cmd->has_error = -1; + VIR_DEBUG("cannot set directory twice"); + } else { + cmd->pwd = strdup(pwd); + if (!cmd->pwd) + cmd->has_error = ENOMEM; + } +} + + +/** + * virCommandSetInputBuffer: + * @cmd: the command to modify + * @inbuf: string to feed to stdin + * + * Feed the child's stdin from a string buffer. This requires the use + * of virCommandRun(). + */ +void +virCommandSetInputBuffer(virCommandPtr cmd, const char *inbuf) +{ + if (!cmd || cmd->has_error) + return; + + if (cmd->infd != -1 || cmd->inbuf) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify input twice"); + return; + } + + cmd->inbuf = strdup(inbuf); + if (!cmd->inbuf) + cmd->has_error = ENOMEM; +} + + +/** + * virCommandSetOutputBuffer: + * @cmd: the command to modify + * @outbuf: address of variable to store malloced result buffer + * + * Capture the child's stdout to a string buffer. *outbuf is + * guaranteed to be allocated after successful virCommandRun or + * virCommandWait, and is best-effort allocated after failed + * virCommandRun; caller is responsible for freeing *outbuf. + * This requires the use of virCommandRun. + */ +void +virCommandSetOutputBuffer(virCommandPtr cmd, char **outbuf) +{ + *outbuf = NULL; + if (!cmd || cmd->has_error) + return; + + if (cmd->outfdptr) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify output twice"); + return; + } + + cmd->outbuf = outbuf; + cmd->outfdptr = &cmd->outfd; +} + + +/** + * virCommandSetErrorBuffer: + * @cmd: the command to modify + * @errbuf: address of variable to store malloced result buffer + * + * Capture the child's stderr to a string buffer. *errbuf is + * guaranteed to be allocated after successful virCommandRun or + * virCommandWait, and is best-effort allocated after failed + * virCommandRun; caller is responsible for freeing *errbuf. + * This requires the use of virCommandRun. It is possible to + * pass the same pointer as for virCommandSetOutputBuffer(), in + * which case the child process will interleave all output into + * a single string. + */ +void +virCommandSetErrorBuffer(virCommandPtr cmd, char **errbuf) +{ + *errbuf = NULL; + if (!cmd || cmd->has_error) + return; + + if (cmd->errfdptr) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify stderr twice"); + return; + } + + cmd->errbuf = errbuf; + cmd->errfdptr = &cmd->errfd; +} + + +/** + * virCommandSetInputFD: + * @cmd: the command to modify + * @infd: the descriptor to use + * + * Attach a file descriptor to the child's stdin + */ +void +virCommandSetInputFD(virCommandPtr cmd, int infd) +{ + if (!cmd || cmd->has_error) + return; + + if (cmd->infd != -1 || cmd->inbuf) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify input twice"); + return; + } + if (infd < 0) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify invalid input fd"); + return; + } + + cmd->infd = infd; +} + + +/** + * virCommandSetOutputFD: + * @cmd: the command to modify + * @outfd: location of output fd + * + * Attach a file descriptor to the child's stdout. If *@outfd is -1 on + * entry, then a pipe will be created and returned in this variable when + * the child is run. Otherwise, *@outfd is used as the output. + */ +void +virCommandSetOutputFD(virCommandPtr cmd, int *outfd) +{ + if (!cmd || cmd->has_error) + return; + + if (cmd->outfdptr) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify output twice"); + return; + } + + cmd->outfdptr = outfd; +} + + +/** + * virCommandSetErrorFD: + * @cmd: the command to modify + * @errfd: location of error fd + * + * Attach a file descriptor to the child's stderr. If *@errfd is -1 on + * entry, then a pipe will be created and returned in this variable when + * the child is run. Otherwise, *@errfd is used for error collection, + * and may be the same as outfd given to virCommandSetOutputFD(). + */ +void +virCommandSetErrorFD(virCommandPtr cmd, int *errfd) +{ + if (!cmd || cmd->has_error) + return; + + if (cmd->errfdptr) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify stderr twice"); + return; + } + + cmd->errfdptr = errfd; +} + + +/** + * virCommandSetPreExecHook: + * @cmd: the command to modify + * @hook: the hook to run + * @opaque: argument to pass to the hook + * + * Run HOOK(OPAQUE) in the child as the last thing before changing + * directories, dropping capabilities, and executing the new process. + * Force the child to fail if HOOK does not return zero. + * + * Since @hook runs in the child, it should be careful to avoid + * any functions that are not async-signal-safe. + */ +void +virCommandSetPreExecHook(virCommandPtr cmd, virExecHook hook, void *opaque) +{ + if (!cmd || cmd->has_error) + return; + + if (cmd->hook) { + cmd->has_error = -1; + VIR_DEBUG("cannot specify hook twice"); + return; + } + cmd->hook = hook; + cmd->opaque = opaque; +} + + +/** + * virCommandWriteArgLog: + * @cmd: the command to log + * @logfd: where to log the results + * + * Call after adding all arguments and environment settings, but before + * Run/RunAsync, to immediately output the environment and arguments of + * cmd to logfd. If virCommandRun cannot succeed (because of an + * out-of-memory condition while building cmd), nothing will be logged. + */ +void +virCommandWriteArgLog(virCommandPtr cmd, int logfd) +{ + int ioError = 0; + size_t i; + + /* Any errors will be reported later by virCommandRun, which means + * no command will be run, so there is nothing to log. */ + if (!cmd || cmd->has_error) + return; + + for (i = 0 ; i < cmd->nenv ; i++) { + if (safewrite(logfd, cmd->env[i], strlen(cmd->env[i])) < 0) + ioError = errno; + if (safewrite(logfd, " ", 1) < 0) + ioError = errno; + } + for (i = 0 ; i < cmd->nargs ; i++) { + if (safewrite(logfd, cmd->args[i], strlen(cmd->args[i])) < 0) + ioError = errno; + if (safewrite(logfd, i == cmd->nargs - 1 ? "\n" : " ", 1) < 0) + ioError = errno; + } + + if (ioError) { + char ebuf[1024]; + VIR_WARN("Unable to write command %s args to logfile: %s", + cmd->args[0], virStrerror(ioError, ebuf, sizeof(ebuf))); + } +} + + +/** + * virCommandToString: + * @cmd: the command to convert + * + * Call after adding all arguments and environment settings, but + * before Run/RunAsync, to return a string representation of the + * environment and arguments of cmd, suitably quoted for pasting into + * a shell. If virCommandRun cannot succeed (because of an + * out-of-memory condition while building cmd), NULL will be returned. + * Caller is responsible for freeing the resulting string. + */ +char * +virCommandToString(virCommandPtr cmd) +{ + size_t i; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + /* Cannot assume virCommandRun will be called; so report the error + * now. If virCommandRun is called, it will report the same error. */ + if (!cmd ||cmd->has_error == ENOMEM) { + virReportOOMError(); + return NULL; + } + if (cmd->has_error) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return NULL; + } + + for (i = 0; i < cmd->nenv; i++) { + /* In shell, a='b c' has a different meaning than 'a=b c', so + * we must determine where the '=' lives. */ + char *eq = strchr(cmd->env[i], '='); + + if (!eq) { + virBufferFreeAndReset(&buf); + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return NULL; + } + eq++; + virBufferAdd(&buf, cmd->env[i], eq - cmd->env[i]); + virBufferEscapeShell(&buf, eq); + virBufferAddChar(&buf, ' '); + } + virBufferEscapeShell(&buf, cmd->args[0]); + for (i = 1; i < cmd->nargs; i++) { + virBufferAddChar(&buf, ' '); + virBufferEscapeShell(&buf, cmd->args[i]); + } + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return NULL; + } + + return virBufferContentAndReset(&buf); +} + + +/* + * Manage input and output to the child process. + */ +static int +virCommandProcessIO(virCommandPtr cmd, int *inpipe) +{ + int infd = -1, outfd = -1, errfd = -1; + size_t inlen = 0, outlen = 0, errlen = 0; + size_t inoff = 0; + int ret = 0; + + /* With an input buffer, feed data to child + * via pipe */ + if (cmd->inbuf) { + inlen = strlen(cmd->inbuf); + infd = *inpipe; + } + + /* With out/err buffer, the outfd/errfd have been filled with an + * FD for us. Guarantee an allocated string with partial results + * even if we encounter a later failure, as well as freeing any + * results accumulated over a prior run of the same command. */ + if (cmd->outbuf) { + outfd = cmd->outfd; + if (VIR_REALLOC_N(*cmd->outbuf, 1) < 0) { + virReportOOMError(); + ret = -1; + } + } + if (cmd->errbuf) { + errfd = cmd->errfd; + if (VIR_REALLOC_N(*cmd->errbuf, 1) < 0) { + virReportOOMError(); + ret = -1; + } + } + if (ret == -1) + goto cleanup; + ret = -1; + + for (;;) { + int i; + struct pollfd fds[3]; + int nfds = 0; + + if (infd != -1) { + fds[nfds].fd = infd; + fds[nfds].events = POLLOUT; + fds[nfds].revents = 0; + nfds++; + } + if (outfd != -1) { + fds[nfds].fd = outfd; + fds[nfds].events = POLLIN; + fds[nfds].revents = 0; + nfds++; + } + if (errfd != -1) { + fds[nfds].fd = errfd; + fds[nfds].events = POLLIN; + fds[nfds].revents = 0; + nfds++; + } + + if (nfds == 0) + break; + + if (poll(fds, nfds, -1) < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + virReportSystemError(errno, "%s", + _("unable to poll on child")); + goto cleanup; + } + + for (i = 0; i < nfds ; i++) { + if (fds[i].revents & (POLLIN | POLLHUP | POLLERR) && + (fds[i].fd == errfd || fds[i].fd == outfd)) { + char data[1024]; + char **buf; + size_t *len; + int done; + if (fds[i].fd == outfd) { + buf = cmd->outbuf; + len = &outlen; + } else { + buf = cmd->errbuf; + len = &errlen; + } + /* Silence a false positive from clang. */ + sa_assert(buf); + + done = read(fds[i].fd, data, sizeof(data)); + if (done < 0) { + if (errno != EINTR && + errno != EAGAIN) { + virReportSystemError(errno, "%s", + (fds[i].fd == outfd) ? + _("unable to read child stdout") : + _("unable to read child stderr")); + goto cleanup; + } + } else if (done == 0) { + if (fds[i].fd == outfd) + outfd = -1; + else + errfd = -1; + } else { + if (VIR_REALLOC_N(*buf, *len + done + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + memcpy(*buf + *len, data, done); + *len += done; + } + } + + if (fds[i].revents & (POLLOUT | POLLERR) && + fds[i].fd == infd) { + int done; + + /* Coverity 5.3.0 can't see that we only get here if + * infd is in the set because it was non-negative. */ + sa_assert(infd != -1); + done = write(infd, cmd->inbuf + inoff, + inlen - inoff); + if (done < 0) { + if (errno == EPIPE) { + VIR_DEBUG("child closed stdin early, ignoring EPIPE " + "on fd %d", infd); + if (VIR_CLOSE(*inpipe) < 0) + VIR_DEBUG("ignoring failed close on fd %d", infd); + infd = -1; + } else if (errno != EINTR && errno != EAGAIN) { + virReportSystemError(errno, "%s", + _("unable to write to child input")); + goto cleanup; + } + } else { + inoff += done; + if (inoff == inlen) { + if (VIR_CLOSE(*inpipe) < 0) + VIR_DEBUG("ignoring failed close on fd %d", infd); + infd = -1; + } + } + } + } + } + + ret = 0; +cleanup: + if (cmd->outbuf && *cmd->outbuf) + (*cmd->outbuf)[outlen] = '\0'; + if (cmd->errbuf && *cmd->errbuf) + (*cmd->errbuf)[errlen] = '\0'; + return ret; +} + +/** + * virCommandExec: + * @cmd: command to run + * + * Exec the command, replacing the current process. Meant to be called + * in the hook after already forking / cloning, so does not attempt to + * daemonize or preserve any FDs. + * + * Returns -1 on any error executing the command. + * Will not return on success. + */ +#ifndef WIN32 +int virCommandExec(virCommandPtr cmd) +{ + if (!cmd ||cmd->has_error == ENOMEM) { + virReportOOMError(); + return -1; + } + if (cmd->has_error) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return -1; + } + + return execve(cmd->args[0], cmd->args, cmd->env); +} +#else +int virCommandExec(virCommandPtr cmd ATTRIBUTE_UNUSED) +{ + /* Mingw execve() has a broken signature. Disable this + * function until gnulib fixes the signature, since we + * don't really need this on Win32 anyway. + */ + virReportSystemError(ENOSYS, "%s", + _("Executing new processes is not supported on Win32 platform")); + return -1; +} +#endif + +/** + * virCommandRun: + * @cmd: command to run + * @exitstatus: optional status collection + * + * Run the command and wait for completion. + * Returns -1 on any error executing the + * command. Returns 0 if the command executed, + * with the exit status set. If @exitstatus is NULL, then the + * child must exit with status 0 for this to succeed. + */ +int +virCommandRun(virCommandPtr cmd, int *exitstatus) +{ + int ret = 0; + char *outbuf = NULL; + char *errbuf = NULL; + int infd[2] = { -1, -1 }; + struct stat st; + bool string_io; + bool async_io = false; + char *str; + int tmpfd; + + if (!cmd ||cmd->has_error == ENOMEM) { + virReportOOMError(); + return -1; + } + if (cmd->has_error) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return -1; + } + + /* Avoid deadlock, by requiring that any open fd not under our + * control must be visiting a regular file, or that we are + * daemonized and no string io is required. */ + string_io = cmd->inbuf || cmd->outbuf || cmd->errbuf; + if (cmd->infd != -1 && + (fstat(cmd->infd, &st) < 0 || !S_ISREG(st.st_mode))) + async_io = true; + if (cmd->outfdptr && cmd->outfdptr != &cmd->outfd && + (*cmd->outfdptr == -1 || + fstat(*cmd->outfdptr, &st) < 0 || !S_ISREG(st.st_mode))) + async_io = true; + if (cmd->errfdptr && cmd->errfdptr != &cmd->errfd && + (*cmd->errfdptr == -1 || + fstat(*cmd->errfdptr, &st) < 0 || !S_ISREG(st.st_mode))) + async_io = true; + if (async_io) { + if (!(cmd->flags & VIR_EXEC_DAEMON) || string_io) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot mix caller fds with blocking execution")); + return -1; + } + } else { + if ((cmd->flags & VIR_EXEC_DAEMON) && string_io) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot mix string I/O with daemon")); + return -1; + } + } + + /* If we have an input buffer, we need + * a pipe to feed the data to the child */ + if (cmd->inbuf) { + if (pipe2(infd, O_CLOEXEC) < 0) { + virReportSystemError(errno, "%s", + _("unable to open pipe")); + cmd->has_error = -1; + return -1; + } + cmd->infd = infd[0]; + } + + /* If caller requested the same string for stdout and stderr, then + * merge those into one string. */ + if (cmd->outbuf && cmd->outbuf == cmd->errbuf) { + cmd->errfdptr = &cmd->outfd; + cmd->errbuf = NULL; + } + + /* If caller hasn't requested capture of stdout/err, then capture + * it ourselves so we can log it. But the intermediate child for + * a daemon has no expected output, and we don't want our + * capturing pipes passed on to the daemon grandchild. + */ + if (!(cmd->flags & VIR_EXEC_DAEMON)) { + if (!cmd->outfdptr) { + cmd->outfdptr = &cmd->outfd; + cmd->outbuf = &outbuf; + string_io = true; + } + if (!cmd->errfdptr) { + cmd->errfdptr = &cmd->errfd; + cmd->errbuf = &errbuf; + string_io = true; + } + } + + cmd->flags |= VIR_EXEC_RUN_SYNC; + if (virCommandRunAsync(cmd, NULL) < 0) { + if (cmd->inbuf) { + tmpfd = infd[0]; + if (VIR_CLOSE(infd[0]) < 0) + VIR_DEBUG("ignoring failed close on fd %d", tmpfd); + tmpfd = infd[1]; + if (VIR_CLOSE(infd[1]) < 0) + VIR_DEBUG("ignoring failed close on fd %d", tmpfd); + } + cmd->has_error = -1; + return -1; + } + + tmpfd = infd[0]; + if (VIR_CLOSE(infd[0]) < 0) + VIR_DEBUG("ignoring failed close on fd %d", tmpfd); + if (string_io) + ret = virCommandProcessIO(cmd, &infd[1]); + + if (virCommandWait(cmd, exitstatus) < 0) + ret = -1; + + str = (exitstatus ? virProcessTranslateStatus(*exitstatus) + : (char *) "status 0"); + VIR_DEBUG("Result %s, stdout: '%s' stderr: '%s'", + NULLSTR(str), + cmd->outbuf ? NULLSTR(*cmd->outbuf) : "(null)", + cmd->errbuf ? NULLSTR(*cmd->errbuf) : "(null)"); + if (exitstatus) + VIR_FREE(str); + + /* Reset any capturing, in case caller runs + * this identical command again */ + if (cmd->inbuf) { + tmpfd = infd[1]; + if (VIR_CLOSE(infd[1]) < 0) + VIR_DEBUG("ignoring failed close on fd %d", tmpfd); + } + if (cmd->outbuf == &outbuf) { + tmpfd = cmd->outfd; + if (VIR_CLOSE(cmd->outfd) < 0) + VIR_DEBUG("ignoring failed close on fd %d", tmpfd); + cmd->outfdptr = NULL; + cmd->outbuf = NULL; + VIR_FREE(outbuf); + } + if (cmd->errbuf == &errbuf) { + tmpfd = cmd->errfd; + if (VIR_CLOSE(cmd->errfd) < 0) + VIR_DEBUG("ignoring failed close on fd %d", tmpfd); + cmd->errfdptr = NULL; + cmd->errbuf = NULL; + VIR_FREE(errbuf); + } + + return ret; +} + + +/* + * Perform all virCommand-specific actions, along with the user hook. + */ +static int +virCommandHook(void *data) +{ + virCommandPtr cmd = data; + int res = 0; + + if (cmd->hook) { + VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque); + res = cmd->hook(cmd->opaque); + VIR_DEBUG("Done hook %d", res); + } + if (res == 0 && cmd->pwd) { + VIR_DEBUG("Running child in %s", cmd->pwd); + res = chdir(cmd->pwd); + if (res < 0) { + virReportSystemError(errno, + _("Unable to change to %s"), cmd->pwd); + } + } + if (cmd->handshake) { + char c = res < 0 ? '0' : '1'; + int rv; + VIR_DEBUG("Notifying parent for handshake start on %d", + cmd->handshakeWait[1]); + if (safewrite(cmd->handshakeWait[1], &c, sizeof(c)) != sizeof(c)) { + virReportSystemError(errno, "%s", + _("Unable to notify parent process")); + return -1; + } + + /* On failure we pass the error message back to parent, + * so they don't have to dig through stderr logs + */ + if (res < 0) { + virErrorPtr err = virGetLastError(); + const char *msg = err ? err->message : + _("Unknown failure during hook execution"); + size_t len = strlen(msg) + 1; + if (safewrite(cmd->handshakeWait[1], msg, len) != len) { + virReportSystemError(errno, "%s", + _("Unable to send error to parent")); + return -1; + } + return -1; + } + + VIR_DEBUG("Waiting on parent for handshake complete on %d", + cmd->handshakeNotify[0]); + if ((rv = saferead(cmd->handshakeNotify[0], &c, + sizeof(c))) != sizeof(c)) { + if (rv < 0) + virReportSystemError(errno, "%s", + _("Unable to wait on parent process")); + else + virReportSystemError(EIO, "%s", + _("libvirtd quit during handshake")); + return -1; + } + if (c != '1') { + virReportSystemError(EINVAL, + _("Unexpected confirm code '%c' from parent"), + c); + return -1; + } + VIR_FORCE_CLOSE(cmd->handshakeWait[1]); + VIR_FORCE_CLOSE(cmd->handshakeNotify[0]); + } + + VIR_DEBUG("Hook is done %d", res); + + return res; +} + + +/** + * virCommandRunAsync: + * @cmd: command to start + * @pid: optional variable to track child pid + * + * Run the command asynchronously + * Returns -1 on any error executing the + * command. Returns 0 if the command executed. + * + * There are two approaches to child process cleanup. + * 1. Use auto-cleanup, by passing NULL for pid. The child will be + * auto-reaped by virCommandFree, unless you reap it earlier via + * virCommandWait or virCommandAbort. Good for where cmd is in + * scope for the duration of the child process. + * 2. Use manual cleanup, by passing the address of a pid_t variable + * for pid. While cmd is still in scope, you may reap the child via + * virCommandWait or virCommandAbort. But after virCommandFree, if + * you have not yet reaped the child, then it continues to run until + * you call virProcessWait or virProcessAbort. + */ +int +virCommandRunAsync(virCommandPtr cmd, pid_t *pid) +{ + int ret; + char *str; + int i; + bool synchronous = false; + + if (!cmd || cmd->has_error == ENOMEM) { + virReportOOMError(); + return -1; + } + if (cmd->has_error) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return -1; + } + + synchronous = cmd->flags & VIR_EXEC_RUN_SYNC; + cmd->flags &= ~VIR_EXEC_RUN_SYNC; + + /* Buffer management can only be requested via virCommandRun. */ + if ((cmd->inbuf && cmd->infd == -1) || + (cmd->outbuf && cmd->outfdptr != &cmd->outfd) || + (cmd->errbuf && cmd->errfdptr != &cmd->errfd)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot mix string I/O with asynchronous command")); + return -1; + } + + if (cmd->pid != -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("command is already running as pid %lld"), + (long long) cmd->pid); + return -1; + } + + if (!synchronous && (cmd->flags & VIR_EXEC_DAEMON)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("daemonized command cannot use virCommandRunAsync")); + return -1; + } + if (cmd->pwd && (cmd->flags & VIR_EXEC_DAEMON)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("daemonized command cannot set working directory %s"), + cmd->pwd); + return -1; + } + if (cmd->pidfile && !(cmd->flags & VIR_EXEC_DAEMON)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("creation of pid file requires daemonized command")); + return -1; + } + + str = virCommandToString(cmd); + VIR_DEBUG("About to run %s", str ? str : cmd->args[0]); + VIR_FREE(str); + + ret = virExecWithHook((const char *const *)cmd->args, + (const char *const *)cmd->env, + cmd->preserve, + cmd->preserve_size, + &cmd->pid, + cmd->infd, + cmd->outfdptr, + cmd->errfdptr, + cmd->flags, + virCommandHook, + cmd, + cmd->pidfile, + cmd->capabilities); + + VIR_DEBUG("Command result %d, with PID %d", + ret, (int)cmd->pid); + + for (i = 0; i < cmd->transfer_size; i++) { + VIR_FORCE_CLOSE(cmd->transfer[i]); + } + cmd->transfer_size = 0; + VIR_FREE(cmd->transfer); + + if (ret == 0 && pid) + *pid = cmd->pid; + else + cmd->reap = true; + + return ret; +} + + +/** + * virCommandWait: + * @cmd: command to wait on + * @exitstatus: optional status collection + * + * Wait for the command previously started with virCommandRunAsync() + * to complete. Return -1 on any error waiting for + * completion. Returns 0 if the command + * finished with the exit status set. If @exitstatus is NULL, then the + * child must exit with status 0 for this to succeed. + */ +int +virCommandWait(virCommandPtr cmd, int *exitstatus) +{ + int ret; + int status = 0; + + if (!cmd ||cmd->has_error == ENOMEM) { + virReportOOMError(); + return -1; + } + if (cmd->has_error) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return -1; + } + + if (cmd->pid == -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("command is not yet running")); + return -1; + } + + /* If virProcessWait reaps pid but then returns failure because + * exitstatus was NULL, then a second virCommandWait would risk + * calling waitpid on an unrelated process. Besides, that error + * message is not as detailed as what we can provide. So, we + * guarantee that virProcessWait only fails due to failure to wait, + * and repeat the exitstatus check code ourselves. */ + ret = virProcessWait(cmd->pid, exitstatus ? exitstatus : &status); + if (ret == 0) { + cmd->pid = -1; + cmd->reap = false; + if (status) { + char *str = virCommandToString(cmd); + char *st = virProcessTranslateStatus(status); + bool haveErrMsg = cmd->errbuf && *cmd->errbuf && (*cmd->errbuf)[0]; + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Child process (%s) unexpected %s%s%s"), + str ? str : cmd->args[0], NULLSTR(st), + haveErrMsg ? ": " : "", + haveErrMsg ? *cmd->errbuf : ""); + VIR_FREE(str); + VIR_FREE(st); + return -1; + } + } + + return ret; +} + + +#ifndef WIN32 +/** + * virCommandAbort: + * @cmd: command to abort + * + * Abort an async command if it is running, without issuing + * any errors or affecting errno. Designed for error paths + * where some but not all paths to the cleanup code might + * have started the child process. + */ +void +virCommandAbort(virCommandPtr cmd) +{ + if (!cmd || cmd->pid == -1) + return; + virProcessAbort(cmd->pid); + cmd->pid = -1; + cmd->reap = false; +} +#else /* WIN32 */ +void +virCommandAbort(virCommandPtr cmd ATTRIBUTE_UNUSED) +{ + /* Mingw lacks WNOHANG and kill(). But since we haven't ported + * virExecWithHook to mingw yet, there's no process to be killed, + * making this implementation trivially correct for now :) */ +} +#endif + + +/** + * virCommandRequireHandshake: + * @cmd: command to modify + * + * Request that the child perform a handshake with + * the parent when the hook function has completed + * execution. The child will not exec() until the + * parent has notified + */ +void virCommandRequireHandshake(virCommandPtr cmd) +{ + if (!cmd || cmd->has_error) + return; + + if (cmd->handshake) { + cmd->has_error = -1; + VIR_DEBUG("Cannot require handshake twice"); + return; + } + + if (pipe2(cmd->handshakeWait, O_CLOEXEC) < 0) { + cmd->has_error = errno; + return; + } + if (pipe2(cmd->handshakeNotify, O_CLOEXEC) < 0) { + VIR_FORCE_CLOSE(cmd->handshakeWait[0]); + VIR_FORCE_CLOSE(cmd->handshakeWait[1]); + cmd->has_error = errno; + return; + } + + VIR_DEBUG("Transfer handshake wait=%d notify=%d, " + "keep handshake wait=%d notify=%d", + cmd->handshakeWait[1], cmd->handshakeNotify[0], + cmd->handshakeWait[0], cmd->handshakeNotify[1]); + virCommandTransferFD(cmd, cmd->handshakeWait[1]); + virCommandTransferFD(cmd, cmd->handshakeNotify[0]); + cmd->handshake = true; +} + +/** + * virCommandHandshakeWait: + * @cmd: command to wait on + * + * Wait for the child to complete execution of its + * hook function. To be called in the parent. + */ +int virCommandHandshakeWait(virCommandPtr cmd) +{ + char c; + int rv; + if (!cmd ||cmd->has_error == ENOMEM) { + virReportOOMError(); + return -1; + } + if (cmd->has_error || !cmd->handshake) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return -1; + } + + if (cmd->handshakeWait[0] == -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Handshake is already complete")); + return -1; + } + + VIR_DEBUG("Wait for handshake on %d", cmd->handshakeWait[0]); + if ((rv = saferead(cmd->handshakeWait[0], &c, sizeof(c))) != sizeof(c)) { + if (rv < 0) + virReportSystemError(errno, "%s", + _("Unable to wait for child process")); + else + virReportSystemError(EIO, "%s", + _("Child quit during startup handshake")); + VIR_FORCE_CLOSE(cmd->handshakeWait[0]); + return -1; + } + if (c != '1') { + char *msg; + ssize_t len; + if (VIR_ALLOC_N(msg, 1024) < 0) { + virReportOOMError(); + VIR_FORCE_CLOSE(cmd->handshakeWait[0]); + return -1; + } + /* Close the handshakeNotify fd before trying to read anything + * further on the handshakeWait pipe; so that a child waiting + * on our acknowledgment will die rather than deadlock. */ + VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); + + if ((len = saferead(cmd->handshakeWait[0], msg, 1024)) < 0) { + VIR_FORCE_CLOSE(cmd->handshakeWait[0]); + VIR_FREE(msg); + virReportSystemError(errno, "%s", + _("No error message from child failure")); + return -1; + } + VIR_FORCE_CLOSE(cmd->handshakeWait[0]); + msg[len-1] = '\0'; + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", msg); + VIR_FREE(msg); + return -1; + } + VIR_FORCE_CLOSE(cmd->handshakeWait[0]); + return 0; +} + +/** + * virCommandHandshakeNotify: + * @cmd: command to resume + * + * Notify the child that it is OK to exec() the + * real binary now. To be called in the parent. + */ +int virCommandHandshakeNotify(virCommandPtr cmd) +{ + char c = '1'; + if (!cmd ||cmd->has_error == ENOMEM) { + virReportOOMError(); + return -1; + } + if (cmd->has_error || !cmd->handshake) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid use of command API")); + return -1; + } + + if (cmd->handshakeNotify[1] == -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Handshake is already complete")); + return -1; + } + + VIR_DEBUG("Notify handshake on %d", cmd->handshakeNotify[1]); + if (safewrite(cmd->handshakeNotify[1], &c, sizeof(c)) != sizeof(c)) { + virReportSystemError(errno, "%s", _("Unable to notify child process")); + VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); + return -1; + } + VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); + return 0; +} + + +/** + * virCommandFree: + * @cmd: optional command to free + * + * Release all resources. The only exception is that if you called + * virCommandRunAsync with a non-null pid, then the asynchronous child + * is not reaped, and you must call virProcessWait() or virProcessAbort() yourself. + */ +void +virCommandFree(virCommandPtr cmd) +{ + int i; + if (!cmd) + return; + + for (i = 0; i < cmd->transfer_size; i++) { + VIR_FORCE_CLOSE(cmd->transfer[i]); + } + + VIR_FREE(cmd->inbuf); + VIR_FORCE_CLOSE(cmd->outfd); + VIR_FORCE_CLOSE(cmd->errfd); + + for (i = 0 ; i < cmd->nargs ; i++) + VIR_FREE(cmd->args[i]); + VIR_FREE(cmd->args); + + for (i = 0 ; i < cmd->nenv ; i++) + VIR_FREE(cmd->env[i]); + VIR_FREE(cmd->env); + + VIR_FREE(cmd->pwd); + + if (cmd->handshake) { + /* The other 2 fds in these arrays are closed + * due to use with virCommandTransferFD + */ + VIR_FORCE_CLOSE(cmd->handshakeWait[0]); + VIR_FORCE_CLOSE(cmd->handshakeNotify[1]); + } + + VIR_FREE(cmd->pidfile); + + if (cmd->reap) + virCommandAbort(cmd); + + VIR_FREE(cmd->transfer); + VIR_FREE(cmd->preserve); + + VIR_FREE(cmd); +} diff --git a/src/util/vircommand.h b/src/util/vircommand.h new file mode 100644 index 0000000..4c88165 --- /dev/null +++ b/src/util/vircommand.h @@ -0,0 +1,166 @@ +/* + * vircommand.h: Child command execution + * + * Copyright (C) 2010-2011 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __VIR_COMMAND_H__ +# define __VIR_COMMAND_H__ + +# include "internal.h" +# include "util.h" +# include "virbuffer.h" + +typedef struct _virCommand virCommand; +typedef virCommand *virCommandPtr; + +/* This will execute in the context of the first child + * after fork() but before execve(). As such, it is unsafe to + * call any function that is not async-signal-safe. */ +typedef int (*virExecHook)(void *data); + +int virFork(pid_t *pid) ATTRIBUTE_RETURN_CHECK; + +int virRun(const char *const*argv, int *status) ATTRIBUTE_RETURN_CHECK; + +virCommandPtr virCommandNew(const char *binary) ATTRIBUTE_NONNULL(1); + +virCommandPtr virCommandNewArgs(const char *const*args) ATTRIBUTE_NONNULL(1); + +virCommandPtr virCommandNewArgList(const char *binary, ...) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; + +virCommandPtr virCommandNewVAList(const char *binary, va_list list) + ATTRIBUTE_NONNULL(1); + +/* All error report from these setup APIs is + * delayed until the Run/RunAsync methods + */ + +void virCommandPreserveFD(virCommandPtr cmd, + int fd); + +void virCommandTransferFD(virCommandPtr cmd, + int fd); + +void virCommandSetPidFile(virCommandPtr cmd, + const char *pidfile) ATTRIBUTE_NONNULL(2); + +void virCommandClearCaps(virCommandPtr cmd); + +void virCommandAllowCap(virCommandPtr cmd, + int capability); + +void virCommandDaemonize(virCommandPtr cmd); + +void virCommandNonblockingFDs(virCommandPtr cmd); + +void virCommandAddEnvFormat(virCommandPtr cmd, const char *format, ...) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); + +void virCommandAddEnvPair(virCommandPtr cmd, + const char *name, + const char *value) ATTRIBUTE_NONNULL(2); + +void virCommandAddEnvString(virCommandPtr cmd, + const char *str) ATTRIBUTE_NONNULL(2); + +void virCommandAddEnvBuffer(virCommandPtr cmd, + virBufferPtr buf); + +void virCommandAddEnvPass(virCommandPtr cmd, + const char *name) ATTRIBUTE_NONNULL(2); + +void virCommandAddEnvPassCommon(virCommandPtr cmd); + +void virCommandAddArg(virCommandPtr cmd, + const char *val) ATTRIBUTE_NONNULL(2); + +void virCommandAddArgBuffer(virCommandPtr cmd, + virBufferPtr buf); + +void virCommandAddArgFormat(virCommandPtr cmd, + const char *format, ...) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); + +void virCommandAddArgPair(virCommandPtr cmd, + const char *name, + const char *val) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + +void virCommandAddArgSet(virCommandPtr cmd, + const char *const*vals) ATTRIBUTE_NONNULL(2); + +void virCommandAddArgList(virCommandPtr cmd, + ... /* const char *arg, ..., NULL */) + ATTRIBUTE_SENTINEL; + +void virCommandSetWorkingDirectory(virCommandPtr cmd, + const char *pwd) ATTRIBUTE_NONNULL(2); + +void virCommandSetInputBuffer(virCommandPtr cmd, + const char *inbuf) ATTRIBUTE_NONNULL(2); + +void virCommandSetOutputBuffer(virCommandPtr cmd, + char **outbuf) ATTRIBUTE_NONNULL(2); + +void virCommandSetErrorBuffer(virCommandPtr cmd, + char **errbuf) ATTRIBUTE_NONNULL(2); + +void virCommandSetInputFD(virCommandPtr cmd, + int infd); + +void virCommandSetOutputFD(virCommandPtr cmd, + int *outfd) ATTRIBUTE_NONNULL(2); + +void virCommandSetErrorFD(virCommandPtr cmd, + int *errfd) ATTRIBUTE_NONNULL(2); + +void virCommandSetPreExecHook(virCommandPtr cmd, + virExecHook hook, + void *opaque) ATTRIBUTE_NONNULL(2); + +void virCommandWriteArgLog(virCommandPtr cmd, + int logfd); + +char *virCommandToString(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; + +int virCommandExec(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; + +int virCommandRun(virCommandPtr cmd, + int *exitstatus) ATTRIBUTE_RETURN_CHECK; + +int virCommandRunAsync(virCommandPtr cmd, + pid_t *pid) ATTRIBUTE_RETURN_CHECK; + +int virCommandWait(virCommandPtr cmd, + int *exitstatus) ATTRIBUTE_RETURN_CHECK; + +void virCommandRequireHandshake(virCommandPtr cmd); + +int virCommandHandshakeWait(virCommandPtr cmd) + ATTRIBUTE_RETURN_CHECK; + +int virCommandHandshakeNotify(virCommandPtr cmd) + ATTRIBUTE_RETURN_CHECK; + +void virCommandAbort(virCommandPtr cmd); + +void virCommandFree(virCommandPtr cmd); + +#endif /* __VIR_COMMAND_H__ */ diff --git a/src/util/virfile.c b/src/util/virfile.c index c79ef04..d77b726 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -37,7 +37,7 @@ # include <sys/ioctl.h> #endif -#include "command.h" +#include "vircommand.h" #include "configmake.h" #include "memory.h" #include "virterror_internal.h" diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index c345013..e98a2ca 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -26,7 +26,7 @@ #include "virmacaddr.h" #include "virfile.h" #include "virterror_internal.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "pci.h" #include "logging.h" diff --git a/src/util/virnetdevbandwidth.c b/src/util/virnetdevbandwidth.c index 19c00b6..bd75a9d 100644 --- a/src/util/virnetdevbandwidth.c +++ b/src/util/virnetdevbandwidth.c @@ -23,7 +23,7 @@ #include <config.h> #include "virnetdevbandwidth.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "virterror_internal.h" diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c index 5bce611..983a240 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -24,7 +24,7 @@ #include <config.h> #include "virnetdevopenvswitch.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "virterror_internal.h" #include "virmacaddr.h" diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c index 4166ee0..3261337 100644 --- a/src/util/virnetdevveth.c +++ b/src/util/virnetdevveth.c @@ -28,7 +28,7 @@ #include "virnetdevveth.h" #include "memory.h" #include "logging.h" -#include "command.h" +#include "vircommand.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c index f80920e..a34ca6a 100644 --- a/src/util/virnodesuspend.c +++ b/src/util/virnodesuspend.c @@ -22,7 +22,7 @@ #include <config.h> #include "virnodesuspend.h" -#include "command.h" +#include "vircommand.h" #include "threads.h" #include "datatypes.h" diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c index 2eed4f8..b32de66 100644 --- a/src/vmware/vmware_conf.c +++ b/src/vmware/vmware_conf.c @@ -24,7 +24,7 @@ #include <string.h> #include <sys/utsname.h> -#include "command.h" +#include "vircommand.h" #include "cpu/cpu.h" #include "dirname.h" #include "memory.h" diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 3e7397f..d9a1333 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -30,7 +30,7 @@ #include "memory.h" #include "util.h" #include "uuid.h" -#include "command.h" +#include "vircommand.h" #include "vmx.h" #include "vmware_conf.h" #include "vmware_driver.h" diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d2de141..d9174b6 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -62,7 +62,7 @@ #include "fdstream.h" #include "virfile.h" #include "viruri.h" -#include "command.h" +#include "vircommand.h" #include "virnodesuspend.h" #include "nodeinfo.h" #include "configmake.h" diff --git a/tests/commandtest.c b/tests/commandtest.c index 19bf9ba..f76bc54 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -33,7 +33,7 @@ #include "nodeinfo.h" #include "util.h" #include "memory.h" -#include "command.h" +#include "vircommand.h" #include "virfile.h" #include "virpidfile.h" #include "virterror_internal.h" diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c index 1888465..dc0e064 100644 --- a/tests/networkxml2conftest.c +++ b/tests/networkxml2conftest.c @@ -11,7 +11,7 @@ #include "internal.h" #include "testutils.h" #include "network_conf.h" -#include "command.h" +#include "vircommand.h" #include "memory.h" #include "network/bridge_driver.h" diff --git a/tests/reconnect.c b/tests/reconnect.c index 90af830..4031360 100644 --- a/tests/reconnect.c +++ b/tests/reconnect.c @@ -6,7 +6,7 @@ #include "internal.h" #include "testutils.h" -#include "command.h" +#include "vircommand.h" static void errorHandler(void *userData ATTRIBUTE_UNUSED, virErrorPtr error ATTRIBUTE_UNUSED) { diff --git a/tests/statstest.c b/tests/statstest.c index 8c40082..ad71bf9 100644 --- a/tests/statstest.c +++ b/tests/statstest.c @@ -9,7 +9,7 @@ #include "internal.h" #include "xen/block_stats.h" #include "testutils.h" -#include "command.h" +#include "vircommand.h" static void testQuietError(void *userData ATTRIBUTE_UNUSED, virErrorPtr error ATTRIBUTE_UNUSED) diff --git a/tests/testutils.c b/tests/testutils.c index e8b48e8..1315cb5 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -45,7 +45,7 @@ #include "virterror_internal.h" #include "virbuffer.h" #include "logging.h" -#include "command.h" +#include "vircommand.h" #include "virrandom.h" #include "dirname.h" #include "virprocess.h" diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c index cc260e0..d421feb 100644 --- a/tests/virnettlscontexttest.c +++ b/tests/virnettlscontexttest.c @@ -32,7 +32,7 @@ #include "memory.h" #include "logging.h" #include "virfile.h" -#include "command.h" +#include "vircommand.h" #include "virsocketaddr.h" #include "gnutls_1_0_compat.h" diff --git a/tools/virsh.c b/tools/virsh.c index 82c03e4..07da077 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -66,7 +66,7 @@ #include "event_poll.h" #include "configmake.h" #include "threads.h" -#include "command.h" +#include "vircommand.h" #include "virkeycode.h" #include "virnetdevbandwidth.h" #include "virbitmap.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- daemon/libvirtd-config.c | 2 +- daemon/libvirtd.c | 2 +- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_daemon_config.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_sanlock.c | 2 +- src/locking/sanlock_helper.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/security/security_selinux.c | 2 +- src/uml/uml_conf.c | 2 +- src/util/conf.c | 1032 ------------------------------------- src/util/conf.h | 100 ---- src/util/virconf.c | 1032 +++++++++++++++++++++++++++++++++++++ src/util/virconf.h | 100 ++++ src/vmx/vmx.c | 2 +- src/vmx/vmx.h | 2 +- src/xen/xen_inotify.c | 2 +- src/xen/xm_internal.h | 2 +- src/xenxs/xen_sxpr.c | 2 +- src/xenxs/xen_sxpr.h | 2 +- src/xenxs/xen_xm.c | 2 +- src/xenxs/xen_xm.h | 2 +- tests/conftest.c | 2 +- tests/libvirtdconftest.c | 2 +- 29 files changed, 1157 insertions(+), 1157 deletions(-) delete mode 100644 src/util/conf.c delete mode 100644 src/util/conf.h create mode 100644 src/util/virconf.c create mode 100644 src/util/virconf.h diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index 7838044..0ca185c 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -24,7 +24,7 @@ #include <config.h> #include "libvirtd-config.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index f88be9b..9b0e45a 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -47,7 +47,7 @@ #include "uuid.h" #include "remote_driver.h" #include "memory.h" -#include "conf.h" +#include "virconf.h" #include "virnetlink.h" #include "virnetserver.h" #include "threads.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index 843db7c..e80c413 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/conf.c src/util/dnsmasq.c src/util/event_poll.c src/util/hooks.c @@ -157,6 +156,7 @@ src/util/virauth.c src/util/virauthconfig.c src/util/vircgroup.c src/util/vircommand.c +src/util/virconf.c src/util/virdbus.c src/util/virfile.c src/util/virhash.c diff --git a/src/Makefile.am b/src/Makefile.am index 7e16d68..b53f1f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/conf.c util/conf.h \ util/event.c util/event.h \ util/event_poll.c util/event_poll.h \ util/hooks.c util/hooks.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virbitmap.c util/virbitmap.h \ util/virbuffer.c util/virbuffer.h \ util/vircommand.c util/vircommand.h \ + util/virconf.c util/virconf.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/libvirt.c b/src/libvirt.c index e28ed05..8f7a869 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -54,7 +54,7 @@ #include "memory.h" #include "configmake.h" #include "intprops.h" -#include "conf.h" +#include "virconf.h" #include "rpc/virnettlscontext.h" #include "vircommand.h" #include "virrandom.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 1423073..884fca8 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -34,7 +34,7 @@ #include "internal.h" #include "logging.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "datatypes.h" #include "virfile.h" #include "memory.h" diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index d7906c5..08caa16 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -40,7 +40,7 @@ #include "virterror_internal.h" #include "logging.h" #include "memory.h" -#include "conf.h" +#include "virconf.h" #include "rpc/virnetserver.h" #include "virrandom.h" #include "virhash.h" diff --git a/src/locking/lock_daemon_config.c b/src/locking/lock_daemon_config.c index c64de67..c2d9a76 100644 --- a/src/locking/lock_daemon_config.c +++ b/src/locking/lock_daemon_config.c @@ -24,7 +24,7 @@ #include <config.h> #include "lock_daemon_config.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index 3902ede..c88c5af 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -22,7 +22,7 @@ #include <config.h> #include "lock_driver.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "logging.h" #include "uuid.h" diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index a072343..2eadc07 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -43,7 +43,7 @@ #include "util.h" #include "virfile.h" #include "md5.h" -#include "conf.h" +#include "virconf.h" #include "configmake.h" diff --git a/src/locking/sanlock_helper.c b/src/locking/sanlock_helper.c index a73b49c..ad69312 100644 --- a/src/locking/sanlock_helper.c +++ b/src/locking/sanlock_helper.c @@ -5,7 +5,7 @@ #include "configmake.h" #include "internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "domain_conf.h" diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index e512b8f..77667bd 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -31,7 +31,7 @@ #include "lxc_conf.h" #include "nodeinfo.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "logging.h" #include "uuid.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 4a8b857..7c8d826 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -42,7 +42,7 @@ #include "qemu_bridge_filter.h" #include "uuid.h" #include "virbuffer.h" -#include "conf.h" +#include "virconf.h" #include "util.h" #include "memory.h" #include "datatypes.h" diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 5c125fe..287312a 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -44,7 +44,7 @@ #include "virhash.h" #include "virrandom.h" #include "util.h" -#include "conf.h" +#include "virconf.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 6aec8fc..51e5a7a 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -38,7 +38,7 @@ #include "uml_conf.h" #include "uuid.h" #include "virbuffer.h" -#include "conf.h" +#include "virconf.h" #include "util.h" #include "memory.h" #include "nodeinfo.h" diff --git a/src/util/conf.c b/src/util/conf.c deleted file mode 100644 index 3b97545..0000000 --- a/src/util/conf.c +++ /dev/null @@ -1,1032 +0,0 @@ -/** - * conf.c: parser for a subset of the Python encoded Xen configuration files - * - * Copyright (C) 2006-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 "virbuffer.h" -#include "conf.h" -#include "util.h" -#include "c-ctype.h" -#include "logging.h" -#include "memory.h" -#include "virfile.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 - */ -#define virConfError(ctxt, error, info) \ - virConfErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info) -static void -virConfErrorHelper(const char *file, const char *func, size_t line, - virConfParserCtxtPtr ctxt, - virErrorNumber error, const char *info) -{ - if (error == VIR_ERR_OK) - return; - - /* Construct the string 'filename:line: info' if we have that. */ - if (ctxt && ctxt->filename) { - virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, - _("%s:%d: %s"), ctxt->filename, ctxt->line, info); - } else { - virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, - "%s", 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(); - 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(); - 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: - virBufferAsprintf(buf, "%ld", val->l); - break; - case VIR_CONF_STRING: - if (strchr(val->str, '\n') != NULL) { - virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str); - } else if (strchr(val->str, '"') == NULL) { - virBufferAsprintf(buf, "\"%s\"", val->str); - } else if (strchr(val->str, '\'') == NULL) { - virBufferAsprintf(buf, "'%s'", val->str); - } else { - virBufferAsprintf(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); - if (ret == NULL) { - virReportOOMError(); - return NULL; - } - NEXT; - } else if ((ctxt->cur + 6 < ctxt->end) && - (STRPREFIX(ctxt->cur, "\"\"\""))) { - /* String starts with python-style triple quotes """ */ - ctxt->cur += 3; - base = ctxt->cur; - - /* Find the ending triple quotes */ - while ((ctxt->cur + 2 < ctxt->end) && - !(STRPREFIX(ctxt->cur, "\"\"\""))) { - if (CUR == '\n') - ctxt->line++; - NEXT; - } - - if (!STRPREFIX(ctxt->cur, "\"\"\"")) { - virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); - return NULL; - } - ret = strndup(base, ctxt->cur - base); - if (ret == NULL) { - virReportOOMError(); - return NULL; - } - 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); - if (ret == NULL) { - virReportOOMError(); - return NULL; - } - 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 != ']')) { - - /* Tell Clang that when execution reaches this point - "lst" is guaranteed to be non-NULL. This stops it - from issuing an invalid NULL-dereference warning about - "prev = lst; while (prev->next..." below. */ - sa_assert(lst); - - 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(); - 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 == '.') || (CUR == '-'))))) - NEXT; - ret = strndup(base, ctxt->cur - base); - if (ret == NULL) { - virReportOOMError(); - 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(); - 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")); - VIR_FREE(name); - 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(); - 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 a 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 a 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; - - VIR_DEBUG("filename=%s", NULLSTR(filename)); - - 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 a 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) - return 0; - - 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; - - if (conf == NULL) - return NULL; - - cur = conf->entries; - while (cur != NULL) { - if ((cur->name != NULL) && - ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT && - STRCASEEQ(cur->name, setting)) || - 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; - - if (value && value->type == VIR_CONF_STRING && value->str == NULL) - return -1; - - 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) { - virReportOOMError(); - virConfFreeValue(value); - return -1; - } - cur->comment = NULL; - if (!(cur->name = strdup(setting))) { - virReportOOMError(); - 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 { - 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)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - return -1; - } - - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); - if (fd < 0) { - virBufferFreeAndReset(&buf); - virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file")); - return -1; - } - - use = virBufferUse(&buf); - content = virBufferContentAndReset(&buf); - ret = safewrite(fd, content, use); - VIR_FREE(content); - VIR_FORCE_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)) { - virBufferFreeAndReset(&buf); - virReportOOMError(); - 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 deleted file mode 100644 index 224592d..0000000 --- a/src/util/conf.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * conf.h: parser for a subset of the Python encoded Xen configuration files - * - * Copyright (C) 2006, 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, see - * <http://www.gnu.org/licenses/>. - * - * 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/virconf.c b/src/util/virconf.c new file mode 100644 index 0000000..221a1eb --- /dev/null +++ b/src/util/virconf.c @@ -0,0 +1,1032 @@ +/** + * conf.c: parser for a subset of the Python encoded Xen configuration files + * + * Copyright (C) 2006-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * 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 "virbuffer.h" +#include "virconf.h" +#include "util.h" +#include "c-ctype.h" +#include "logging.h" +#include "memory.h" +#include "virfile.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 + */ +#define virConfError(ctxt, error, info) \ + virConfErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info) +static void +virConfErrorHelper(const char *file, const char *func, size_t line, + virConfParserCtxtPtr ctxt, + virErrorNumber error, const char *info) +{ + if (error == VIR_ERR_OK) + return; + + /* Construct the string 'filename:line: info' if we have that. */ + if (ctxt && ctxt->filename) { + virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, + _("%s:%d: %s"), ctxt->filename, ctxt->line, info); + } else { + virReportErrorHelper(VIR_FROM_CONF, error, file, func, line, + "%s", 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(); + 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(); + 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: + virBufferAsprintf(buf, "%ld", val->l); + break; + case VIR_CONF_STRING: + if (strchr(val->str, '\n') != NULL) { + virBufferAsprintf(buf, "\"\"\"%s\"\"\"", val->str); + } else if (strchr(val->str, '"') == NULL) { + virBufferAsprintf(buf, "\"%s\"", val->str); + } else if (strchr(val->str, '\'') == NULL) { + virBufferAsprintf(buf, "'%s'", val->str); + } else { + virBufferAsprintf(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); + if (ret == NULL) { + virReportOOMError(); + return NULL; + } + NEXT; + } else if ((ctxt->cur + 6 < ctxt->end) && + (STRPREFIX(ctxt->cur, "\"\"\""))) { + /* String starts with python-style triple quotes """ */ + ctxt->cur += 3; + base = ctxt->cur; + + /* Find the ending triple quotes */ + while ((ctxt->cur + 2 < ctxt->end) && + !(STRPREFIX(ctxt->cur, "\"\"\""))) { + if (CUR == '\n') + ctxt->line++; + NEXT; + } + + if (!STRPREFIX(ctxt->cur, "\"\"\"")) { + virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); + return NULL; + } + ret = strndup(base, ctxt->cur - base); + if (ret == NULL) { + virReportOOMError(); + return NULL; + } + 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); + if (ret == NULL) { + virReportOOMError(); + return NULL; + } + 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 != ']')) { + + /* Tell Clang that when execution reaches this point + "lst" is guaranteed to be non-NULL. This stops it + from issuing an invalid NULL-dereference warning about + "prev = lst; while (prev->next..." below. */ + sa_assert(lst); + + 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(); + 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 == '.') || (CUR == '-'))))) + NEXT; + ret = strndup(base, ctxt->cur - base); + if (ret == NULL) { + virReportOOMError(); + 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(); + 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")); + VIR_FREE(name); + 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(); + 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 a 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 a 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; + + VIR_DEBUG("filename=%s", NULLSTR(filename)); + + 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 a 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) + return 0; + + 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; + + if (conf == NULL) + return NULL; + + cur = conf->entries; + while (cur != NULL) { + if ((cur->name != NULL) && + ((conf->flags & VIR_CONF_FLAG_VMX_FORMAT && + STRCASEEQ(cur->name, setting)) || + 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; + + if (value && value->type == VIR_CONF_STRING && value->str == NULL) + return -1; + + 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) { + virReportOOMError(); + virConfFreeValue(value); + return -1; + } + cur->comment = NULL; + if (!(cur->name = strdup(setting))) { + virReportOOMError(); + 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 { + 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)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + return -1; + } + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (fd < 0) { + virBufferFreeAndReset(&buf); + virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file")); + return -1; + } + + use = virBufferUse(&buf); + content = virBufferContentAndReset(&buf); + ret = safewrite(fd, content, use); + VIR_FREE(content); + VIR_FORCE_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)) { + virBufferFreeAndReset(&buf); + virReportOOMError(); + 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/virconf.h b/src/util/virconf.h new file mode 100644 index 0000000..224592d --- /dev/null +++ b/src/util/virconf.h @@ -0,0 +1,100 @@ +/** + * conf.h: parser for a subset of the Python encoded Xen configuration files + * + * Copyright (C) 2006, 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, see + * <http://www.gnu.org/licenses/>. + * + * 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/vmx/vmx.c b/src/vmx/vmx.c index e051de5..0d34453 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -27,7 +27,7 @@ #include "internal.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "logging.h" #include "uuid.h" diff --git a/src/vmx/vmx.h b/src/vmx/vmx.h index 406c27e..f4877b1 100644 --- a/src/vmx/vmx.h +++ b/src/vmx/vmx.h @@ -24,7 +24,7 @@ # define __VIR_VMX_H__ # include "internal.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" typedef struct _virVMXContext virVMXContext; diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 2e40015..bcafdd0 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -32,7 +32,7 @@ #include "driver.h" #include "memory.h" #include "xen_driver.h" -#include "conf.h" +#include "virconf.h" #include "domain_conf.h" #include "xen_inotify.h" #include "xend_internal.h" diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h index 98b5ad7..df77ac8 100644 --- a/src/xen/xm_internal.h +++ b/src/xen/xm_internal.h @@ -27,7 +27,7 @@ # include "internal.h" # include "driver.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" extern struct xenUnifiedDriver xenXMDriver; diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index 3e8396b..ed0c9e1 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -28,7 +28,7 @@ #include "internal.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "verify.h" #include "uuid.h" diff --git a/src/xenxs/xen_sxpr.h b/src/xenxs/xen_sxpr.h index d4502bd..4ff640c 100644 --- a/src/xenxs/xen_sxpr.h +++ b/src/xenxs/xen_sxpr.h @@ -28,7 +28,7 @@ # define __VIR_XEN_SXPR_H__ # include "internal.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" # include "sexpr.h" diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index 23b3037..7bde7ab 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -27,7 +27,7 @@ #include "internal.h" #include "virterror_internal.h" -#include "conf.h" +#include "virconf.h" #include "memory.h" #include "verify.h" #include "uuid.h" diff --git a/src/xenxs/xen_xm.h b/src/xenxs/xen_xm.h index c3d0ad4..629a4b3 100644 --- a/src/xenxs/xen_xm.h +++ b/src/xenxs/xen_xm.h @@ -27,7 +27,7 @@ # define __VIR_XEN_XM_H__ # include "internal.h" -# include "conf.h" +# include "virconf.h" # include "domain_conf.h" virConfPtr xenFormatXM(virConnectPtr conn, virDomainDefPtr def, diff --git a/tests/conftest.c b/tests/conftest.c index 4342a52..aacc526 100644 --- a/tests/conftest.c +++ b/tests/conftest.c @@ -5,7 +5,7 @@ #include <stdio.h> #include <string.h> #include <errno.h> -#include "conf.h" +#include "virconf.h" #include "memory.h" int main(int argc, char **argv) diff --git a/tests/libvirtdconftest.c b/tests/libvirtdconftest.c index ee1f8a0..c2b02a6 100644 --- a/tests/libvirtdconftest.c +++ b/tests/libvirtdconftest.c @@ -28,7 +28,7 @@ #include "c-ctype.h" #include "virterror_internal.h" #include "logging.h" -#include "conf.h" +#include "virconf.h" #define VIR_FROM_THIS VIR_FROM_NONE -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/network/bridge_driver.c | 2 +- src/network/bridge_driver.h | 2 +- src/util/dnsmasq.c | 872 -------------------------------------------- src/util/dnsmasq.h | 117 ------ src/util/virdnsmasq.c | 872 ++++++++++++++++++++++++++++++++++++++++++++ src/util/virdnsmasq.h | 117 ++++++ 8 files changed, 993 insertions(+), 993 deletions(-) delete mode 100644 src/util/dnsmasq.c delete mode 100644 src/util/dnsmasq.h create mode 100644 src/util/virdnsmasq.c create mode 100644 src/util/virdnsmasq.h diff --git a/po/POTFILES.in b/po/POTFILES.in index e80c413..3214ebe 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/dnsmasq.c src/util/event_poll.c src/util/hooks.c src/util/hostusb.c @@ -158,6 +157,7 @@ src/util/vircgroup.c src/util/vircommand.c src/util/virconf.c src/util/virdbus.c +src/util/virdnsmasq.c src/util/virfile.c src/util/virhash.c src/util/virinitctl.c diff --git a/src/Makefile.am b/src/Makefile.am index b53f1f2..ce16e87 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -58,7 +58,6 @@ UTIL_SOURCES = \ util/hooks.c util/hooks.h \ util/iptables.c util/iptables.h \ util/ebtables.c util/ebtables.h \ - util/dnsmasq.c util/dnsmasq.h \ util/json.c util/json.h \ util/logging.c util/logging.h \ util/memory.c util/memory.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virbuffer.c util/virbuffer.h \ util/vircommand.c util/vircommand.h \ util/virconf.c util/virconf.h \ + util/virdnsmasq.c util/virdnsmasq.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 319ff8c..1110208 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -58,7 +58,7 @@ #include "uuid.h" #include "iptables.h" #include "logging.h" -#include "dnsmasq.h" +#include "virdnsmasq.h" #include "configmake.h" #include "virnetdev.h" #include "pci.h" diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index fea27e0..4bf64ea 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -31,7 +31,7 @@ # include "network_conf.h" # include "domain_conf.h" # include "vircommand.h" -# include "dnsmasq.h" +# include "virdnsmasq.h" int networkRegister(void); diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c deleted file mode 100644 index 6e9c9dd..0000000 --- a/src/util/dnsmasq.c +++ /dev/null @@ -1,872 +0,0 @@ -/* - * Copyright (C) 2007-2012 Red Hat, Inc. - * Copyright (C) 2010 Satoru SATOH <satoru.satoh@gmail.com> - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Based on iptables.c - */ - -#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> -#include <signal.h> - -#ifdef HAVE_PATHS_H -# include <paths.h> -#endif - -#include "internal.h" -#include "datatypes.h" -#include "virbitmap.h" -#include "dnsmasq.h" -#include "util.h" -#include "vircommand.h" -#include "memory.h" -#include "virterror_internal.h" -#include "logging.h" -#include "virfile.h" - -#define VIR_FROM_THIS VIR_FROM_NETWORK -#define DNSMASQ_HOSTSFILE_SUFFIX "hostsfile" -#define DNSMASQ_ADDNHOSTSFILE_SUFFIX "addnhosts" - -static void -dhcphostFree(dnsmasqDhcpHost *host) -{ - VIR_FREE(host->host); -} - -static void -addnhostFree(dnsmasqAddnHost *host) -{ - int i; - - for (i = 0; i < host->nhostnames; i++) - VIR_FREE(host->hostnames[i]); - VIR_FREE(host->hostnames); - VIR_FREE(host->ip); -} - -static void -addnhostsFree(dnsmasqAddnHostsfile *addnhostsfile) -{ - unsigned int i; - - if (addnhostsfile->hosts) { - for (i = 0; i < addnhostsfile->nhosts; i++) - addnhostFree(&addnhostsfile->hosts[i]); - - VIR_FREE(addnhostsfile->hosts); - - addnhostsfile->nhosts = 0; - } - - VIR_FREE(addnhostsfile->path); - - VIR_FREE(addnhostsfile); -} - -static int -addnhostsAdd(dnsmasqAddnHostsfile *addnhostsfile, - virSocketAddr *ip, - const char *name) -{ - char *ipstr = NULL; - int idx = -1; - int i; - - if (!(ipstr = virSocketAddrFormat(ip))) - return -1; - - for (i = 0; i < addnhostsfile->nhosts; i++) { - if (STREQ((const char *)addnhostsfile->hosts[i].ip, (const char *)ipstr)) { - idx = i; - break; - } - } - - if (idx < 0) { - if (VIR_REALLOC_N(addnhostsfile->hosts, addnhostsfile->nhosts + 1) < 0) - goto alloc_error; - - idx = addnhostsfile->nhosts; - if (VIR_ALLOC(addnhostsfile->hosts[idx].hostnames) < 0) - goto alloc_error; - - if (virAsprintf(&addnhostsfile->hosts[idx].ip, "%s", ipstr) < 0) - goto alloc_error; - - addnhostsfile->hosts[idx].nhostnames = 0; - addnhostsfile->nhosts++; - } - - if (VIR_REALLOC_N(addnhostsfile->hosts[idx].hostnames, addnhostsfile->hosts[idx].nhostnames + 1) < 0) - goto alloc_error; - - if (virAsprintf(&addnhostsfile->hosts[idx].hostnames[addnhostsfile->hosts[idx].nhostnames], "%s", name) < 0) - goto alloc_error; - - VIR_FREE(ipstr); - - addnhostsfile->hosts[idx].nhostnames++; - - return 0; - - alloc_error: - virReportOOMError(); - VIR_FREE(ipstr); - return -1; -} - -static dnsmasqAddnHostsfile * -addnhostsNew(const char *name, - const char *config_dir) -{ - dnsmasqAddnHostsfile *addnhostsfile; - - if (VIR_ALLOC(addnhostsfile) < 0) { - virReportOOMError(); - return NULL; - } - - addnhostsfile->hosts = NULL; - addnhostsfile->nhosts = 0; - - if (virAsprintf(&addnhostsfile->path, "%s/%s.%s", config_dir, name, - DNSMASQ_ADDNHOSTSFILE_SUFFIX) < 0) { - virReportOOMError(); - goto error; - } - - return addnhostsfile; - - error: - addnhostsFree(addnhostsfile); - return NULL; -} - -static int -addnhostsWrite(const char *path, - dnsmasqAddnHost *hosts, - unsigned int nhosts) -{ - char *tmp; - FILE *f; - bool istmp = true; - unsigned int i, ii; - int rc = 0; - - /* even if there are 0 hosts, create a 0 length file, to allow - * for runtime addition. - */ - - if (virAsprintf(&tmp, "%s.new", path) < 0) - return -ENOMEM; - - if (!(f = fopen(tmp, "w"))) { - istmp = false; - if (!(f = fopen(path, "w"))) { - rc = -errno; - goto cleanup; - } - } - - for (i = 0; i < nhosts; i++) { - if (fputs(hosts[i].ip, f) == EOF || fputc('\t', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - - for (ii = 0; ii < hosts[i].nhostnames; ii++) { - if (fputs(hosts[i].hostnames[ii], f) == EOF || fputc('\t', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - } - - if (fputc('\n', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - } - - if (VIR_FCLOSE(f) == EOF) { - rc = -errno; - goto cleanup; - } - - if (istmp && rename(tmp, path) < 0) { - rc = -errno; - unlink(tmp); - goto cleanup; - } - - cleanup: - VIR_FREE(tmp); - - return rc; -} - -static int -addnhostsSave(dnsmasqAddnHostsfile *addnhostsfile) -{ - int err = addnhostsWrite(addnhostsfile->path, addnhostsfile->hosts, - addnhostsfile->nhosts); - - if (err < 0) { - virReportSystemError(-err, _("cannot write config file '%s'"), - addnhostsfile->path); - return -1; - } - - return 0; -} - -static int -genericFileDelete(char *path) -{ - if (!virFileExists(path)) - return 0; - - if (unlink(path) < 0) { - virReportSystemError(errno, _("cannot remove config file '%s'"), - path); - return -1; - } - - return 0; -} - -static void -hostsfileFree(dnsmasqHostsfile *hostsfile) -{ - unsigned int i; - - if (hostsfile->hosts) { - for (i = 0; i < hostsfile->nhosts; i++) - dhcphostFree(&hostsfile->hosts[i]); - - VIR_FREE(hostsfile->hosts); - - hostsfile->nhosts = 0; - } - - VIR_FREE(hostsfile->path); - - VIR_FREE(hostsfile); -} - -/* Note: There are many additional dhcp-host specifications - * supported by dnsmasq. There are only the basic ones. - */ -static int -hostsfileAdd(dnsmasqHostsfile *hostsfile, - const char *mac, - virSocketAddr *ip, - const char *name, - bool ipv6) -{ - char *ipstr = NULL; - if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0) - goto alloc_error; - - if (!(ipstr = virSocketAddrFormat(ip))) - return -1; - - /* the first test determines if it is a dhcpv6 host */ - if (ipv6) { - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,[%s]", - name, ipstr) < 0) - goto alloc_error; - } - else if (name && mac) { - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s", - mac, ipstr, name) < 0) - goto alloc_error; - } else if (name && !mac){ - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", - name, ipstr) < 0) - goto alloc_error; - } else { - if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", - mac, ipstr) < 0) - goto alloc_error; - } - VIR_FREE(ipstr); - - hostsfile->nhosts++; - - return 0; - - alloc_error: - virReportOOMError(); - VIR_FREE(ipstr); - return -1; -} - -static dnsmasqHostsfile * -hostsfileNew(const char *name, - const char *config_dir) -{ - dnsmasqHostsfile *hostsfile; - - if (VIR_ALLOC(hostsfile) < 0) { - virReportOOMError(); - return NULL; - } - - hostsfile->hosts = NULL; - hostsfile->nhosts = 0; - - if (virAsprintf(&hostsfile->path, "%s/%s.%s", config_dir, name, - DNSMASQ_HOSTSFILE_SUFFIX) < 0) { - virReportOOMError(); - goto error; - } - - return hostsfile; - - error: - hostsfileFree(hostsfile); - return NULL; -} - -static int -hostsfileWrite(const char *path, - dnsmasqDhcpHost *hosts, - unsigned int nhosts) -{ - char *tmp; - FILE *f; - bool istmp = true; - unsigned int i; - int rc = 0; - - /* even if there are 0 hosts, create a 0 length file, to allow - * for runtime addition. - */ - - if (virAsprintf(&tmp, "%s.new", path) < 0) - return -ENOMEM; - - if (!(f = fopen(tmp, "w"))) { - istmp = false; - if (!(f = fopen(path, "w"))) { - rc = -errno; - goto cleanup; - } - } - - for (i = 0; i < nhosts; i++) { - if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) { - rc = -errno; - VIR_FORCE_FCLOSE(f); - - if (istmp) - unlink(tmp); - - goto cleanup; - } - } - - if (VIR_FCLOSE(f) == EOF) { - rc = -errno; - goto cleanup; - } - - if (istmp && rename(tmp, path) < 0) { - rc = -errno; - unlink(tmp); - goto cleanup; - } - - cleanup: - VIR_FREE(tmp); - - return rc; -} - -static int -hostsfileSave(dnsmasqHostsfile *hostsfile) -{ - int err = hostsfileWrite(hostsfile->path, hostsfile->hosts, - hostsfile->nhosts); - - if (err < 0) { - virReportSystemError(-err, _("cannot write config file '%s'"), - hostsfile->path); - return -1; - } - - return 0; -} - -/** - * dnsmasqContextNew: - * - * Create a new Dnsmasq context - * - * Returns a pointer to the new structure or NULL in case of error - */ -dnsmasqContext * -dnsmasqContextNew(const char *network_name, - const char *config_dir) -{ - dnsmasqContext *ctx; - - if (VIR_ALLOC(ctx) < 0) { - virReportOOMError(); - return NULL; - } - - if (!(ctx->config_dir = strdup(config_dir))) { - virReportOOMError(); - goto error; - } - - if (!(ctx->hostsfile = hostsfileNew(network_name, config_dir))) - goto error; - if (!(ctx->addnhostsfile = addnhostsNew(network_name, config_dir))) - goto error; - - return ctx; - - error: - dnsmasqContextFree(ctx); - return NULL; -} - -/** - * dnsmasqContextFree: - * @ctx: pointer to the dnsmasq context - * - * Free the resources associated with a dnsmasq context - */ -void -dnsmasqContextFree(dnsmasqContext *ctx) -{ - if (!ctx) - return; - - VIR_FREE(ctx->config_dir); - - if (ctx->hostsfile) - hostsfileFree(ctx->hostsfile); - if (ctx->addnhostsfile) - addnhostsFree(ctx->addnhostsfile); - - VIR_FREE(ctx); -} - -/** - * dnsmasqAddDhcpHost: - * @ctx: pointer to the dnsmasq context for each network - * @mac: pointer to the string contains mac address of the host - * @ip: pointer to the socket address contains ip of the host - * @name: pointer to the string contains hostname of the host or NULL - * - * Add dhcp-host entry. - */ -int -dnsmasqAddDhcpHost(dnsmasqContext *ctx, - const char *mac, - virSocketAddr *ip, - const char *name, - bool ipv6) -{ - return hostsfileAdd(ctx->hostsfile, mac, ip, name, ipv6); -} - -/* - * dnsmasqAddHost: - * @ctx: pointer to the dnsmasq context for each network - * @ip: pointer to the socket address contains ip of the host - * @name: pointer to the string contains hostname of the host - * - * Add additional host entry. - */ - -int -dnsmasqAddHost(dnsmasqContext *ctx, - virSocketAddr *ip, - const char *name) -{ - return addnhostsAdd(ctx->addnhostsfile, ip, name); -} - -/** - * dnsmasqSave: - * @ctx: pointer to the dnsmasq context for each network - * - * Saves all the configurations associated with a context to disk. - */ -int -dnsmasqSave(const dnsmasqContext *ctx) -{ - int ret = 0; - - if (virFileMakePath(ctx->config_dir) < 0) { - virReportSystemError(errno, _("cannot create config directory '%s'"), - ctx->config_dir); - return -1; - } - - if (ctx->hostsfile) - ret = hostsfileSave(ctx->hostsfile); - if (ret == 0) { - if (ctx->addnhostsfile) - ret = addnhostsSave(ctx->addnhostsfile); - } - - return ret; -} - - -/** - * dnsmasqDelete: - * @ctx: pointer to the dnsmasq context for each network - * - * Delete all the configuration files associated with a context. - */ -int -dnsmasqDelete(const dnsmasqContext *ctx) -{ - int ret = 0; - - if (ctx->hostsfile) - ret = genericFileDelete(ctx->hostsfile->path); - if (ctx->addnhostsfile) - ret = genericFileDelete(ctx->addnhostsfile->path); - - return ret; -} - -/** - * dnsmasqReload: - * @pid: the pid of the target dnsmasq process - * - * Reloads all the configurations associated to a context - */ -int -dnsmasqReload(pid_t pid ATTRIBUTE_UNUSED) -{ -#ifndef WIN32 - if (kill(pid, SIGHUP) != 0) { - virReportSystemError(errno, - _("Failed to make dnsmasq (PID: %d) reload config files."), - pid); - return -1; - } -#endif /* WIN32 */ - - return 0; -} - -/* - * dnsmasqCapabilities functions - provide useful information about the - * version of dnsmasq on this machine. - * - */ -struct _dnsmasqCaps { - virObject object; - char *binaryPath; - bool noRefresh; - time_t mtime; - virBitmapPtr flags; - unsigned long version; -}; - -static virClassPtr dnsmasqCapsClass; - -static void -dnsmasqCapsDispose(void *obj) -{ - dnsmasqCapsPtr caps = obj; - - virBitmapFree(caps->flags); - VIR_FREE(caps->binaryPath); -} - -static int dnsmasqCapsOnceInit(void) -{ - if (!(dnsmasqCapsClass = virClassNew("dnsmasqCaps", - sizeof(dnsmasqCaps), - dnsmasqCapsDispose))) { - return -1; - } - - return 0; -} - -VIR_ONCE_GLOBAL_INIT(dnsmasqCaps) - -static void -dnsmasqCapsSet(dnsmasqCapsPtr caps, - dnsmasqCapsFlags flag) -{ - ignore_value(virBitmapSetBit(caps->flags, flag)); -} - - -#define DNSMASQ_VERSION_STR "Dnsmasq version " - -static int -dnsmasqCapsSetFromBuffer(dnsmasqCapsPtr caps, const char *buf) -{ - const char *p; - - caps->noRefresh = true; - - p = STRSKIP(buf, DNSMASQ_VERSION_STR); - if (!p) - goto fail; - virSkipSpaces(&p); - if (virParseVersionString(p, &caps->version, true) < 0) - goto fail; - - if (strstr(buf, "--bind-dynamic")) - dnsmasqCapsSet(caps, DNSMASQ_CAPS_BIND_DYNAMIC); - - VIR_INFO("dnsmasq version is %d.%d, --bind-dynamic is %s", - (int)caps->version / 1000000, (int)(caps->version % 1000000) / 1000, - dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) - ? "present" : "NOT present"); - return 0; - -fail: - p = strchrnul(buf, '\n'); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse %s version number in '%.*s'"), - caps->binaryPath, (int) (p - buf), buf); - return -1; - -} - -static int -dnsmasqCapsSetFromFile(dnsmasqCapsPtr caps, const char *path) -{ - int ret = -1; - char *buf = NULL; - - if (virFileReadAll(path, 1024 * 1024, &buf) < 0) - goto cleanup; - - ret = dnsmasqCapsSetFromBuffer(caps, buf); - -cleanup: - VIR_FREE(buf); - return ret; -} - -static int -dnsmasqCapsRefreshInternal(dnsmasqCapsPtr caps, bool force) -{ - int ret = -1; - struct stat sb; - virCommandPtr cmd = NULL; - char *help = NULL, *version = NULL, *complete = NULL; - - if (!caps || caps->noRefresh) - return 0; - - if (stat(caps->binaryPath, &sb) < 0) { - virReportSystemError(errno, _("Cannot check dnsmasq binary %s"), - caps->binaryPath); - return -1; - } - if (!force && caps->mtime == sb.st_mtime) { - return 0; - } - caps->mtime = sb.st_mtime; - - /* Make sure the binary we are about to try exec'ing exists. - * Technically we could catch the exec() failure, but that's - * in a sub-process so it's hard to feed back a useful error. - */ - if (!virFileIsExecutable(caps->binaryPath)) { - virReportSystemError(errno, _("dnsmasq binary %s is not executable"), - caps->binaryPath); - goto cleanup; - } - - cmd = virCommandNewArgList(caps->binaryPath, "--version", NULL); - virCommandSetOutputBuffer(cmd, &version); - virCommandAddEnvPassCommon(cmd); - virCommandClearCaps(cmd); - if (virCommandRun(cmd, NULL) < 0) { - virReportSystemError(errno, _("failed to run '%s --version': %s"), - caps->binaryPath, version); - goto cleanup; - } - virCommandFree(cmd); - - cmd = virCommandNewArgList(caps->binaryPath, "--help", NULL); - virCommandSetOutputBuffer(cmd, &help); - virCommandAddEnvPassCommon(cmd); - virCommandClearCaps(cmd); - if (virCommandRun(cmd, NULL) < 0) { - virReportSystemError(errno, _("failed to run '%s --help': %s"), - caps->binaryPath, help); - goto cleanup; - } - - if (virAsprintf(&complete, "%s\n%s", version, help) < 0) { - virReportOOMError(); - goto cleanup; - } - - ret = dnsmasqCapsSetFromBuffer(caps, complete); - -cleanup: - virCommandFree(cmd); - VIR_FREE(help); - VIR_FREE(version); - VIR_FREE(complete); - return ret; -} - -static dnsmasqCapsPtr -dnsmasqCapsNewEmpty(const char *binaryPath) -{ - dnsmasqCapsPtr caps; - - if (dnsmasqCapsInitialize() < 0) - return NULL; - if (!(caps = virObjectNew(dnsmasqCapsClass))) - return NULL; - if (!(caps->flags = virBitmapNew(DNSMASQ_CAPS_LAST))) - goto error; - if (!(caps->binaryPath = strdup(binaryPath ? binaryPath : DNSMASQ))) - goto error; - return caps; - -error: - virReportOOMError(); - virObjectUnref(caps); - return NULL; -} - -dnsmasqCapsPtr -dnsmasqCapsNewFromBuffer(const char *buf, const char *binaryPath) -{ - dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); - - if (!caps) - return NULL; - - if (dnsmasqCapsSetFromBuffer(caps, buf) < 0) { - virObjectUnref(caps); - return NULL; - } - return caps; -} - -dnsmasqCapsPtr -dnsmasqCapsNewFromFile(const char *dataPath, const char *binaryPath) -{ - dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); - - if (!caps) - return NULL; - - if (dnsmasqCapsSetFromFile(caps, dataPath) < 0) { - virObjectUnref(caps); - return NULL; - } - return caps; -} - -dnsmasqCapsPtr -dnsmasqCapsNewFromBinary(const char *binaryPath) -{ - dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); - - if (!caps) - return NULL; - - if (dnsmasqCapsRefreshInternal(caps, true) < 0) { - virObjectUnref(caps); - return NULL; - } - return caps; -} - -/** dnsmasqCapsRefresh: - * - * Refresh an existing caps object if the binary has changed. If - * there isn't yet a caps object (if it's NULL), create a new one. - * - * Returns 0 on success, -1 on failure - */ -int -dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath) -{ - if (!*caps) { - *caps = dnsmasqCapsNewFromBinary(binaryPath); - return *caps ? 0 : -1; - } - return dnsmasqCapsRefreshInternal(*caps, false); -} - -const char * -dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps) -{ - return caps ? caps->binaryPath : DNSMASQ; -} - -unsigned long -dnsmasqCapsGetVersion(dnsmasqCapsPtr caps) -{ - if (caps) - return caps->version; - else - return 0; -} - -bool -dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag) -{ - bool b; - - if (!caps || virBitmapGetBit(caps->flags, flag, &b) < 0) - return false; - else - return b; -} diff --git a/src/util/dnsmasq.h b/src/util/dnsmasq.h deleted file mode 100644 index 7a39232..0000000 --- a/src/util/dnsmasq.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2007-2012 Red Hat, Inc. - * Copyright (C) 2010 Satoru SATOH <satoru.satoh@gmail.com> - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * based on iptables.h - */ - -#ifndef __DNSMASQ_H__ -# define __DNSMASQ_H__ - -# include "virobject.h" -# include "virsocketaddr.h" - -typedef struct -{ - /* - * Each entry holds a string, "<mac_addr>,<hostname>,<ip_addr>" such as - * "01:23:45:67:89:0a,foo,10.0.0.3". - */ - char *host; - -} dnsmasqDhcpHost; - -typedef struct -{ - unsigned int nhosts; - dnsmasqDhcpHost *hosts; - - char *path; /* Absolute path of dnsmasq's hostsfile. */ -} dnsmasqHostsfile; - -typedef struct -{ - unsigned int nhostnames; - char *ip; - char **hostnames; - -} dnsmasqAddnHost; - -typedef struct -{ - unsigned int nhosts; - dnsmasqAddnHost *hosts; - - char *path; /* Absolute path of dnsmasq's hostsfile. */ -} dnsmasqAddnHostsfile; - -typedef struct -{ - char *config_dir; - dnsmasqHostsfile *hostsfile; - dnsmasqAddnHostsfile *addnhostsfile; -} dnsmasqContext; - -typedef enum { - DNSMASQ_CAPS_BIND_DYNAMIC = 0, /* support for --bind-dynamic */ - - DNSMASQ_CAPS_LAST, /* this must always be the last item */ -} dnsmasqCapsFlags; - -typedef struct _dnsmasqCaps dnsmasqCaps; -typedef dnsmasqCaps *dnsmasqCapsPtr; - - -dnsmasqContext * dnsmasqContextNew(const char *network_name, - const char *config_dir); -void dnsmasqContextFree(dnsmasqContext *ctx); -int dnsmasqAddDhcpHost(dnsmasqContext *ctx, - const char *mac, - virSocketAddr *ip, - const char *name, - bool ipv6); -int dnsmasqAddHost(dnsmasqContext *ctx, - virSocketAddr *ip, - const char *name); -int dnsmasqSave(const dnsmasqContext *ctx); -int dnsmasqDelete(const dnsmasqContext *ctx); -int dnsmasqReload(pid_t pid); - -dnsmasqCapsPtr dnsmasqCapsNewFromBuffer(const char *buf, - const char *binaryPath); -dnsmasqCapsPtr dnsmasqCapsNewFromFile(const char *dataPath, - const char *binaryPath); -dnsmasqCapsPtr dnsmasqCapsNewFromBinary(const char *binaryPath); -int dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath); -bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag); -const char *dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps); -unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps); - -# define DNSMASQ_DHCPv6_MAJOR_REQD 2 -# define DNSMASQ_DHCPv6_MINOR_REQD 64 -# define DNSMASQ_RA_MAJOR_REQD 2 -# define DNSMASQ_RA_MINOR_REQD 64 - -# define DNSMASQ_DHCPv6_SUPPORT(CAPS) \ - (dnsmasqCapsGetVersion(CAPS) >= \ - (DNSMASQ_DHCPv6_MAJOR_REQD * 1000000) + \ - (DNSMASQ_DHCPv6_MINOR_REQD * 1000)) -# define DNSMASQ_RA_SUPPORT(CAPS) \ - (dnsmasqCapsGetVersion(CAPS) >= \ - (DNSMASQ_RA_MAJOR_REQD * 1000000) + \ - (DNSMASQ_RA_MINOR_REQD * 1000)) -#endif /* __DNSMASQ_H__ */ diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c new file mode 100644 index 0000000..4a32f49 --- /dev/null +++ b/src/util/virdnsmasq.c @@ -0,0 +1,872 @@ +/* + * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2010 Satoru SATOH <satoru.satoh@gmail.com> + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Based on iptables.c + */ + +#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> +#include <signal.h> + +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif + +#include "internal.h" +#include "datatypes.h" +#include "virbitmap.h" +#include "virdnsmasq.h" +#include "util.h" +#include "vircommand.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" +#include "virfile.h" + +#define VIR_FROM_THIS VIR_FROM_NETWORK +#define DNSMASQ_HOSTSFILE_SUFFIX "hostsfile" +#define DNSMASQ_ADDNHOSTSFILE_SUFFIX "addnhosts" + +static void +dhcphostFree(dnsmasqDhcpHost *host) +{ + VIR_FREE(host->host); +} + +static void +addnhostFree(dnsmasqAddnHost *host) +{ + int i; + + for (i = 0; i < host->nhostnames; i++) + VIR_FREE(host->hostnames[i]); + VIR_FREE(host->hostnames); + VIR_FREE(host->ip); +} + +static void +addnhostsFree(dnsmasqAddnHostsfile *addnhostsfile) +{ + unsigned int i; + + if (addnhostsfile->hosts) { + for (i = 0; i < addnhostsfile->nhosts; i++) + addnhostFree(&addnhostsfile->hosts[i]); + + VIR_FREE(addnhostsfile->hosts); + + addnhostsfile->nhosts = 0; + } + + VIR_FREE(addnhostsfile->path); + + VIR_FREE(addnhostsfile); +} + +static int +addnhostsAdd(dnsmasqAddnHostsfile *addnhostsfile, + virSocketAddr *ip, + const char *name) +{ + char *ipstr = NULL; + int idx = -1; + int i; + + if (!(ipstr = virSocketAddrFormat(ip))) + return -1; + + for (i = 0; i < addnhostsfile->nhosts; i++) { + if (STREQ((const char *)addnhostsfile->hosts[i].ip, (const char *)ipstr)) { + idx = i; + break; + } + } + + if (idx < 0) { + if (VIR_REALLOC_N(addnhostsfile->hosts, addnhostsfile->nhosts + 1) < 0) + goto alloc_error; + + idx = addnhostsfile->nhosts; + if (VIR_ALLOC(addnhostsfile->hosts[idx].hostnames) < 0) + goto alloc_error; + + if (virAsprintf(&addnhostsfile->hosts[idx].ip, "%s", ipstr) < 0) + goto alloc_error; + + addnhostsfile->hosts[idx].nhostnames = 0; + addnhostsfile->nhosts++; + } + + if (VIR_REALLOC_N(addnhostsfile->hosts[idx].hostnames, addnhostsfile->hosts[idx].nhostnames + 1) < 0) + goto alloc_error; + + if (virAsprintf(&addnhostsfile->hosts[idx].hostnames[addnhostsfile->hosts[idx].nhostnames], "%s", name) < 0) + goto alloc_error; + + VIR_FREE(ipstr); + + addnhostsfile->hosts[idx].nhostnames++; + + return 0; + + alloc_error: + virReportOOMError(); + VIR_FREE(ipstr); + return -1; +} + +static dnsmasqAddnHostsfile * +addnhostsNew(const char *name, + const char *config_dir) +{ + dnsmasqAddnHostsfile *addnhostsfile; + + if (VIR_ALLOC(addnhostsfile) < 0) { + virReportOOMError(); + return NULL; + } + + addnhostsfile->hosts = NULL; + addnhostsfile->nhosts = 0; + + if (virAsprintf(&addnhostsfile->path, "%s/%s.%s", config_dir, name, + DNSMASQ_ADDNHOSTSFILE_SUFFIX) < 0) { + virReportOOMError(); + goto error; + } + + return addnhostsfile; + + error: + addnhostsFree(addnhostsfile); + return NULL; +} + +static int +addnhostsWrite(const char *path, + dnsmasqAddnHost *hosts, + unsigned int nhosts) +{ + char *tmp; + FILE *f; + bool istmp = true; + unsigned int i, ii; + int rc = 0; + + /* even if there are 0 hosts, create a 0 length file, to allow + * for runtime addition. + */ + + if (virAsprintf(&tmp, "%s.new", path) < 0) + return -ENOMEM; + + if (!(f = fopen(tmp, "w"))) { + istmp = false; + if (!(f = fopen(path, "w"))) { + rc = -errno; + goto cleanup; + } + } + + for (i = 0; i < nhosts; i++) { + if (fputs(hosts[i].ip, f) == EOF || fputc('\t', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + + for (ii = 0; ii < hosts[i].nhostnames; ii++) { + if (fputs(hosts[i].hostnames[ii], f) == EOF || fputc('\t', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + } + + if (fputc('\n', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + } + + if (VIR_FCLOSE(f) == EOF) { + rc = -errno; + goto cleanup; + } + + if (istmp && rename(tmp, path) < 0) { + rc = -errno; + unlink(tmp); + goto cleanup; + } + + cleanup: + VIR_FREE(tmp); + + return rc; +} + +static int +addnhostsSave(dnsmasqAddnHostsfile *addnhostsfile) +{ + int err = addnhostsWrite(addnhostsfile->path, addnhostsfile->hosts, + addnhostsfile->nhosts); + + if (err < 0) { + virReportSystemError(-err, _("cannot write config file '%s'"), + addnhostsfile->path); + return -1; + } + + return 0; +} + +static int +genericFileDelete(char *path) +{ + if (!virFileExists(path)) + return 0; + + if (unlink(path) < 0) { + virReportSystemError(errno, _("cannot remove config file '%s'"), + path); + return -1; + } + + return 0; +} + +static void +hostsfileFree(dnsmasqHostsfile *hostsfile) +{ + unsigned int i; + + if (hostsfile->hosts) { + for (i = 0; i < hostsfile->nhosts; i++) + dhcphostFree(&hostsfile->hosts[i]); + + VIR_FREE(hostsfile->hosts); + + hostsfile->nhosts = 0; + } + + VIR_FREE(hostsfile->path); + + VIR_FREE(hostsfile); +} + +/* Note: There are many additional dhcp-host specifications + * supported by dnsmasq. There are only the basic ones. + */ +static int +hostsfileAdd(dnsmasqHostsfile *hostsfile, + const char *mac, + virSocketAddr *ip, + const char *name, + bool ipv6) +{ + char *ipstr = NULL; + if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0) + goto alloc_error; + + if (!(ipstr = virSocketAddrFormat(ip))) + return -1; + + /* the first test determines if it is a dhcpv6 host */ + if (ipv6) { + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,[%s]", + name, ipstr) < 0) + goto alloc_error; + } + else if (name && mac) { + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s", + mac, ipstr, name) < 0) + goto alloc_error; + } else if (name && !mac){ + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", + name, ipstr) < 0) + goto alloc_error; + } else { + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s", + mac, ipstr) < 0) + goto alloc_error; + } + VIR_FREE(ipstr); + + hostsfile->nhosts++; + + return 0; + + alloc_error: + virReportOOMError(); + VIR_FREE(ipstr); + return -1; +} + +static dnsmasqHostsfile * +hostsfileNew(const char *name, + const char *config_dir) +{ + dnsmasqHostsfile *hostsfile; + + if (VIR_ALLOC(hostsfile) < 0) { + virReportOOMError(); + return NULL; + } + + hostsfile->hosts = NULL; + hostsfile->nhosts = 0; + + if (virAsprintf(&hostsfile->path, "%s/%s.%s", config_dir, name, + DNSMASQ_HOSTSFILE_SUFFIX) < 0) { + virReportOOMError(); + goto error; + } + + return hostsfile; + + error: + hostsfileFree(hostsfile); + return NULL; +} + +static int +hostsfileWrite(const char *path, + dnsmasqDhcpHost *hosts, + unsigned int nhosts) +{ + char *tmp; + FILE *f; + bool istmp = true; + unsigned int i; + int rc = 0; + + /* even if there are 0 hosts, create a 0 length file, to allow + * for runtime addition. + */ + + if (virAsprintf(&tmp, "%s.new", path) < 0) + return -ENOMEM; + + if (!(f = fopen(tmp, "w"))) { + istmp = false; + if (!(f = fopen(path, "w"))) { + rc = -errno; + goto cleanup; + } + } + + for (i = 0; i < nhosts; i++) { + if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) { + rc = -errno; + VIR_FORCE_FCLOSE(f); + + if (istmp) + unlink(tmp); + + goto cleanup; + } + } + + if (VIR_FCLOSE(f) == EOF) { + rc = -errno; + goto cleanup; + } + + if (istmp && rename(tmp, path) < 0) { + rc = -errno; + unlink(tmp); + goto cleanup; + } + + cleanup: + VIR_FREE(tmp); + + return rc; +} + +static int +hostsfileSave(dnsmasqHostsfile *hostsfile) +{ + int err = hostsfileWrite(hostsfile->path, hostsfile->hosts, + hostsfile->nhosts); + + if (err < 0) { + virReportSystemError(-err, _("cannot write config file '%s'"), + hostsfile->path); + return -1; + } + + return 0; +} + +/** + * dnsmasqContextNew: + * + * Create a new Dnsmasq context + * + * Returns a pointer to the new structure or NULL in case of error + */ +dnsmasqContext * +dnsmasqContextNew(const char *network_name, + const char *config_dir) +{ + dnsmasqContext *ctx; + + if (VIR_ALLOC(ctx) < 0) { + virReportOOMError(); + return NULL; + } + + if (!(ctx->config_dir = strdup(config_dir))) { + virReportOOMError(); + goto error; + } + + if (!(ctx->hostsfile = hostsfileNew(network_name, config_dir))) + goto error; + if (!(ctx->addnhostsfile = addnhostsNew(network_name, config_dir))) + goto error; + + return ctx; + + error: + dnsmasqContextFree(ctx); + return NULL; +} + +/** + * dnsmasqContextFree: + * @ctx: pointer to the dnsmasq context + * + * Free the resources associated with a dnsmasq context + */ +void +dnsmasqContextFree(dnsmasqContext *ctx) +{ + if (!ctx) + return; + + VIR_FREE(ctx->config_dir); + + if (ctx->hostsfile) + hostsfileFree(ctx->hostsfile); + if (ctx->addnhostsfile) + addnhostsFree(ctx->addnhostsfile); + + VIR_FREE(ctx); +} + +/** + * dnsmasqAddDhcpHost: + * @ctx: pointer to the dnsmasq context for each network + * @mac: pointer to the string contains mac address of the host + * @ip: pointer to the socket address contains ip of the host + * @name: pointer to the string contains hostname of the host or NULL + * + * Add dhcp-host entry. + */ +int +dnsmasqAddDhcpHost(dnsmasqContext *ctx, + const char *mac, + virSocketAddr *ip, + const char *name, + bool ipv6) +{ + return hostsfileAdd(ctx->hostsfile, mac, ip, name, ipv6); +} + +/* + * dnsmasqAddHost: + * @ctx: pointer to the dnsmasq context for each network + * @ip: pointer to the socket address contains ip of the host + * @name: pointer to the string contains hostname of the host + * + * Add additional host entry. + */ + +int +dnsmasqAddHost(dnsmasqContext *ctx, + virSocketAddr *ip, + const char *name) +{ + return addnhostsAdd(ctx->addnhostsfile, ip, name); +} + +/** + * dnsmasqSave: + * @ctx: pointer to the dnsmasq context for each network + * + * Saves all the configurations associated with a context to disk. + */ +int +dnsmasqSave(const dnsmasqContext *ctx) +{ + int ret = 0; + + if (virFileMakePath(ctx->config_dir) < 0) { + virReportSystemError(errno, _("cannot create config directory '%s'"), + ctx->config_dir); + return -1; + } + + if (ctx->hostsfile) + ret = hostsfileSave(ctx->hostsfile); + if (ret == 0) { + if (ctx->addnhostsfile) + ret = addnhostsSave(ctx->addnhostsfile); + } + + return ret; +} + + +/** + * dnsmasqDelete: + * @ctx: pointer to the dnsmasq context for each network + * + * Delete all the configuration files associated with a context. + */ +int +dnsmasqDelete(const dnsmasqContext *ctx) +{ + int ret = 0; + + if (ctx->hostsfile) + ret = genericFileDelete(ctx->hostsfile->path); + if (ctx->addnhostsfile) + ret = genericFileDelete(ctx->addnhostsfile->path); + + return ret; +} + +/** + * dnsmasqReload: + * @pid: the pid of the target dnsmasq process + * + * Reloads all the configurations associated to a context + */ +int +dnsmasqReload(pid_t pid ATTRIBUTE_UNUSED) +{ +#ifndef WIN32 + if (kill(pid, SIGHUP) != 0) { + virReportSystemError(errno, + _("Failed to make dnsmasq (PID: %d) reload config files."), + pid); + return -1; + } +#endif /* WIN32 */ + + return 0; +} + +/* + * dnsmasqCapabilities functions - provide useful information about the + * version of dnsmasq on this machine. + * + */ +struct _dnsmasqCaps { + virObject object; + char *binaryPath; + bool noRefresh; + time_t mtime; + virBitmapPtr flags; + unsigned long version; +}; + +static virClassPtr dnsmasqCapsClass; + +static void +dnsmasqCapsDispose(void *obj) +{ + dnsmasqCapsPtr caps = obj; + + virBitmapFree(caps->flags); + VIR_FREE(caps->binaryPath); +} + +static int dnsmasqCapsOnceInit(void) +{ + if (!(dnsmasqCapsClass = virClassNew("dnsmasqCaps", + sizeof(dnsmasqCaps), + dnsmasqCapsDispose))) { + return -1; + } + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(dnsmasqCaps) + +static void +dnsmasqCapsSet(dnsmasqCapsPtr caps, + dnsmasqCapsFlags flag) +{ + ignore_value(virBitmapSetBit(caps->flags, flag)); +} + + +#define DNSMASQ_VERSION_STR "Dnsmasq version " + +static int +dnsmasqCapsSetFromBuffer(dnsmasqCapsPtr caps, const char *buf) +{ + const char *p; + + caps->noRefresh = true; + + p = STRSKIP(buf, DNSMASQ_VERSION_STR); + if (!p) + goto fail; + virSkipSpaces(&p); + if (virParseVersionString(p, &caps->version, true) < 0) + goto fail; + + if (strstr(buf, "--bind-dynamic")) + dnsmasqCapsSet(caps, DNSMASQ_CAPS_BIND_DYNAMIC); + + VIR_INFO("dnsmasq version is %d.%d, --bind-dynamic is %s", + (int)caps->version / 1000000, (int)(caps->version % 1000000) / 1000, + dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC) + ? "present" : "NOT present"); + return 0; + +fail: + p = strchrnul(buf, '\n'); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse %s version number in '%.*s'"), + caps->binaryPath, (int) (p - buf), buf); + return -1; + +} + +static int +dnsmasqCapsSetFromFile(dnsmasqCapsPtr caps, const char *path) +{ + int ret = -1; + char *buf = NULL; + + if (virFileReadAll(path, 1024 * 1024, &buf) < 0) + goto cleanup; + + ret = dnsmasqCapsSetFromBuffer(caps, buf); + +cleanup: + VIR_FREE(buf); + return ret; +} + +static int +dnsmasqCapsRefreshInternal(dnsmasqCapsPtr caps, bool force) +{ + int ret = -1; + struct stat sb; + virCommandPtr cmd = NULL; + char *help = NULL, *version = NULL, *complete = NULL; + + if (!caps || caps->noRefresh) + return 0; + + if (stat(caps->binaryPath, &sb) < 0) { + virReportSystemError(errno, _("Cannot check dnsmasq binary %s"), + caps->binaryPath); + return -1; + } + if (!force && caps->mtime == sb.st_mtime) { + return 0; + } + caps->mtime = sb.st_mtime; + + /* Make sure the binary we are about to try exec'ing exists. + * Technically we could catch the exec() failure, but that's + * in a sub-process so it's hard to feed back a useful error. + */ + if (!virFileIsExecutable(caps->binaryPath)) { + virReportSystemError(errno, _("dnsmasq binary %s is not executable"), + caps->binaryPath); + goto cleanup; + } + + cmd = virCommandNewArgList(caps->binaryPath, "--version", NULL); + virCommandSetOutputBuffer(cmd, &version); + virCommandAddEnvPassCommon(cmd); + virCommandClearCaps(cmd); + if (virCommandRun(cmd, NULL) < 0) { + virReportSystemError(errno, _("failed to run '%s --version': %s"), + caps->binaryPath, version); + goto cleanup; + } + virCommandFree(cmd); + + cmd = virCommandNewArgList(caps->binaryPath, "--help", NULL); + virCommandSetOutputBuffer(cmd, &help); + virCommandAddEnvPassCommon(cmd); + virCommandClearCaps(cmd); + if (virCommandRun(cmd, NULL) < 0) { + virReportSystemError(errno, _("failed to run '%s --help': %s"), + caps->binaryPath, help); + goto cleanup; + } + + if (virAsprintf(&complete, "%s\n%s", version, help) < 0) { + virReportOOMError(); + goto cleanup; + } + + ret = dnsmasqCapsSetFromBuffer(caps, complete); + +cleanup: + virCommandFree(cmd); + VIR_FREE(help); + VIR_FREE(version); + VIR_FREE(complete); + return ret; +} + +static dnsmasqCapsPtr +dnsmasqCapsNewEmpty(const char *binaryPath) +{ + dnsmasqCapsPtr caps; + + if (dnsmasqCapsInitialize() < 0) + return NULL; + if (!(caps = virObjectNew(dnsmasqCapsClass))) + return NULL; + if (!(caps->flags = virBitmapNew(DNSMASQ_CAPS_LAST))) + goto error; + if (!(caps->binaryPath = strdup(binaryPath ? binaryPath : DNSMASQ))) + goto error; + return caps; + +error: + virReportOOMError(); + virObjectUnref(caps); + return NULL; +} + +dnsmasqCapsPtr +dnsmasqCapsNewFromBuffer(const char *buf, const char *binaryPath) +{ + dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); + + if (!caps) + return NULL; + + if (dnsmasqCapsSetFromBuffer(caps, buf) < 0) { + virObjectUnref(caps); + return NULL; + } + return caps; +} + +dnsmasqCapsPtr +dnsmasqCapsNewFromFile(const char *dataPath, const char *binaryPath) +{ + dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); + + if (!caps) + return NULL; + + if (dnsmasqCapsSetFromFile(caps, dataPath) < 0) { + virObjectUnref(caps); + return NULL; + } + return caps; +} + +dnsmasqCapsPtr +dnsmasqCapsNewFromBinary(const char *binaryPath) +{ + dnsmasqCapsPtr caps = dnsmasqCapsNewEmpty(binaryPath); + + if (!caps) + return NULL; + + if (dnsmasqCapsRefreshInternal(caps, true) < 0) { + virObjectUnref(caps); + return NULL; + } + return caps; +} + +/** dnsmasqCapsRefresh: + * + * Refresh an existing caps object if the binary has changed. If + * there isn't yet a caps object (if it's NULL), create a new one. + * + * Returns 0 on success, -1 on failure + */ +int +dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath) +{ + if (!*caps) { + *caps = dnsmasqCapsNewFromBinary(binaryPath); + return *caps ? 0 : -1; + } + return dnsmasqCapsRefreshInternal(*caps, false); +} + +const char * +dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps) +{ + return caps ? caps->binaryPath : DNSMASQ; +} + +unsigned long +dnsmasqCapsGetVersion(dnsmasqCapsPtr caps) +{ + if (caps) + return caps->version; + else + return 0; +} + +bool +dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag) +{ + bool b; + + if (!caps || virBitmapGetBit(caps->flags, flag, &b) < 0) + return false; + else + return b; +} diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h new file mode 100644 index 0000000..7a39232 --- /dev/null +++ b/src/util/virdnsmasq.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2010 Satoru SATOH <satoru.satoh@gmail.com> + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * based on iptables.h + */ + +#ifndef __DNSMASQ_H__ +# define __DNSMASQ_H__ + +# include "virobject.h" +# include "virsocketaddr.h" + +typedef struct +{ + /* + * Each entry holds a string, "<mac_addr>,<hostname>,<ip_addr>" such as + * "01:23:45:67:89:0a,foo,10.0.0.3". + */ + char *host; + +} dnsmasqDhcpHost; + +typedef struct +{ + unsigned int nhosts; + dnsmasqDhcpHost *hosts; + + char *path; /* Absolute path of dnsmasq's hostsfile. */ +} dnsmasqHostsfile; + +typedef struct +{ + unsigned int nhostnames; + char *ip; + char **hostnames; + +} dnsmasqAddnHost; + +typedef struct +{ + unsigned int nhosts; + dnsmasqAddnHost *hosts; + + char *path; /* Absolute path of dnsmasq's hostsfile. */ +} dnsmasqAddnHostsfile; + +typedef struct +{ + char *config_dir; + dnsmasqHostsfile *hostsfile; + dnsmasqAddnHostsfile *addnhostsfile; +} dnsmasqContext; + +typedef enum { + DNSMASQ_CAPS_BIND_DYNAMIC = 0, /* support for --bind-dynamic */ + + DNSMASQ_CAPS_LAST, /* this must always be the last item */ +} dnsmasqCapsFlags; + +typedef struct _dnsmasqCaps dnsmasqCaps; +typedef dnsmasqCaps *dnsmasqCapsPtr; + + +dnsmasqContext * dnsmasqContextNew(const char *network_name, + const char *config_dir); +void dnsmasqContextFree(dnsmasqContext *ctx); +int dnsmasqAddDhcpHost(dnsmasqContext *ctx, + const char *mac, + virSocketAddr *ip, + const char *name, + bool ipv6); +int dnsmasqAddHost(dnsmasqContext *ctx, + virSocketAddr *ip, + const char *name); +int dnsmasqSave(const dnsmasqContext *ctx); +int dnsmasqDelete(const dnsmasqContext *ctx); +int dnsmasqReload(pid_t pid); + +dnsmasqCapsPtr dnsmasqCapsNewFromBuffer(const char *buf, + const char *binaryPath); +dnsmasqCapsPtr dnsmasqCapsNewFromFile(const char *dataPath, + const char *binaryPath); +dnsmasqCapsPtr dnsmasqCapsNewFromBinary(const char *binaryPath); +int dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath); +bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag); +const char *dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps); +unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps); + +# define DNSMASQ_DHCPv6_MAJOR_REQD 2 +# define DNSMASQ_DHCPv6_MINOR_REQD 64 +# define DNSMASQ_RA_MAJOR_REQD 2 +# define DNSMASQ_RA_MINOR_REQD 64 + +# define DNSMASQ_DHCPv6_SUPPORT(CAPS) \ + (dnsmasqCapsGetVersion(CAPS) >= \ + (DNSMASQ_DHCPv6_MAJOR_REQD * 1000000) + \ + (DNSMASQ_DHCPv6_MINOR_REQD * 1000)) +# define DNSMASQ_RA_SUPPORT(CAPS) \ + (dnsmasqCapsGetVersion(CAPS) >= \ + (DNSMASQ_RA_MAJOR_REQD * 1000000) + \ + (DNSMASQ_RA_MINOR_REQD * 1000)) +#endif /* __DNSMASQ_H__ */ -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- src/Makefile.am | 2 +- src/qemu/qemu_bridge_filter.c | 2 +- src/qemu/qemu_conf.h | 2 +- src/util/ebtables.c | 486 ------------------------------------------ src/util/ebtables.h | 67 ------ src/util/virebtables.c | 486 ++++++++++++++++++++++++++++++++++++++++++ src/util/virebtables.h | 67 ++++++ 7 files changed, 556 insertions(+), 556 deletions(-) delete mode 100644 src/util/ebtables.c delete mode 100644 src/util/ebtables.h create mode 100644 src/util/virebtables.c create mode 100644 src/util/virebtables.h diff --git a/src/Makefile.am b/src/Makefile.am index ce16e87..daefa95 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -57,7 +57,6 @@ UTIL_SOURCES = \ util/event_poll.c util/event_poll.h \ util/hooks.c util/hooks.h \ util/iptables.c util/iptables.h \ - util/ebtables.c util/ebtables.h \ util/json.c util/json.h \ util/logging.c util/logging.h \ util/memory.c util/memory.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/vircommand.c util/vircommand.h \ util/virconf.c util/virconf.h \ util/virdnsmasq.c util/virdnsmasq.h \ + util/virebtables.c util/virebtables.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/qemu/qemu_bridge_filter.c b/src/qemu/qemu_bridge_filter.c index a34a92e..a6d0d4f 100644 --- a/src/qemu/qemu_bridge_filter.c +++ b/src/qemu/qemu_bridge_filter.c @@ -22,7 +22,7 @@ #include <config.h> -#include "ebtables.h" +#include "virebtables.h" #include "qemu_conf.h" #include "qemu_driver.h" #include "util.h" diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index eafaf9f..5499203 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -26,7 +26,7 @@ # include <config.h> -# include "ebtables.h" +# include "virebtables.h" # include "internal.h" # include "capabilities.h" # include "network_conf.h" diff --git a/src/util/ebtables.c b/src/util/ebtables.c deleted file mode 100644 index 4b427ee..0000000 --- a/src/util/ebtables.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (C) 2007-2012 Red Hat, Inc. - * Copyright (C) 2009 IBM Corp. - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * based on iptables.c - * Authors: - * Gerhard Stenzel <gerhard.stenzel@de.ibm.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> -#include <sys/wait.h> - -#ifdef HAVE_PATHS_H -# include <paths.h> -#endif - -#include "internal.h" -#include "ebtables.h" -#include "vircommand.h" -#include "memory.h" -#include "virterror_internal.h" -#include "logging.h" -#include "threads.h" - -#if HAVE_FIREWALLD -static char *firewall_cmd_path = NULL; - -static int -virEbTablesOnceInit(void) -{ - firewall_cmd_path = virFindFileInPath("firewall-cmd"); - if (!firewall_cmd_path) { - VIR_INFO("firewall-cmd not found on system. " - "firewalld support disabled for ebtables."); - } else { - virCommandPtr cmd = virCommandNew(firewall_cmd_path); - int status; - - virCommandAddArgList(cmd, "--state", NULL); - if (virCommandRun(cmd, &status) < 0 || status != 0) { - VIR_INFO("firewall-cmd found but disabled for ebtables"); - VIR_FREE(firewall_cmd_path); - firewall_cmd_path = NULL; - } else { - VIR_INFO("using firewalld for ebtables commands"); - } - virCommandFree(cmd); - } - return 0; -} - -VIR_ONCE_GLOBAL_INIT(virEbTables) - -#endif - -struct _ebtablesContext -{ - ebtRules *input_filter; - ebtRules *forward_filter; - ebtRules *nat_postrouting; -}; - -enum { - ADD = 0, - REMOVE, - CREATE, - POLICY, - INSERT -}; - -static void -ebtRuleFree(ebtRule *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 -ebtRulesAppend(ebtRules *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 -ebtRulesRemove(ebtRules *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; - - ebtRuleFree(&rules->rules[i]); - - memmove(&rules->rules[i], - &rules->rules[i+1], - (rules->nrules - i - 1) * sizeof(ebtRule)); - - rules->nrules--; - - return 0; -} - -static void -ebtRulesFree(ebtRules *rules) -{ - int i; - - VIR_FREE(rules->table); - VIR_FREE(rules->chain); - - if (rules->rules) { - for (i = 0; i < rules->nrules; i++) - ebtRuleFree(&rules->rules[i]); - - VIR_FREE(rules->rules); - - rules->nrules = 0; - } - - VIR_FREE(rules); -} - -static ebtRules * -ebtRulesNew(const char *table, - const char *chain) -{ - ebtRules *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; - - return rules; - - error: - ebtRulesFree(rules); - return NULL; -} - -static int ATTRIBUTE_SENTINEL -ebtablesAddRemoveRule(ebtRules *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/ebtables */ - 2 + /* --table foo */ - 2 + /* --insert bar */ - 1; /* arg */ - -#if HAVE_FIREWALLD - virEbTablesInitialize(); - if (firewall_cmd_path) - n += 3; /* --direct --passthrough eb */ -#endif - - 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 HAVE_FIREWALLD - if (firewall_cmd_path) { - if (!(argv[n++] = strdup(firewall_cmd_path))) - goto error; - if (!(argv[n++] = strdup("--direct"))) - goto error; - if (!(argv[n++] = strdup("--passthrough"))) - goto error; - if (!(argv[n++] = strdup("eb"))) - goto error; - } else -#endif - if (!(argv[n++] = strdup(EBTABLES_PATH))) - goto error; - - command_idx = n; - - if (action == ADD || action == REMOVE) { - 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))) { - va_end(args); - 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(argv, NULL) < 0) { - retval = errno; - goto error; - } - - if (action == ADD || action == CREATE || action == POLICY || - action == INSERT) { - retval = ebtRulesAppend(rules, rule, argv, command_idx); - rule = NULL; - argv = NULL; - } else { - retval = ebtRulesRemove(rules, rule); - } - - error: - VIR_FREE(rule); - - if (argv) { - n = 0; - while (argv[n]) - VIR_FREE(argv[n++]); - VIR_FREE(argv); - } - - return retval; -} - - -/** - * ebtablesContextNew: - * - * Create a new ebtable context - * - * Returns a pointer to the new structure or NULL in case of error - */ -ebtablesContext * -ebtablesContextNew(const char *driver) -{ - bool success = false; - ebtablesContext *ctx = NULL; - char *input_chain = NULL; - char *forward_chain = NULL; - char *nat_chain = NULL; - - if (VIR_ALLOC(ctx) < 0) - return NULL; - - if (virAsprintf(&input_chain, "libvirt_%s_INPUT", driver) < 0 || - virAsprintf(&forward_chain, "libvirt_%s_FORWARD", driver) < 0 || - virAsprintf(&nat_chain, "libvirt_%s_POSTROUTING", driver) < 0) { - goto cleanup; - } - - if (!(ctx->input_filter = ebtRulesNew("filter", input_chain))) - goto cleanup; - - if (!(ctx->forward_filter = ebtRulesNew("filter", forward_chain))) - goto cleanup; - - if (!(ctx->nat_postrouting = ebtRulesNew("nat", nat_chain))) - goto cleanup; - - success = true; - -cleanup: - VIR_FREE(input_chain); - VIR_FREE(forward_chain); - VIR_FREE(nat_chain); - - if (!success) { - ebtablesContextFree(ctx); - ctx = NULL; - } - - return ctx; -} - -/** - * ebtablesContextFree: - * @ctx: pointer to the EB table context - * - * Free the resources associated with an EB table context - */ -void -ebtablesContextFree(ebtablesContext *ctx) -{ - if (!ctx) - return; - if (ctx->input_filter) - ebtRulesFree(ctx->input_filter); - if (ctx->forward_filter) - ebtRulesFree(ctx->forward_filter); - if (ctx->nat_postrouting) - ebtRulesFree(ctx->nat_postrouting); - VIR_FREE(ctx); -} - -int -ebtablesAddForwardPolicyReject(ebtablesContext *ctx) -{ - return ebtablesForwardPolicyReject(ctx, ADD); -} - - -int -ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx) -{ - return ebtablesForwardPolicyReject(ctx, REMOVE); -} - -int -ebtablesForwardPolicyReject(ebtablesContext *ctx, - int action) -{ - /* create it, if it does not exist */ - if (action == ADD) { - ebtablesAddRemoveRule(ctx->forward_filter, - CREATE, - "--new-chain", ctx->forward_filter->chain, NULL, - NULL); - ebtablesAddRemoveRule(ctx->forward_filter, - INSERT, - "--insert", "FORWARD", "--jump", - ctx->forward_filter->chain, NULL); - } - - return ebtablesAddRemoveRule(ctx->forward_filter, - POLICY, - "-P", ctx->forward_filter->chain, "DROP", - NULL); -} - -/* - * Allow all traffic destined to the bridge, with a valid network address - */ -static int -ebtablesForwardAllowIn(ebtablesContext *ctx, - const char *iface, - const char *macaddr, - int action) -{ - return ebtablesAddRemoveRule(ctx->forward_filter, - action, - "--in-interface", iface, - "--source", macaddr, - "--jump", "ACCEPT", - NULL); -} - -/** - * ebtablesAddForwardAllowIn: - * @ctx: pointer to the EB table context - * @iface: the output interface name - * @physdev: the physical input device or NULL - * - * Add rules to the EB table context to allow the traffic on - * @physdev device to be forwarded to interface @iface. This allows - * the inbound traffic on a bridge. - * - * Returns 0 in case of success or an error code otherwise - */ -int -ebtablesAddForwardAllowIn(ebtablesContext *ctx, - const char *iface, - const virMacAddrPtr mac) -{ - char *macaddr; - - if (virAsprintf(&macaddr, - "%02x:%02x:%02x:%02x:%02x:%02x", - mac->addr[0], mac->addr[1], - mac->addr[2], mac->addr[3], - mac->addr[4], mac->addr[5]) < 0) { - return -1; - } - return ebtablesForwardAllowIn(ctx, iface, macaddr, ADD); -} - -/** - * ebtablesRemoveForwardAllowIn: - * @ctx: pointer to the EB table context - * @iface: the output interface name - * @physdev: the physical input device or NULL - * - * Remove rules from the EB table context hence forbidding the traffic - * on the @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 -ebtablesRemoveForwardAllowIn(ebtablesContext *ctx, - const char *iface, - const virMacAddrPtr mac) -{ - char *macaddr; - - if (virAsprintf(&macaddr, - "%02x:%02x:%02x:%02x:%02x:%02x", - mac->addr[0], mac->addr[1], - mac->addr[2], mac->addr[3], - mac->addr[4], mac->addr[5]) < 0) { - return -1; - } - return ebtablesForwardAllowIn(ctx, iface, macaddr, REMOVE); -} diff --git a/src/util/ebtables.h b/src/util/ebtables.h deleted file mode 100644 index 49dc8a0..0000000 --- a/src/util/ebtables.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2009 IBM Corp. - * 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, see - * <http://www.gnu.org/licenses/>. - * - * based on iptables.h - * Authors: - * Gerhard Stenzel <gerhard.stenzel@de.ibm.com> - */ - -#ifndef __QEMUD_EBTABLES_H__ -# define __QEMUD_EBTABLES_H__ - -# include "virmacaddr.h" - -typedef struct -{ - char *rule; - const char **argv; - int command_idx; -} ebtRule; - -typedef struct -{ - char *table; - char *chain; - - int nrules; - ebtRule *rules; - -} ebtRules; - -typedef struct _ebtablesContext ebtablesContext; - -ebtablesContext *ebtablesContextNew (const char *driver); -void ebtablesContextFree (ebtablesContext *ctx); - -void ebtablesSaveRules (ebtablesContext *ctx); - -int ebtablesAddForwardAllowIn (ebtablesContext *ctx, - const char *iface, - const virMacAddrPtr mac); -int ebtablesRemoveForwardAllowIn (ebtablesContext *ctx, - const char *iface, - const virMacAddrPtr mac); - -int ebtablesAddForwardPolicyReject(ebtablesContext *ctx); - -int ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx); - -int ebtablesForwardPolicyReject(ebtablesContext *ctx, - int action); - -#endif /* __QEMUD_ebtabLES_H__ */ diff --git a/src/util/virebtables.c b/src/util/virebtables.c new file mode 100644 index 0000000..8474b2a --- /dev/null +++ b/src/util/virebtables.c @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2009 IBM Corp. + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * based on iptables.c + * Authors: + * Gerhard Stenzel <gerhard.stenzel@de.ibm.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> +#include <sys/wait.h> + +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif + +#include "internal.h" +#include "virebtables.h" +#include "vircommand.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" +#include "threads.h" + +#if HAVE_FIREWALLD +static char *firewall_cmd_path = NULL; + +static int +virEbTablesOnceInit(void) +{ + firewall_cmd_path = virFindFileInPath("firewall-cmd"); + if (!firewall_cmd_path) { + VIR_INFO("firewall-cmd not found on system. " + "firewalld support disabled for ebtables."); + } else { + virCommandPtr cmd = virCommandNew(firewall_cmd_path); + int status; + + virCommandAddArgList(cmd, "--state", NULL); + if (virCommandRun(cmd, &status) < 0 || status != 0) { + VIR_INFO("firewall-cmd found but disabled for ebtables"); + VIR_FREE(firewall_cmd_path); + firewall_cmd_path = NULL; + } else { + VIR_INFO("using firewalld for ebtables commands"); + } + virCommandFree(cmd); + } + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virEbTables) + +#endif + +struct _ebtablesContext +{ + ebtRules *input_filter; + ebtRules *forward_filter; + ebtRules *nat_postrouting; +}; + +enum { + ADD = 0, + REMOVE, + CREATE, + POLICY, + INSERT +}; + +static void +ebtRuleFree(ebtRule *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 +ebtRulesAppend(ebtRules *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 +ebtRulesRemove(ebtRules *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; + + ebtRuleFree(&rules->rules[i]); + + memmove(&rules->rules[i], + &rules->rules[i+1], + (rules->nrules - i - 1) * sizeof(ebtRule)); + + rules->nrules--; + + return 0; +} + +static void +ebtRulesFree(ebtRules *rules) +{ + int i; + + VIR_FREE(rules->table); + VIR_FREE(rules->chain); + + if (rules->rules) { + for (i = 0; i < rules->nrules; i++) + ebtRuleFree(&rules->rules[i]); + + VIR_FREE(rules->rules); + + rules->nrules = 0; + } + + VIR_FREE(rules); +} + +static ebtRules * +ebtRulesNew(const char *table, + const char *chain) +{ + ebtRules *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; + + return rules; + + error: + ebtRulesFree(rules); + return NULL; +} + +static int ATTRIBUTE_SENTINEL +ebtablesAddRemoveRule(ebtRules *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/ebtables */ + 2 + /* --table foo */ + 2 + /* --insert bar */ + 1; /* arg */ + +#if HAVE_FIREWALLD + virEbTablesInitialize(); + if (firewall_cmd_path) + n += 3; /* --direct --passthrough eb */ +#endif + + 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 HAVE_FIREWALLD + if (firewall_cmd_path) { + if (!(argv[n++] = strdup(firewall_cmd_path))) + goto error; + if (!(argv[n++] = strdup("--direct"))) + goto error; + if (!(argv[n++] = strdup("--passthrough"))) + goto error; + if (!(argv[n++] = strdup("eb"))) + goto error; + } else +#endif + if (!(argv[n++] = strdup(EBTABLES_PATH))) + goto error; + + command_idx = n; + + if (action == ADD || action == REMOVE) { + 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))) { + va_end(args); + 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(argv, NULL) < 0) { + retval = errno; + goto error; + } + + if (action == ADD || action == CREATE || action == POLICY || + action == INSERT) { + retval = ebtRulesAppend(rules, rule, argv, command_idx); + rule = NULL; + argv = NULL; + } else { + retval = ebtRulesRemove(rules, rule); + } + + error: + VIR_FREE(rule); + + if (argv) { + n = 0; + while (argv[n]) + VIR_FREE(argv[n++]); + VIR_FREE(argv); + } + + return retval; +} + + +/** + * ebtablesContextNew: + * + * Create a new ebtable context + * + * Returns a pointer to the new structure or NULL in case of error + */ +ebtablesContext * +ebtablesContextNew(const char *driver) +{ + bool success = false; + ebtablesContext *ctx = NULL; + char *input_chain = NULL; + char *forward_chain = NULL; + char *nat_chain = NULL; + + if (VIR_ALLOC(ctx) < 0) + return NULL; + + if (virAsprintf(&input_chain, "libvirt_%s_INPUT", driver) < 0 || + virAsprintf(&forward_chain, "libvirt_%s_FORWARD", driver) < 0 || + virAsprintf(&nat_chain, "libvirt_%s_POSTROUTING", driver) < 0) { + goto cleanup; + } + + if (!(ctx->input_filter = ebtRulesNew("filter", input_chain))) + goto cleanup; + + if (!(ctx->forward_filter = ebtRulesNew("filter", forward_chain))) + goto cleanup; + + if (!(ctx->nat_postrouting = ebtRulesNew("nat", nat_chain))) + goto cleanup; + + success = true; + +cleanup: + VIR_FREE(input_chain); + VIR_FREE(forward_chain); + VIR_FREE(nat_chain); + + if (!success) { + ebtablesContextFree(ctx); + ctx = NULL; + } + + return ctx; +} + +/** + * ebtablesContextFree: + * @ctx: pointer to the EB table context + * + * Free the resources associated with an EB table context + */ +void +ebtablesContextFree(ebtablesContext *ctx) +{ + if (!ctx) + return; + if (ctx->input_filter) + ebtRulesFree(ctx->input_filter); + if (ctx->forward_filter) + ebtRulesFree(ctx->forward_filter); + if (ctx->nat_postrouting) + ebtRulesFree(ctx->nat_postrouting); + VIR_FREE(ctx); +} + +int +ebtablesAddForwardPolicyReject(ebtablesContext *ctx) +{ + return ebtablesForwardPolicyReject(ctx, ADD); +} + + +int +ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx) +{ + return ebtablesForwardPolicyReject(ctx, REMOVE); +} + +int +ebtablesForwardPolicyReject(ebtablesContext *ctx, + int action) +{ + /* create it, if it does not exist */ + if (action == ADD) { + ebtablesAddRemoveRule(ctx->forward_filter, + CREATE, + "--new-chain", ctx->forward_filter->chain, NULL, + NULL); + ebtablesAddRemoveRule(ctx->forward_filter, + INSERT, + "--insert", "FORWARD", "--jump", + ctx->forward_filter->chain, NULL); + } + + return ebtablesAddRemoveRule(ctx->forward_filter, + POLICY, + "-P", ctx->forward_filter->chain, "DROP", + NULL); +} + +/* + * Allow all traffic destined to the bridge, with a valid network address + */ +static int +ebtablesForwardAllowIn(ebtablesContext *ctx, + const char *iface, + const char *macaddr, + int action) +{ + return ebtablesAddRemoveRule(ctx->forward_filter, + action, + "--in-interface", iface, + "--source", macaddr, + "--jump", "ACCEPT", + NULL); +} + +/** + * ebtablesAddForwardAllowIn: + * @ctx: pointer to the EB table context + * @iface: the output interface name + * @physdev: the physical input device or NULL + * + * Add rules to the EB table context to allow the traffic on + * @physdev device to be forwarded to interface @iface. This allows + * the inbound traffic on a bridge. + * + * Returns 0 in case of success or an error code otherwise + */ +int +ebtablesAddForwardAllowIn(ebtablesContext *ctx, + const char *iface, + const virMacAddrPtr mac) +{ + char *macaddr; + + if (virAsprintf(&macaddr, + "%02x:%02x:%02x:%02x:%02x:%02x", + mac->addr[0], mac->addr[1], + mac->addr[2], mac->addr[3], + mac->addr[4], mac->addr[5]) < 0) { + return -1; + } + return ebtablesForwardAllowIn(ctx, iface, macaddr, ADD); +} + +/** + * ebtablesRemoveForwardAllowIn: + * @ctx: pointer to the EB table context + * @iface: the output interface name + * @physdev: the physical input device or NULL + * + * Remove rules from the EB table context hence forbidding the traffic + * on the @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 +ebtablesRemoveForwardAllowIn(ebtablesContext *ctx, + const char *iface, + const virMacAddrPtr mac) +{ + char *macaddr; + + if (virAsprintf(&macaddr, + "%02x:%02x:%02x:%02x:%02x:%02x", + mac->addr[0], mac->addr[1], + mac->addr[2], mac->addr[3], + mac->addr[4], mac->addr[5]) < 0) { + return -1; + } + return ebtablesForwardAllowIn(ctx, iface, macaddr, REMOVE); +} diff --git a/src/util/virebtables.h b/src/util/virebtables.h new file mode 100644 index 0000000..49dc8a0 --- /dev/null +++ b/src/util/virebtables.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 IBM Corp. + * 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, see + * <http://www.gnu.org/licenses/>. + * + * based on iptables.h + * Authors: + * Gerhard Stenzel <gerhard.stenzel@de.ibm.com> + */ + +#ifndef __QEMUD_EBTABLES_H__ +# define __QEMUD_EBTABLES_H__ + +# include "virmacaddr.h" + +typedef struct +{ + char *rule; + const char **argv; + int command_idx; +} ebtRule; + +typedef struct +{ + char *table; + char *chain; + + int nrules; + ebtRule *rules; + +} ebtRules; + +typedef struct _ebtablesContext ebtablesContext; + +ebtablesContext *ebtablesContextNew (const char *driver); +void ebtablesContextFree (ebtablesContext *ctx); + +void ebtablesSaveRules (ebtablesContext *ctx); + +int ebtablesAddForwardAllowIn (ebtablesContext *ctx, + const char *iface, + const virMacAddrPtr mac); +int ebtablesRemoveForwardAllowIn (ebtablesContext *ctx, + const char *iface, + const virMacAddrPtr mac); + +int ebtablesAddForwardPolicyReject(ebtablesContext *ctx); + +int ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx); + +int ebtablesForwardPolicyReject(ebtablesContext *ctx, + int action); + +#endif /* __QEMUD_ebtabLES_H__ */ -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> Since the event APIs are now in the public header, no internal code should include virevent.h --- src/Makefile.am | 2 +- src/rpc/virnetclientstream.c | 1 - src/rpc/virnetserver.c | 1 - src/rpc/virnetservermdns.c | 1 - src/rpc/virnetsocket.c | 1 - src/util/event.c | 253 ------------------------------------------- src/util/event.h | 28 ----- src/util/virevent.c | 253 +++++++++++++++++++++++++++++++++++++++++++ src/util/virevent.h | 28 +++++ tests/eventtest.c | 1 - 10 files changed, 282 insertions(+), 287 deletions(-) delete mode 100644 src/util/event.c delete mode 100644 src/util/event.h create mode 100644 src/util/virevent.c create mode 100644 src/util/virevent.h diff --git a/src/Makefile.am b/src/Makefile.am index daefa95..5c0d668 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/event.c util/event.h \ util/event_poll.c util/event_poll.h \ util/hooks.c util/hooks.h \ util/iptables.c util/iptables.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virconf.c util/virconf.h \ util/virdnsmasq.c util/virdnsmasq.h \ util/virebtables.c util/virebtables.h \ + util/virevent.c util/virevent.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c index 4ed40ca..0e7e38e 100644 --- a/src/rpc/virnetclientstream.c +++ b/src/rpc/virnetclientstream.c @@ -27,7 +27,6 @@ #include "memory.h" #include "virterror_internal.h" #include "logging.h" -#include "event.h" #include "threads.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 6a5a53a..f686a8f 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -35,7 +35,6 @@ #include "threadpool.h" #include "util.h" #include "virfile.h" -#include "event.h" #include "virnetservermdns.h" #include "virdbus.h" diff --git a/src/rpc/virnetservermdns.c b/src/rpc/virnetservermdns.c index b55d403..0ddb9d8 100644 --- a/src/rpc/virnetservermdns.c +++ b/src/rpc/virnetservermdns.c @@ -41,7 +41,6 @@ #endif #include "virnetservermdns.h" -#include "event.h" #include "event_poll.h" #include "memory.h" #include "virterror_internal.h" diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 70c621f..5a2eab3 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -46,7 +46,6 @@ #include "virterror_internal.h" #include "logging.h" #include "virfile.h" -#include "event.h" #include "threads.h" #include "virprocess.h" diff --git a/src/util/event.c b/src/util/event.c deleted file mode 100644 index 0abc30b..0000000 --- a/src/util/event.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * event.c: event loop for monitoring file handles - * - * Copyright (C) 2007, 2011 Red Hat, Inc. - * Copyright (C) 2007 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel P. Berrange <berrange@redhat.com> - */ - -#include <config.h> - -#include "event.h" -#include "event_poll.h" -#include "logging.h" -#include "virterror_internal.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; - -/** - * 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) { - if (!addHandleImpl) - return -1; - - return addHandleImpl(fd, events, cb, opaque, 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) { - updateHandleImpl(watch, 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) { - if (!removeHandleImpl) - return -1; - - return removeHandleImpl(watch); -} - -/** - * virEventAddTimeout: register a callback for a timer event - * - * @timeout: time between events in milliseconds - * @cb: callback to invoke when an event occurs - * @opaque: user data to pass to callback - * - * Setting timeout to -1 will disable the timer. Setting the timeout - * to zero will cause it to fire on every event loop iteration. - * - * returns -1 if the timer cannot be registered, a positive - * integer timer id upon success - */ -int virEventAddTimeout(int timeout, - virEventTimeoutCallback cb, - void *opaque, - virFreeCallback ff) { - if (!addTimeoutImpl) - return -1; - - return addTimeoutImpl(timeout, cb, opaque, 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 timeout) { - updateTimeoutImpl(timer, timeout); -} - -/** - * 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) { - if (!removeTimeoutImpl) - return -1; - - return removeTimeoutImpl(timer); -} - - -/***************************************************** - * - * Below this point are 3 *PUBLIC* APIs for event - * loop integration with applications using libvirt. - * These API contracts cannot be changed. - * - *****************************************************/ - -/** - * virEventRegisterImpl: - * @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 - * - * Registers an event implementation, to allow integration - * with an external event loop. Applications would use this - * to integrate with the libglib2 event loop, or libevent - * or the QT event loop. - * - * If an application does not need to integrate with an - * existing event loop implementation, then the - * virEventRegisterDefaultImpl method can be used to setup - * the generic libvirt implementation. - */ -void virEventRegisterImpl(virEventAddHandleFunc addHandle, - virEventUpdateHandleFunc updateHandle, - virEventRemoveHandleFunc removeHandle, - virEventAddTimeoutFunc addTimeout, - virEventUpdateTimeoutFunc updateTimeout, - virEventRemoveTimeoutFunc removeTimeout) -{ - VIR_DEBUG("addHandle=%p updateHandle=%p removeHandle=%p " - "addTimeout=%p updateTimeout=%p removeTimeout=%p", - addHandle, updateHandle, removeHandle, - addTimeout, updateTimeout, removeTimeout); - - addHandleImpl = addHandle; - updateHandleImpl = updateHandle; - removeHandleImpl = removeHandle; - addTimeoutImpl = addTimeout; - updateTimeoutImpl = updateTimeout; - removeTimeoutImpl = removeTimeout; -} - -/** - * virEventRegisterDefaultImpl: - * - * Registers a default event implementation based on the - * poll() system call. This is a generic implementation - * that can be used by any client application which does - * not have a need to integrate with an external event - * loop impl. - * - * Once registered, the application has to invoke virEventRunDefaultImpl in - * a loop to process events. Failure to do so may result in connections being - * closed unexpectedly as a result of keepalive timeout. - * - * Returns 0 on success, -1 on failure. - */ -int virEventRegisterDefaultImpl(void) -{ - VIR_DEBUG("registering default event implementation"); - - virResetLastError(); - - if (virEventPollInit() < 0) { - virDispatchError(NULL); - return -1; - } - - virEventRegisterImpl( - virEventPollAddHandle, - virEventPollUpdateHandle, - virEventPollRemoveHandle, - virEventPollAddTimeout, - virEventPollUpdateTimeout, - virEventPollRemoveTimeout - ); - - return 0; -} - - -/** - * virEventRunDefaultImpl: - * - * Run one iteration of the event loop. Applications - * will generally want to have a thread which invokes - * this method in an infinite loop - * - * static bool quit = false; - * - * while (!quit) { - * if (virEventRunDefaultImpl() < 0) - * ...print error... - * } - * - * Returns 0 on success, -1 on failure. - */ -int virEventRunDefaultImpl(void) -{ - VIR_DEBUG("running default event implementation"); - virResetLastError(); - - if (virEventPollRunOnce() < 0) { - virDispatchError(NULL); - return -1; - } - - return 0; -} diff --git a/src/util/event.h b/src/util/event.h deleted file mode 100644 index 5ab567a..0000000 --- a/src/util/event.h +++ /dev/null @@ -1,28 +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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel P. Berrange <berrange@redhat.com> - */ - -#ifndef __VIR_EVENT_H__ -# define __VIR_EVENT_H__ -# include "internal.h" - -#endif /* __VIR_EVENT_H__ */ diff --git a/src/util/virevent.c b/src/util/virevent.c new file mode 100644 index 0000000..08b7006 --- /dev/null +++ b/src/util/virevent.c @@ -0,0 +1,253 @@ +/* + * event.c: event loop for monitoring file handles + * + * Copyright (C) 2007, 2011 Red Hat, Inc. + * Copyright (C) 2007 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include "virevent.h" +#include "event_poll.h" +#include "logging.h" +#include "virterror_internal.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; + +/** + * 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) { + if (!addHandleImpl) + return -1; + + return addHandleImpl(fd, events, cb, opaque, 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) { + updateHandleImpl(watch, 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) { + if (!removeHandleImpl) + return -1; + + return removeHandleImpl(watch); +} + +/** + * virEventAddTimeout: register a callback for a timer event + * + * @timeout: time between events in milliseconds + * @cb: callback to invoke when an event occurs + * @opaque: user data to pass to callback + * + * Setting timeout to -1 will disable the timer. Setting the timeout + * to zero will cause it to fire on every event loop iteration. + * + * returns -1 if the timer cannot be registered, a positive + * integer timer id upon success + */ +int virEventAddTimeout(int timeout, + virEventTimeoutCallback cb, + void *opaque, + virFreeCallback ff) { + if (!addTimeoutImpl) + return -1; + + return addTimeoutImpl(timeout, cb, opaque, 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 timeout) { + updateTimeoutImpl(timer, timeout); +} + +/** + * 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) { + if (!removeTimeoutImpl) + return -1; + + return removeTimeoutImpl(timer); +} + + +/***************************************************** + * + * Below this point are 3 *PUBLIC* APIs for event + * loop integration with applications using libvirt. + * These API contracts cannot be changed. + * + *****************************************************/ + +/** + * virEventRegisterImpl: + * @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 + * + * Registers an event implementation, to allow integration + * with an external event loop. Applications would use this + * to integrate with the libglib2 event loop, or libevent + * or the QT event loop. + * + * If an application does not need to integrate with an + * existing event loop implementation, then the + * virEventRegisterDefaultImpl method can be used to setup + * the generic libvirt implementation. + */ +void virEventRegisterImpl(virEventAddHandleFunc addHandle, + virEventUpdateHandleFunc updateHandle, + virEventRemoveHandleFunc removeHandle, + virEventAddTimeoutFunc addTimeout, + virEventUpdateTimeoutFunc updateTimeout, + virEventRemoveTimeoutFunc removeTimeout) +{ + VIR_DEBUG("addHandle=%p updateHandle=%p removeHandle=%p " + "addTimeout=%p updateTimeout=%p removeTimeout=%p", + addHandle, updateHandle, removeHandle, + addTimeout, updateTimeout, removeTimeout); + + addHandleImpl = addHandle; + updateHandleImpl = updateHandle; + removeHandleImpl = removeHandle; + addTimeoutImpl = addTimeout; + updateTimeoutImpl = updateTimeout; + removeTimeoutImpl = removeTimeout; +} + +/** + * virEventRegisterDefaultImpl: + * + * Registers a default event implementation based on the + * poll() system call. This is a generic implementation + * that can be used by any client application which does + * not have a need to integrate with an external event + * loop impl. + * + * Once registered, the application has to invoke virEventRunDefaultImpl in + * a loop to process events. Failure to do so may result in connections being + * closed unexpectedly as a result of keepalive timeout. + * + * Returns 0 on success, -1 on failure. + */ +int virEventRegisterDefaultImpl(void) +{ + VIR_DEBUG("registering default event implementation"); + + virResetLastError(); + + if (virEventPollInit() < 0) { + virDispatchError(NULL); + return -1; + } + + virEventRegisterImpl( + virEventPollAddHandle, + virEventPollUpdateHandle, + virEventPollRemoveHandle, + virEventPollAddTimeout, + virEventPollUpdateTimeout, + virEventPollRemoveTimeout + ); + + return 0; +} + + +/** + * virEventRunDefaultImpl: + * + * Run one iteration of the event loop. Applications + * will generally want to have a thread which invokes + * this method in an infinite loop + * + * static bool quit = false; + * + * while (!quit) { + * if (virEventRunDefaultImpl() < 0) + * ...print error... + * } + * + * Returns 0 on success, -1 on failure. + */ +int virEventRunDefaultImpl(void) +{ + VIR_DEBUG("running default event implementation"); + virResetLastError(); + + if (virEventPollRunOnce() < 0) { + virDispatchError(NULL); + return -1; + } + + return 0; +} diff --git a/src/util/virevent.h b/src/util/virevent.h new file mode 100644 index 0000000..5ab567a --- /dev/null +++ b/src/util/virevent.h @@ -0,0 +1,28 @@ +/* + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_EVENT_H__ +# define __VIR_EVENT_H__ +# include "internal.h" + +#endif /* __VIR_EVENT_H__ */ diff --git a/tests/eventtest.c b/tests/eventtest.c index 78f51b7..c087978 100644 --- a/tests/eventtest.c +++ b/tests/eventtest.c @@ -31,7 +31,6 @@ #include "threads.h" #include "logging.h" #include "util.h" -#include "event.h" #include "event_poll.h" #define NUM_FDS 31 -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/rpc/virnetservermdns.c | 2 +- src/util/event_poll.c | 761 --------------------------------------------- src/util/event_poll.h | 132 -------- src/util/virevent.c | 2 +- src/util/vireventpoll.c | 761 +++++++++++++++++++++++++++++++++++++++++++++ src/util/vireventpoll.h | 132 ++++++++ tests/eventtest.c | 2 +- tools/virsh.c | 1 - 10 files changed, 898 insertions(+), 899 deletions(-) delete mode 100644 src/util/event_poll.c delete mode 100644 src/util/event_poll.h create mode 100644 src/util/vireventpoll.c create mode 100644 src/util/vireventpoll.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 3214ebe..818bb4e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/event_poll.c src/util/hooks.c src/util/hostusb.c src/util/iohelper.c @@ -158,6 +157,7 @@ src/util/vircommand.c src/util/virconf.c src/util/virdbus.c src/util/virdnsmasq.c +src/util/vireventpoll.c src/util/virfile.c src/util/virhash.c src/util/virinitctl.c diff --git a/src/Makefile.am b/src/Makefile.am index 5c0d668..f803de0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/event_poll.c util/event_poll.h \ util/hooks.c util/hooks.h \ util/iptables.c util/iptables.h \ util/json.c util/json.h \ @@ -83,6 +82,7 @@ UTIL_SOURCES = \ util/virdnsmasq.c util/virdnsmasq.h \ util/virebtables.c util/virebtables.h \ util/virevent.c util/virevent.h \ + util/vireventpoll.c util/vireventpoll.h \ util/virfile.c util/virfile.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ diff --git a/src/rpc/virnetservermdns.c b/src/rpc/virnetservermdns.c index 0ddb9d8..166b4eb 100644 --- a/src/rpc/virnetservermdns.c +++ b/src/rpc/virnetservermdns.c @@ -41,7 +41,7 @@ #endif #include "virnetservermdns.h" -#include "event_poll.h" +#include "vireventpoll.h" #include "memory.h" #include "virterror_internal.h" #include "logging.h" diff --git a/src/util/event_poll.c b/src/util/event_poll.c deleted file mode 100644 index 7a83a37..0000000 --- a/src/util/event_poll.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * event.c: event loop for monitoring file handles - * - * Copyright (C) 2007, 2010-2012 Red Hat, Inc. - * Copyright (C) 2007 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel P. Berrange <berrange@redhat.com> - */ - -#include <config.h> - -#include <stdlib.h> -#include <string.h> -#include <poll.h> -#include <sys/time.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> - -#include "threads.h" -#include "logging.h" -#include "event_poll.h" -#include "memory.h" -#include "util.h" -#include "virfile.h" -#include "virterror_internal.h" -#include "virtime.h" - -#define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__) - -#define VIR_FROM_THIS VIR_FROM_EVENT - -static int virEventPollInterruptLocked(void); - -/* State for a single file handle being monitored */ -struct virEventPollHandle { - int watch; - int fd; - int events; - virEventHandleCallback cb; - virFreeCallback ff; - void *opaque; - int deleted; -}; - -/* State for a single timer being generated */ -struct virEventPollTimeout { - int timer; - int frequency; - unsigned long long expiresAt; - virEventTimeoutCallback cb; - virFreeCallback ff; - void *opaque; - int deleted; -}; - -/* Allocate extra slots for virEventPollHandle/virEventPollTimeout - records in this multiple */ -#define EVENT_ALLOC_EXTENT 10 - -/* State for the main event loop */ -struct virEventPollLoop { - virMutex lock; - int running; - virThread leader; - int wakeupfd[2]; - size_t handlesCount; - size_t handlesAlloc; - struct virEventPollHandle *handles; - size_t timeoutsCount; - size_t timeoutsAlloc; - struct virEventPollTimeout *timeouts; -}; - -/* Only have one event loop */ -static struct virEventPollLoop eventLoop; - -/* Unique ID for the next FD watch to be registered */ -static int nextWatch = 1; - -/* Unique ID for the next timer to be registered */ -static int nextTimer = 1; - -/* - * Register a callback for monitoring file handle events. - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever append to existing list. - */ -int virEventPollAddHandle(int fd, int events, - virEventHandleCallback cb, - void *opaque, - virFreeCallback ff) { - int watch; - virMutexLock(&eventLoop.lock); - if (eventLoop.handlesCount == eventLoop.handlesAlloc) { - EVENT_DEBUG("Used %zu handle slots, adding at least %d more", - eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); - if (VIR_RESIZE_N(eventLoop.handles, eventLoop.handlesAlloc, - eventLoop.handlesCount, EVENT_ALLOC_EXTENT) < 0) { - virMutexUnlock(&eventLoop.lock); - return -1; - } - } - - watch = nextWatch++; - - eventLoop.handles[eventLoop.handlesCount].watch = watch; - eventLoop.handles[eventLoop.handlesCount].fd = fd; - eventLoop.handles[eventLoop.handlesCount].events = - virEventPollToNativeEvents(events); - eventLoop.handles[eventLoop.handlesCount].cb = cb; - eventLoop.handles[eventLoop.handlesCount].ff = ff; - eventLoop.handles[eventLoop.handlesCount].opaque = opaque; - eventLoop.handles[eventLoop.handlesCount].deleted = 0; - - eventLoop.handlesCount++; - - virEventPollInterruptLocked(); - - PROBE(EVENT_POLL_ADD_HANDLE, - "watch=%d fd=%d events=%d cb=%p opaque=%p ff=%p", - watch, fd, events, cb, opaque, ff); - virMutexUnlock(&eventLoop.lock); - - return watch; -} - -void virEventPollUpdateHandle(int watch, int events) { - int i; - bool found = false; - PROBE(EVENT_POLL_UPDATE_HANDLE, - "watch=%d events=%d", - watch, events); - - if (watch <= 0) { - VIR_WARN("Ignoring invalid update watch %d", watch); - return; - } - - virMutexLock(&eventLoop.lock); - for (i = 0 ; i < eventLoop.handlesCount ; i++) { - if (eventLoop.handles[i].watch == watch) { - eventLoop.handles[i].events = - virEventPollToNativeEvents(events); - virEventPollInterruptLocked(); - found = true; - break; - } - } - virMutexUnlock(&eventLoop.lock); - - if (!found) - VIR_WARN("Got update for non-existent handle watch %d", watch); -} - -/* - * Unregister a callback from a file handle - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever set a flag in the existing list. - * Actual deletion will be done out-of-band - */ -int virEventPollRemoveHandle(int watch) { - int i; - PROBE(EVENT_POLL_REMOVE_HANDLE, - "watch=%d", - watch); - - if (watch <= 0) { - VIR_WARN("Ignoring invalid remove watch %d", watch); - return -1; - } - - virMutexLock(&eventLoop.lock); - for (i = 0 ; i < eventLoop.handlesCount ; i++) { - if (eventLoop.handles[i].deleted) - continue; - - if (eventLoop.handles[i].watch == watch) { - EVENT_DEBUG("mark delete %d %d", i, eventLoop.handles[i].fd); - eventLoop.handles[i].deleted = 1; - virEventPollInterruptLocked(); - virMutexUnlock(&eventLoop.lock); - return 0; - } - } - virMutexUnlock(&eventLoop.lock); - return -1; -} - - -/* - * Register a callback for a timer event - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever append to existing list. - */ -int virEventPollAddTimeout(int frequency, - virEventTimeoutCallback cb, - void *opaque, - virFreeCallback ff) -{ - unsigned long long now; - int ret; - - if (virTimeMillisNow(&now) < 0) { - return -1; - } - - virMutexLock(&eventLoop.lock); - if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) { - EVENT_DEBUG("Used %zu timeout slots, adding at least %d more", - eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); - if (VIR_RESIZE_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, - eventLoop.timeoutsCount, EVENT_ALLOC_EXTENT) < 0) { - virMutexUnlock(&eventLoop.lock); - return -1; - } - } - - eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++; - eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency; - eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb; - eventLoop.timeouts[eventLoop.timeoutsCount].ff = ff; - eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque; - eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0; - eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt = - frequency >= 0 ? frequency + now : 0; - - eventLoop.timeoutsCount++; - ret = nextTimer-1; - virEventPollInterruptLocked(); - - PROBE(EVENT_POLL_ADD_TIMEOUT, - "timer=%d frequency=%d cb=%p opaque=%p ff=%p", - ret, frequency, cb, opaque, ff); - virMutexUnlock(&eventLoop.lock); - return ret; -} - -void virEventPollUpdateTimeout(int timer, int frequency) -{ - unsigned long long now; - int i; - bool found = false; - PROBE(EVENT_POLL_UPDATE_TIMEOUT, - "timer=%d frequency=%d", - timer, frequency); - - if (timer <= 0) { - VIR_WARN("Ignoring invalid update timer %d", timer); - return; - } - - if (virTimeMillisNow(&now) < 0) { - return; - } - - virMutexLock(&eventLoop.lock); - for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { - if (eventLoop.timeouts[i].timer == timer) { - eventLoop.timeouts[i].frequency = frequency; - eventLoop.timeouts[i].expiresAt = - frequency >= 0 ? frequency + now : 0; - VIR_DEBUG("Set timer freq=%d expires=%llu", frequency, - eventLoop.timeouts[i].expiresAt); - virEventPollInterruptLocked(); - found = true; - break; - } - } - virMutexUnlock(&eventLoop.lock); - - if (!found) - VIR_WARN("Got update for non-existent timer %d", timer); -} - -/* - * Unregister a callback for a timer - * NB, it *must* be safe to call this from within a callback - * For this reason we only ever set a flag in the existing list. - * Actual deletion will be done out-of-band - */ -int virEventPollRemoveTimeout(int timer) { - int i; - PROBE(EVENT_POLL_REMOVE_TIMEOUT, - "timer=%d", - timer); - - if (timer <= 0) { - VIR_WARN("Ignoring invalid remove timer %d", timer); - return -1; - } - - virMutexLock(&eventLoop.lock); - for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { - if (eventLoop.timeouts[i].deleted) - continue; - - if (eventLoop.timeouts[i].timer == timer) { - eventLoop.timeouts[i].deleted = 1; - virEventPollInterruptLocked(); - virMutexUnlock(&eventLoop.lock); - return 0; - } - } - virMutexUnlock(&eventLoop.lock); - return -1; -} - -/* Iterates over all registered timeouts and determine which - * will be the first to expire. - * @timeout: filled with expiry time of soonest timer, or -1 if - * no timeout is pending - * returns: 0 on success, -1 on error - */ -static int virEventPollCalculateTimeout(int *timeout) { - unsigned long long then = 0; - int i; - EVENT_DEBUG("Calculate expiry of %zu timers", eventLoop.timeoutsCount); - /* Figure out if we need a timeout */ - for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { - if (eventLoop.timeouts[i].deleted) - continue; - if (eventLoop.timeouts[i].frequency < 0) - continue; - - EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt); - if (then == 0 || - eventLoop.timeouts[i].expiresAt < then) - then = eventLoop.timeouts[i].expiresAt; - } - - /* Calculate how long we should wait for a timeout if needed */ - if (then > 0) { - unsigned long long now; - - if (virTimeMillisNow(&now) < 0) - return -1; - - EVENT_DEBUG("Schedule timeout then=%llu now=%llu", then, now); - *timeout = then - now; - if (*timeout < 0) - *timeout = 0; - } else { - *timeout = -1; - } - - EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout); - - return 0; -} - -/* - * Allocate a pollfd array containing data for all registered - * file handles. The caller must free the returned data struct - * returns: the pollfd array, or NULL on error - */ -static struct pollfd *virEventPollMakePollFDs(int *nfds) { - struct pollfd *fds; - int i; - - *nfds = 0; - for (i = 0 ; i < eventLoop.handlesCount ; i++) { - if (eventLoop.handles[i].events && !eventLoop.handles[i].deleted) - (*nfds)++; - } - - /* Setup the poll file handle data structs */ - if (VIR_ALLOC_N(fds, *nfds) < 0) { - virReportOOMError(); - return NULL; - } - - *nfds = 0; - for (i = 0 ; i < eventLoop.handlesCount ; i++) { - EVENT_DEBUG("Prepare n=%d w=%d, f=%d e=%d d=%d", i, - eventLoop.handles[i].watch, - eventLoop.handles[i].fd, - eventLoop.handles[i].events, - eventLoop.handles[i].deleted); - if (!eventLoop.handles[i].events || eventLoop.handles[i].deleted) - continue; - fds[*nfds].fd = eventLoop.handles[i].fd; - fds[*nfds].events = eventLoop.handles[i].events; - fds[*nfds].revents = 0; - (*nfds)++; - //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events); - } - - return fds; -} - - -/* - * Iterate over all timers and determine if any have expired. - * Invoke the user supplied callback for each timer whose - * expiry time is met, and schedule the next timeout. Does - * not try to 'catch up' on time if the actual expiry time - * was later than the requested time. - * - * This method must cope with new timers being registered - * by a callback, and must skip any timers marked as deleted. - * - * Returns 0 upon success, -1 if an error occurred - */ -static int virEventPollDispatchTimeouts(void) -{ - unsigned long long now; - int i; - /* Save this now - it may be changed during dispatch */ - int ntimeouts = eventLoop.timeoutsCount; - VIR_DEBUG("Dispatch %d", ntimeouts); - - if (virTimeMillisNow(&now) < 0) - return -1; - - for (i = 0 ; i < ntimeouts ; i++) { - if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0) - continue; - - /* Add 20ms fuzz so we don't pointlessly spin doing - * <10ms sleeps, particularly on kernels with low HZ - * it is fine that a timer expires 20ms earlier than - * requested - */ - if (eventLoop.timeouts[i].expiresAt <= (now+20)) { - virEventTimeoutCallback cb = eventLoop.timeouts[i].cb; - int timer = eventLoop.timeouts[i].timer; - void *opaque = eventLoop.timeouts[i].opaque; - eventLoop.timeouts[i].expiresAt = - now + eventLoop.timeouts[i].frequency; - - PROBE(EVENT_POLL_DISPATCH_TIMEOUT, - "timer=%d", - timer); - virMutexUnlock(&eventLoop.lock); - (cb)(timer, opaque); - virMutexLock(&eventLoop.lock); - } - } - return 0; -} - - -/* Iterate over all file handles and dispatch any which - * have pending events listed in the poll() data. Invoke - * the user supplied callback for each handle which has - * pending events - * - * This method must cope with new handles being registered - * by a callback, and must skip any handles marked as deleted. - * - * Returns 0 upon success, -1 if an error occurred - */ -static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) { - int i, n; - VIR_DEBUG("Dispatch %d", nfds); - - /* NB, use nfds not eventLoop.handlesCount, because new - * fds might be added on end of list, and they're not - * in the fds array we've got */ - for (i = 0, n = 0 ; n < nfds && i < eventLoop.handlesCount ; n++) { - while ((eventLoop.handles[i].fd != fds[n].fd || - eventLoop.handles[i].events == 0) && - i < eventLoop.handlesCount) { - i++; - } - if (i == eventLoop.handlesCount) - break; - - VIR_DEBUG("i=%d w=%d", i, eventLoop.handles[i].watch); - if (eventLoop.handles[i].deleted) { - EVENT_DEBUG("Skip deleted n=%d w=%d f=%d", i, - eventLoop.handles[i].watch, eventLoop.handles[i].fd); - continue; - } - - if (fds[n].revents) { - virEventHandleCallback cb = eventLoop.handles[i].cb; - int watch = eventLoop.handles[i].watch; - void *opaque = eventLoop.handles[i].opaque; - int hEvents = virEventPollFromNativeEvents(fds[n].revents); - PROBE(EVENT_POLL_DISPATCH_HANDLE, - "watch=%d events=%d", - watch, hEvents); - virMutexUnlock(&eventLoop.lock); - (cb)(watch, fds[n].fd, hEvents, opaque); - virMutexLock(&eventLoop.lock); - } - } - - return 0; -} - - -/* Used post dispatch to actually remove any timers that - * were previously marked as deleted. This asynchronous - * cleanup is needed to make dispatch re-entrant safe. - */ -static void virEventPollCleanupTimeouts(void) { - int i; - size_t gap; - VIR_DEBUG("Cleanup %zu", eventLoop.timeoutsCount); - - /* Remove deleted entries, shuffling down remaining - * entries as needed to form contiguous series - */ - for (i = 0 ; i < eventLoop.timeoutsCount ;) { - if (!eventLoop.timeouts[i].deleted) { - i++; - continue; - } - - PROBE(EVENT_POLL_PURGE_TIMEOUT, - "timer=%d", - eventLoop.timeouts[i].timer); - if (eventLoop.timeouts[i].ff) { - virFreeCallback ff = eventLoop.timeouts[i].ff; - void *opaque = eventLoop.timeouts[i].opaque; - virMutexUnlock(&eventLoop.lock); - ff(opaque); - virMutexLock(&eventLoop.lock); - } - - if ((i+1) < eventLoop.timeoutsCount) { - memmove(eventLoop.timeouts+i, - eventLoop.timeouts+i+1, - sizeof(struct virEventPollTimeout)*(eventLoop.timeoutsCount - -(i+1))); - } - eventLoop.timeoutsCount--; - } - - /* Release some memory if we've got a big chunk free */ - gap = eventLoop.timeoutsAlloc - eventLoop.timeoutsCount; - if (eventLoop.timeoutsCount == 0 || - (gap > eventLoop.timeoutsCount && gap > EVENT_ALLOC_EXTENT)) { - EVENT_DEBUG("Found %zu out of %zu timeout slots used, releasing %zu", - eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, gap); - VIR_SHRINK_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, gap); - } -} - -/* Used post dispatch to actually remove any handles that - * were previously marked as deleted. This asynchronous - * cleanup is needed to make dispatch re-entrant safe. - */ -static void virEventPollCleanupHandles(void) { - int i; - size_t gap; - VIR_DEBUG("Cleanup %zu", eventLoop.handlesCount); - - /* Remove deleted entries, shuffling down remaining - * entries as needed to form contiguous series - */ - for (i = 0 ; i < eventLoop.handlesCount ;) { - if (!eventLoop.handles[i].deleted) { - i++; - continue; - } - - PROBE(EVENT_POLL_PURGE_HANDLE, - "watch=%d", - eventLoop.handles[i].watch); - if (eventLoop.handles[i].ff) { - virFreeCallback ff = eventLoop.handles[i].ff; - void *opaque = eventLoop.handles[i].opaque; - virMutexUnlock(&eventLoop.lock); - ff(opaque); - virMutexLock(&eventLoop.lock); - } - - if ((i+1) < eventLoop.handlesCount) { - memmove(eventLoop.handles+i, - eventLoop.handles+i+1, - sizeof(struct virEventPollHandle)*(eventLoop.handlesCount - -(i+1))); - } - eventLoop.handlesCount--; - } - - /* Release some memory if we've got a big chunk free */ - gap = eventLoop.handlesAlloc - eventLoop.handlesCount; - if (eventLoop.handlesCount == 0 || - (gap > eventLoop.handlesCount && gap > EVENT_ALLOC_EXTENT)) { - EVENT_DEBUG("Found %zu out of %zu handles slots used, releasing %zu", - eventLoop.handlesCount, eventLoop.handlesAlloc, gap); - VIR_SHRINK_N(eventLoop.handles, eventLoop.handlesAlloc, gap); - } -} - -/* - * Run a single iteration of the event loop, blocking until - * at least one file handle has an event, or a timer expires - */ -int virEventPollRunOnce(void) { - struct pollfd *fds = NULL; - int ret, timeout, nfds; - - virMutexLock(&eventLoop.lock); - eventLoop.running = 1; - virThreadSelf(&eventLoop.leader); - - virEventPollCleanupTimeouts(); - virEventPollCleanupHandles(); - - if (!(fds = virEventPollMakePollFDs(&nfds)) || - virEventPollCalculateTimeout(&timeout) < 0) - goto error; - - virMutexUnlock(&eventLoop.lock); - - retry: - PROBE(EVENT_POLL_RUN, - "nhandles=%d timeout=%d", - nfds, timeout); - ret = poll(fds, nfds, timeout); - if (ret < 0) { - EVENT_DEBUG("Poll got error event %d", errno); - if (errno == EINTR || errno == EAGAIN) { - goto retry; - } - virReportSystemError(errno, "%s", - _("Unable to poll on file handles")); - goto error_unlocked; - } - EVENT_DEBUG("Poll got %d event(s)", ret); - - virMutexLock(&eventLoop.lock); - if (virEventPollDispatchTimeouts() < 0) - goto error; - - if (ret > 0 && - virEventPollDispatchHandles(nfds, fds) < 0) - goto error; - - virEventPollCleanupTimeouts(); - virEventPollCleanupHandles(); - - eventLoop.running = 0; - virMutexUnlock(&eventLoop.lock); - VIR_FREE(fds); - return 0; - -error: - virMutexUnlock(&eventLoop.lock); -error_unlocked: - VIR_FREE(fds); - return -1; -} - - -static void virEventPollHandleWakeup(int watch ATTRIBUTE_UNUSED, - int fd, - int events ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ - char c; - virMutexLock(&eventLoop.lock); - ignore_value(saferead(fd, &c, sizeof(c))); - virMutexUnlock(&eventLoop.lock); -} - -int virEventPollInit(void) -{ - if (virMutexInit(&eventLoop.lock) < 0) { - virReportSystemError(errno, "%s", - _("Unable to initialize mutex")); - return -1; - } - - if (pipe2(eventLoop.wakeupfd, O_CLOEXEC | O_NONBLOCK) < 0) { - virReportSystemError(errno, "%s", - _("Unable to setup wakeup pipe")); - return -1; - } - - if (virEventPollAddHandle(eventLoop.wakeupfd[0], - VIR_EVENT_HANDLE_READABLE, - virEventPollHandleWakeup, NULL, NULL) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to add handle %d to event loop"), - eventLoop.wakeupfd[0]); - VIR_FORCE_CLOSE(eventLoop.wakeupfd[0]); - VIR_FORCE_CLOSE(eventLoop.wakeupfd[1]); - return -1; - } - - return 0; -} - -static int virEventPollInterruptLocked(void) -{ - char c = '\0'; - - if (!eventLoop.running || - virThreadIsSelf(&eventLoop.leader)) { - VIR_DEBUG("Skip interrupt, %d %d", eventLoop.running, - virThreadID(&eventLoop.leader)); - return 0; - } - - VIR_DEBUG("Interrupting"); - if (safewrite(eventLoop.wakeupfd[1], &c, sizeof(c)) != sizeof(c)) - return -1; - return 0; -} - -int virEventPollInterrupt(void) -{ - int ret; - virMutexLock(&eventLoop.lock); - ret = virEventPollInterruptLocked(); - virMutexUnlock(&eventLoop.lock); - return ret; -} - -int -virEventPollToNativeEvents(int events) -{ - int ret = 0; - if (events & VIR_EVENT_HANDLE_READABLE) - ret |= POLLIN; - if (events & VIR_EVENT_HANDLE_WRITABLE) - ret |= POLLOUT; - if (events & VIR_EVENT_HANDLE_ERROR) - ret |= POLLERR; - if (events & VIR_EVENT_HANDLE_HANGUP) - ret |= POLLHUP; - return ret; -} - -int -virEventPollFromNativeEvents(int events) -{ - int ret = 0; - if (events & POLLIN) - ret |= VIR_EVENT_HANDLE_READABLE; - if (events & POLLOUT) - ret |= VIR_EVENT_HANDLE_WRITABLE; - if (events & POLLERR) - ret |= VIR_EVENT_HANDLE_ERROR; - if (events & POLLNVAL) /* Treat NVAL as error, since libvirt doesn't distinguish */ - ret |= VIR_EVENT_HANDLE_ERROR; - if (events & POLLHUP) - ret |= VIR_EVENT_HANDLE_HANGUP; - return ret; -} diff --git a/src/util/event_poll.h b/src/util/event_poll.h deleted file mode 100644 index 64b2e96..0000000 --- a/src/util/event_poll.h +++ /dev/null @@ -1,132 +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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel P. Berrange <berrange@redhat.com> - */ - -#ifndef __VIR_EVENT_POLL_H__ -# define __VIR_EVENT_POLL_H__ - -# include "internal.h" - -/** - * virEventPollAddHandle: register a callback for monitoring file handle events - * - * @fd: file handle to monitor for events - * @events: bitset of events to watch from POLLnnn 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 virEventPollAddHandle(int fd, int events, - virEventHandleCallback cb, - void *opaque, - virFreeCallback ff); - -/** - * virEventPollUpdateHandle: change event set for a monitored file handle - * - * @watch: watch whose handle to update - * @events: bitset of events to watch from POLLnnn constants - * - * Will not fail if fd exists - */ -void virEventPollUpdateHandle(int watch, int events); - -/** - * virEventPollRemoveHandle: unregister a callback from a file handle - * - * @watch: watch whose handle to remove - * - * returns -1 if the file handle was not registered, 0 upon success - */ -int virEventPollRemoveHandle(int watch); - -/** - * virEventPollAddTimeout: 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 virEventPollAddTimeout(int frequency, - virEventTimeoutCallback cb, - void *opaque, - virFreeCallback ff); - -/** - * virEventPollUpdateTimeout: 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 virEventPollUpdateTimeout(int timer, int frequency); - -/** - * virEventPollRemoveTimeout: unregister a callback for a timer - * - * @timer: the timer id to remove - * - * returns -1 if the timer was not registered, 0 upon success - */ -int virEventPollRemoveTimeout(int timer); - -/** - * virEventPollInit: Initialize the event loop - * - * returns -1 if initialization failed - */ -int virEventPollInit(void); - -/** - * virEventPollRunOnce: run a single iteration of the event loop. - * - * Blocks the caller until at least one file handle has an - * event or the first timer expires. - * - * returns -1 if the event monitoring failed - */ -int virEventPollRunOnce(void); - -int virEventPollFromNativeEvents(int events); -int virEventPollToNativeEvents(int events); - - -/** - * virEventPollInterrupt: wakeup any thread waiting in poll() - * - * return -1 if wakup failed - */ -int virEventPollInterrupt(void); - - -#endif /* __VIRTD_EVENT_H__ */ diff --git a/src/util/virevent.c b/src/util/virevent.c index 08b7006..7d11f85 100644 --- a/src/util/virevent.c +++ b/src/util/virevent.c @@ -24,7 +24,7 @@ #include <config.h> #include "virevent.h" -#include "event_poll.h" +#include "vireventpoll.h" #include "logging.h" #include "virterror_internal.h" diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c new file mode 100644 index 0000000..9fd196d --- /dev/null +++ b/src/util/vireventpoll.c @@ -0,0 +1,761 @@ +/* + * event.c: event loop for monitoring file handles + * + * Copyright (C) 2007, 2010-2012 Red Hat, Inc. + * Copyright (C) 2007 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <poll.h> +#include <sys/time.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include "threads.h" +#include "logging.h" +#include "vireventpoll.h" +#include "memory.h" +#include "util.h" +#include "virfile.h" +#include "virterror_internal.h" +#include "virtime.h" + +#define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__) + +#define VIR_FROM_THIS VIR_FROM_EVENT + +static int virEventPollInterruptLocked(void); + +/* State for a single file handle being monitored */ +struct virEventPollHandle { + int watch; + int fd; + int events; + virEventHandleCallback cb; + virFreeCallback ff; + void *opaque; + int deleted; +}; + +/* State for a single timer being generated */ +struct virEventPollTimeout { + int timer; + int frequency; + unsigned long long expiresAt; + virEventTimeoutCallback cb; + virFreeCallback ff; + void *opaque; + int deleted; +}; + +/* Allocate extra slots for virEventPollHandle/virEventPollTimeout + records in this multiple */ +#define EVENT_ALLOC_EXTENT 10 + +/* State for the main event loop */ +struct virEventPollLoop { + virMutex lock; + int running; + virThread leader; + int wakeupfd[2]; + size_t handlesCount; + size_t handlesAlloc; + struct virEventPollHandle *handles; + size_t timeoutsCount; + size_t timeoutsAlloc; + struct virEventPollTimeout *timeouts; +}; + +/* Only have one event loop */ +static struct virEventPollLoop eventLoop; + +/* Unique ID for the next FD watch to be registered */ +static int nextWatch = 1; + +/* Unique ID for the next timer to be registered */ +static int nextTimer = 1; + +/* + * Register a callback for monitoring file handle events. + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever append to existing list. + */ +int virEventPollAddHandle(int fd, int events, + virEventHandleCallback cb, + void *opaque, + virFreeCallback ff) { + int watch; + virMutexLock(&eventLoop.lock); + if (eventLoop.handlesCount == eventLoop.handlesAlloc) { + EVENT_DEBUG("Used %zu handle slots, adding at least %d more", + eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); + if (VIR_RESIZE_N(eventLoop.handles, eventLoop.handlesAlloc, + eventLoop.handlesCount, EVENT_ALLOC_EXTENT) < 0) { + virMutexUnlock(&eventLoop.lock); + return -1; + } + } + + watch = nextWatch++; + + eventLoop.handles[eventLoop.handlesCount].watch = watch; + eventLoop.handles[eventLoop.handlesCount].fd = fd; + eventLoop.handles[eventLoop.handlesCount].events = + virEventPollToNativeEvents(events); + eventLoop.handles[eventLoop.handlesCount].cb = cb; + eventLoop.handles[eventLoop.handlesCount].ff = ff; + eventLoop.handles[eventLoop.handlesCount].opaque = opaque; + eventLoop.handles[eventLoop.handlesCount].deleted = 0; + + eventLoop.handlesCount++; + + virEventPollInterruptLocked(); + + PROBE(EVENT_POLL_ADD_HANDLE, + "watch=%d fd=%d events=%d cb=%p opaque=%p ff=%p", + watch, fd, events, cb, opaque, ff); + virMutexUnlock(&eventLoop.lock); + + return watch; +} + +void virEventPollUpdateHandle(int watch, int events) { + int i; + bool found = false; + PROBE(EVENT_POLL_UPDATE_HANDLE, + "watch=%d events=%d", + watch, events); + + if (watch <= 0) { + VIR_WARN("Ignoring invalid update watch %d", watch); + return; + } + + virMutexLock(&eventLoop.lock); + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].watch == watch) { + eventLoop.handles[i].events = + virEventPollToNativeEvents(events); + virEventPollInterruptLocked(); + found = true; + break; + } + } + virMutexUnlock(&eventLoop.lock); + + if (!found) + VIR_WARN("Got update for non-existent handle watch %d", watch); +} + +/* + * Unregister a callback from a file handle + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever set a flag in the existing list. + * Actual deletion will be done out-of-band + */ +int virEventPollRemoveHandle(int watch) { + int i; + PROBE(EVENT_POLL_REMOVE_HANDLE, + "watch=%d", + watch); + + if (watch <= 0) { + VIR_WARN("Ignoring invalid remove watch %d", watch); + return -1; + } + + virMutexLock(&eventLoop.lock); + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].deleted) + continue; + + if (eventLoop.handles[i].watch == watch) { + EVENT_DEBUG("mark delete %d %d", i, eventLoop.handles[i].fd); + eventLoop.handles[i].deleted = 1; + virEventPollInterruptLocked(); + virMutexUnlock(&eventLoop.lock); + return 0; + } + } + virMutexUnlock(&eventLoop.lock); + return -1; +} + + +/* + * Register a callback for a timer event + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever append to existing list. + */ +int virEventPollAddTimeout(int frequency, + virEventTimeoutCallback cb, + void *opaque, + virFreeCallback ff) +{ + unsigned long long now; + int ret; + + if (virTimeMillisNow(&now) < 0) { + return -1; + } + + virMutexLock(&eventLoop.lock); + if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) { + EVENT_DEBUG("Used %zu timeout slots, adding at least %d more", + eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); + if (VIR_RESIZE_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, + eventLoop.timeoutsCount, EVENT_ALLOC_EXTENT) < 0) { + virMutexUnlock(&eventLoop.lock); + return -1; + } + } + + eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++; + eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency; + eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb; + eventLoop.timeouts[eventLoop.timeoutsCount].ff = ff; + eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque; + eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0; + eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt = + frequency >= 0 ? frequency + now : 0; + + eventLoop.timeoutsCount++; + ret = nextTimer-1; + virEventPollInterruptLocked(); + + PROBE(EVENT_POLL_ADD_TIMEOUT, + "timer=%d frequency=%d cb=%p opaque=%p ff=%p", + ret, frequency, cb, opaque, ff); + virMutexUnlock(&eventLoop.lock); + return ret; +} + +void virEventPollUpdateTimeout(int timer, int frequency) +{ + unsigned long long now; + int i; + bool found = false; + PROBE(EVENT_POLL_UPDATE_TIMEOUT, + "timer=%d frequency=%d", + timer, frequency); + + if (timer <= 0) { + VIR_WARN("Ignoring invalid update timer %d", timer); + return; + } + + if (virTimeMillisNow(&now) < 0) { + return; + } + + virMutexLock(&eventLoop.lock); + for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { + if (eventLoop.timeouts[i].timer == timer) { + eventLoop.timeouts[i].frequency = frequency; + eventLoop.timeouts[i].expiresAt = + frequency >= 0 ? frequency + now : 0; + VIR_DEBUG("Set timer freq=%d expires=%llu", frequency, + eventLoop.timeouts[i].expiresAt); + virEventPollInterruptLocked(); + found = true; + break; + } + } + virMutexUnlock(&eventLoop.lock); + + if (!found) + VIR_WARN("Got update for non-existent timer %d", timer); +} + +/* + * Unregister a callback for a timer + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever set a flag in the existing list. + * Actual deletion will be done out-of-band + */ +int virEventPollRemoveTimeout(int timer) { + int i; + PROBE(EVENT_POLL_REMOVE_TIMEOUT, + "timer=%d", + timer); + + if (timer <= 0) { + VIR_WARN("Ignoring invalid remove timer %d", timer); + return -1; + } + + virMutexLock(&eventLoop.lock); + for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { + if (eventLoop.timeouts[i].deleted) + continue; + + if (eventLoop.timeouts[i].timer == timer) { + eventLoop.timeouts[i].deleted = 1; + virEventPollInterruptLocked(); + virMutexUnlock(&eventLoop.lock); + return 0; + } + } + virMutexUnlock(&eventLoop.lock); + return -1; +} + +/* Iterates over all registered timeouts and determine which + * will be the first to expire. + * @timeout: filled with expiry time of soonest timer, or -1 if + * no timeout is pending + * returns: 0 on success, -1 on error + */ +static int virEventPollCalculateTimeout(int *timeout) { + unsigned long long then = 0; + int i; + EVENT_DEBUG("Calculate expiry of %zu timers", eventLoop.timeoutsCount); + /* Figure out if we need a timeout */ + for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { + if (eventLoop.timeouts[i].deleted) + continue; + if (eventLoop.timeouts[i].frequency < 0) + continue; + + EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt); + if (then == 0 || + eventLoop.timeouts[i].expiresAt < then) + then = eventLoop.timeouts[i].expiresAt; + } + + /* Calculate how long we should wait for a timeout if needed */ + if (then > 0) { + unsigned long long now; + + if (virTimeMillisNow(&now) < 0) + return -1; + + EVENT_DEBUG("Schedule timeout then=%llu now=%llu", then, now); + *timeout = then - now; + if (*timeout < 0) + *timeout = 0; + } else { + *timeout = -1; + } + + EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout); + + return 0; +} + +/* + * Allocate a pollfd array containing data for all registered + * file handles. The caller must free the returned data struct + * returns: the pollfd array, or NULL on error + */ +static struct pollfd *virEventPollMakePollFDs(int *nfds) { + struct pollfd *fds; + int i; + + *nfds = 0; + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].events && !eventLoop.handles[i].deleted) + (*nfds)++; + } + + /* Setup the poll file handle data structs */ + if (VIR_ALLOC_N(fds, *nfds) < 0) { + virReportOOMError(); + return NULL; + } + + *nfds = 0; + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + EVENT_DEBUG("Prepare n=%d w=%d, f=%d e=%d d=%d", i, + eventLoop.handles[i].watch, + eventLoop.handles[i].fd, + eventLoop.handles[i].events, + eventLoop.handles[i].deleted); + if (!eventLoop.handles[i].events || eventLoop.handles[i].deleted) + continue; + fds[*nfds].fd = eventLoop.handles[i].fd; + fds[*nfds].events = eventLoop.handles[i].events; + fds[*nfds].revents = 0; + (*nfds)++; + //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events); + } + + return fds; +} + + +/* + * Iterate over all timers and determine if any have expired. + * Invoke the user supplied callback for each timer whose + * expiry time is met, and schedule the next timeout. Does + * not try to 'catch up' on time if the actual expiry time + * was later than the requested time. + * + * This method must cope with new timers being registered + * by a callback, and must skip any timers marked as deleted. + * + * Returns 0 upon success, -1 if an error occurred + */ +static int virEventPollDispatchTimeouts(void) +{ + unsigned long long now; + int i; + /* Save this now - it may be changed during dispatch */ + int ntimeouts = eventLoop.timeoutsCount; + VIR_DEBUG("Dispatch %d", ntimeouts); + + if (virTimeMillisNow(&now) < 0) + return -1; + + for (i = 0 ; i < ntimeouts ; i++) { + if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0) + continue; + + /* Add 20ms fuzz so we don't pointlessly spin doing + * <10ms sleeps, particularly on kernels with low HZ + * it is fine that a timer expires 20ms earlier than + * requested + */ + if (eventLoop.timeouts[i].expiresAt <= (now+20)) { + virEventTimeoutCallback cb = eventLoop.timeouts[i].cb; + int timer = eventLoop.timeouts[i].timer; + void *opaque = eventLoop.timeouts[i].opaque; + eventLoop.timeouts[i].expiresAt = + now + eventLoop.timeouts[i].frequency; + + PROBE(EVENT_POLL_DISPATCH_TIMEOUT, + "timer=%d", + timer); + virMutexUnlock(&eventLoop.lock); + (cb)(timer, opaque); + virMutexLock(&eventLoop.lock); + } + } + return 0; +} + + +/* Iterate over all file handles and dispatch any which + * have pending events listed in the poll() data. Invoke + * the user supplied callback for each handle which has + * pending events + * + * This method must cope with new handles being registered + * by a callback, and must skip any handles marked as deleted. + * + * Returns 0 upon success, -1 if an error occurred + */ +static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) { + int i, n; + VIR_DEBUG("Dispatch %d", nfds); + + /* NB, use nfds not eventLoop.handlesCount, because new + * fds might be added on end of list, and they're not + * in the fds array we've got */ + for (i = 0, n = 0 ; n < nfds && i < eventLoop.handlesCount ; n++) { + while ((eventLoop.handles[i].fd != fds[n].fd || + eventLoop.handles[i].events == 0) && + i < eventLoop.handlesCount) { + i++; + } + if (i == eventLoop.handlesCount) + break; + + VIR_DEBUG("i=%d w=%d", i, eventLoop.handles[i].watch); + if (eventLoop.handles[i].deleted) { + EVENT_DEBUG("Skip deleted n=%d w=%d f=%d", i, + eventLoop.handles[i].watch, eventLoop.handles[i].fd); + continue; + } + + if (fds[n].revents) { + virEventHandleCallback cb = eventLoop.handles[i].cb; + int watch = eventLoop.handles[i].watch; + void *opaque = eventLoop.handles[i].opaque; + int hEvents = virEventPollFromNativeEvents(fds[n].revents); + PROBE(EVENT_POLL_DISPATCH_HANDLE, + "watch=%d events=%d", + watch, hEvents); + virMutexUnlock(&eventLoop.lock); + (cb)(watch, fds[n].fd, hEvents, opaque); + virMutexLock(&eventLoop.lock); + } + } + + return 0; +} + + +/* Used post dispatch to actually remove any timers that + * were previously marked as deleted. This asynchronous + * cleanup is needed to make dispatch re-entrant safe. + */ +static void virEventPollCleanupTimeouts(void) { + int i; + size_t gap; + VIR_DEBUG("Cleanup %zu", eventLoop.timeoutsCount); + + /* Remove deleted entries, shuffling down remaining + * entries as needed to form contiguous series + */ + for (i = 0 ; i < eventLoop.timeoutsCount ;) { + if (!eventLoop.timeouts[i].deleted) { + i++; + continue; + } + + PROBE(EVENT_POLL_PURGE_TIMEOUT, + "timer=%d", + eventLoop.timeouts[i].timer); + if (eventLoop.timeouts[i].ff) { + virFreeCallback ff = eventLoop.timeouts[i].ff; + void *opaque = eventLoop.timeouts[i].opaque; + virMutexUnlock(&eventLoop.lock); + ff(opaque); + virMutexLock(&eventLoop.lock); + } + + if ((i+1) < eventLoop.timeoutsCount) { + memmove(eventLoop.timeouts+i, + eventLoop.timeouts+i+1, + sizeof(struct virEventPollTimeout)*(eventLoop.timeoutsCount + -(i+1))); + } + eventLoop.timeoutsCount--; + } + + /* Release some memory if we've got a big chunk free */ + gap = eventLoop.timeoutsAlloc - eventLoop.timeoutsCount; + if (eventLoop.timeoutsCount == 0 || + (gap > eventLoop.timeoutsCount && gap > EVENT_ALLOC_EXTENT)) { + EVENT_DEBUG("Found %zu out of %zu timeout slots used, releasing %zu", + eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, gap); + VIR_SHRINK_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, gap); + } +} + +/* Used post dispatch to actually remove any handles that + * were previously marked as deleted. This asynchronous + * cleanup is needed to make dispatch re-entrant safe. + */ +static void virEventPollCleanupHandles(void) { + int i; + size_t gap; + VIR_DEBUG("Cleanup %zu", eventLoop.handlesCount); + + /* Remove deleted entries, shuffling down remaining + * entries as needed to form contiguous series + */ + for (i = 0 ; i < eventLoop.handlesCount ;) { + if (!eventLoop.handles[i].deleted) { + i++; + continue; + } + + PROBE(EVENT_POLL_PURGE_HANDLE, + "watch=%d", + eventLoop.handles[i].watch); + if (eventLoop.handles[i].ff) { + virFreeCallback ff = eventLoop.handles[i].ff; + void *opaque = eventLoop.handles[i].opaque; + virMutexUnlock(&eventLoop.lock); + ff(opaque); + virMutexLock(&eventLoop.lock); + } + + if ((i+1) < eventLoop.handlesCount) { + memmove(eventLoop.handles+i, + eventLoop.handles+i+1, + sizeof(struct virEventPollHandle)*(eventLoop.handlesCount + -(i+1))); + } + eventLoop.handlesCount--; + } + + /* Release some memory if we've got a big chunk free */ + gap = eventLoop.handlesAlloc - eventLoop.handlesCount; + if (eventLoop.handlesCount == 0 || + (gap > eventLoop.handlesCount && gap > EVENT_ALLOC_EXTENT)) { + EVENT_DEBUG("Found %zu out of %zu handles slots used, releasing %zu", + eventLoop.handlesCount, eventLoop.handlesAlloc, gap); + VIR_SHRINK_N(eventLoop.handles, eventLoop.handlesAlloc, gap); + } +} + +/* + * Run a single iteration of the event loop, blocking until + * at least one file handle has an event, or a timer expires + */ +int virEventPollRunOnce(void) { + struct pollfd *fds = NULL; + int ret, timeout, nfds; + + virMutexLock(&eventLoop.lock); + eventLoop.running = 1; + virThreadSelf(&eventLoop.leader); + + virEventPollCleanupTimeouts(); + virEventPollCleanupHandles(); + + if (!(fds = virEventPollMakePollFDs(&nfds)) || + virEventPollCalculateTimeout(&timeout) < 0) + goto error; + + virMutexUnlock(&eventLoop.lock); + + retry: + PROBE(EVENT_POLL_RUN, + "nhandles=%d timeout=%d", + nfds, timeout); + ret = poll(fds, nfds, timeout); + if (ret < 0) { + EVENT_DEBUG("Poll got error event %d", errno); + if (errno == EINTR || errno == EAGAIN) { + goto retry; + } + virReportSystemError(errno, "%s", + _("Unable to poll on file handles")); + goto error_unlocked; + } + EVENT_DEBUG("Poll got %d event(s)", ret); + + virMutexLock(&eventLoop.lock); + if (virEventPollDispatchTimeouts() < 0) + goto error; + + if (ret > 0 && + virEventPollDispatchHandles(nfds, fds) < 0) + goto error; + + virEventPollCleanupTimeouts(); + virEventPollCleanupHandles(); + + eventLoop.running = 0; + virMutexUnlock(&eventLoop.lock); + VIR_FREE(fds); + return 0; + +error: + virMutexUnlock(&eventLoop.lock); +error_unlocked: + VIR_FREE(fds); + return -1; +} + + +static void virEventPollHandleWakeup(int watch ATTRIBUTE_UNUSED, + int fd, + int events ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + char c; + virMutexLock(&eventLoop.lock); + ignore_value(saferead(fd, &c, sizeof(c))); + virMutexUnlock(&eventLoop.lock); +} + +int virEventPollInit(void) +{ + if (virMutexInit(&eventLoop.lock) < 0) { + virReportSystemError(errno, "%s", + _("Unable to initialize mutex")); + return -1; + } + + if (pipe2(eventLoop.wakeupfd, O_CLOEXEC | O_NONBLOCK) < 0) { + virReportSystemError(errno, "%s", + _("Unable to setup wakeup pipe")); + return -1; + } + + if (virEventPollAddHandle(eventLoop.wakeupfd[0], + VIR_EVENT_HANDLE_READABLE, + virEventPollHandleWakeup, NULL, NULL) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to add handle %d to event loop"), + eventLoop.wakeupfd[0]); + VIR_FORCE_CLOSE(eventLoop.wakeupfd[0]); + VIR_FORCE_CLOSE(eventLoop.wakeupfd[1]); + return -1; + } + + return 0; +} + +static int virEventPollInterruptLocked(void) +{ + char c = '\0'; + + if (!eventLoop.running || + virThreadIsSelf(&eventLoop.leader)) { + VIR_DEBUG("Skip interrupt, %d %d", eventLoop.running, + virThreadID(&eventLoop.leader)); + return 0; + } + + VIR_DEBUG("Interrupting"); + if (safewrite(eventLoop.wakeupfd[1], &c, sizeof(c)) != sizeof(c)) + return -1; + return 0; +} + +int virEventPollInterrupt(void) +{ + int ret; + virMutexLock(&eventLoop.lock); + ret = virEventPollInterruptLocked(); + virMutexUnlock(&eventLoop.lock); + return ret; +} + +int +virEventPollToNativeEvents(int events) +{ + int ret = 0; + if (events & VIR_EVENT_HANDLE_READABLE) + ret |= POLLIN; + if (events & VIR_EVENT_HANDLE_WRITABLE) + ret |= POLLOUT; + if (events & VIR_EVENT_HANDLE_ERROR) + ret |= POLLERR; + if (events & VIR_EVENT_HANDLE_HANGUP) + ret |= POLLHUP; + return ret; +} + +int +virEventPollFromNativeEvents(int events) +{ + int ret = 0; + if (events & POLLIN) + ret |= VIR_EVENT_HANDLE_READABLE; + if (events & POLLOUT) + ret |= VIR_EVENT_HANDLE_WRITABLE; + if (events & POLLERR) + ret |= VIR_EVENT_HANDLE_ERROR; + if (events & POLLNVAL) /* Treat NVAL as error, since libvirt doesn't distinguish */ + ret |= VIR_EVENT_HANDLE_ERROR; + if (events & POLLHUP) + ret |= VIR_EVENT_HANDLE_HANGUP; + return ret; +} diff --git a/src/util/vireventpoll.h b/src/util/vireventpoll.h new file mode 100644 index 0000000..64b2e96 --- /dev/null +++ b/src/util/vireventpoll.h @@ -0,0 +1,132 @@ +/* + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_EVENT_POLL_H__ +# define __VIR_EVENT_POLL_H__ + +# include "internal.h" + +/** + * virEventPollAddHandle: register a callback for monitoring file handle events + * + * @fd: file handle to monitor for events + * @events: bitset of events to watch from POLLnnn 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 virEventPollAddHandle(int fd, int events, + virEventHandleCallback cb, + void *opaque, + virFreeCallback ff); + +/** + * virEventPollUpdateHandle: change event set for a monitored file handle + * + * @watch: watch whose handle to update + * @events: bitset of events to watch from POLLnnn constants + * + * Will not fail if fd exists + */ +void virEventPollUpdateHandle(int watch, int events); + +/** + * virEventPollRemoveHandle: unregister a callback from a file handle + * + * @watch: watch whose handle to remove + * + * returns -1 if the file handle was not registered, 0 upon success + */ +int virEventPollRemoveHandle(int watch); + +/** + * virEventPollAddTimeout: 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 virEventPollAddTimeout(int frequency, + virEventTimeoutCallback cb, + void *opaque, + virFreeCallback ff); + +/** + * virEventPollUpdateTimeout: 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 virEventPollUpdateTimeout(int timer, int frequency); + +/** + * virEventPollRemoveTimeout: unregister a callback for a timer + * + * @timer: the timer id to remove + * + * returns -1 if the timer was not registered, 0 upon success + */ +int virEventPollRemoveTimeout(int timer); + +/** + * virEventPollInit: Initialize the event loop + * + * returns -1 if initialization failed + */ +int virEventPollInit(void); + +/** + * virEventPollRunOnce: run a single iteration of the event loop. + * + * Blocks the caller until at least one file handle has an + * event or the first timer expires. + * + * returns -1 if the event monitoring failed + */ +int virEventPollRunOnce(void); + +int virEventPollFromNativeEvents(int events); +int virEventPollToNativeEvents(int events); + + +/** + * virEventPollInterrupt: wakeup any thread waiting in poll() + * + * return -1 if wakup failed + */ +int virEventPollInterrupt(void); + + +#endif /* __VIRTD_EVENT_H__ */ diff --git a/tests/eventtest.c b/tests/eventtest.c index c087978..bc8d443 100644 --- a/tests/eventtest.c +++ b/tests/eventtest.c @@ -31,7 +31,7 @@ #include "threads.h" #include "logging.h" #include "util.h" -#include "event_poll.h" +#include "vireventpoll.h" #define NUM_FDS 31 #define NUM_TIME 31 diff --git a/tools/virsh.c b/tools/virsh.c index 07da077..5cb2e06 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -63,7 +63,6 @@ #include "xml.h" #include "libvirt/libvirt-qemu.h" #include "virfile.h" -#include "event_poll.h" #include "configmake.h" #include "threads.h" #include "vircommand.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- daemon/libvirtd.c | 2 +- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/lxc/lxc_driver.c | 2 +- src/lxc/lxc_process.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_process.c | 2 +- src/util/hooks.c | 293 ---------------------------------------------- src/util/hooks.h | 85 -------------- src/util/virhooks.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhooks.h | 85 ++++++++++++++ 12 files changed, 386 insertions(+), 386 deletions(-) delete mode 100644 src/util/hooks.c delete mode 100644 src/util/hooks.h create mode 100644 src/util/virhooks.c create mode 100644 src/util/virhooks.h diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 9b0e45a..fbf23d8 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -53,7 +53,7 @@ #include "threads.h" #include "remote.h" #include "remote_driver.h" -#include "hooks.h" +#include "virhooks.h" #include "uuid.h" #include "viraudit.h" #include "locking/lock_manager.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index 818bb4e..18d96c8 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/hooks.c src/util/hostusb.c src/util/iohelper.c src/util/iptables.c @@ -160,6 +159,7 @@ src/util/virdnsmasq.c src/util/vireventpoll.c src/util/virfile.c src/util/virhash.c +src/util/virhooks.c src/util/virinitctl.c src/util/virkeyfile.c src/util/virlockspace.c diff --git a/src/Makefile.am b/src/Makefile.am index f803de0..07ace32 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/hooks.c util/hooks.h \ util/iptables.c util/iptables.h \ util/json.c util/json.h \ util/logging.c util/logging.h \ @@ -84,6 +83,7 @@ UTIL_SOURCES = \ util/virevent.c util/virevent.h \ util/vireventpoll.c util/vireventpoll.h \ util/virfile.c util/virfile.h \ + util/virhooks.c util/virhooks.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/virobject.c util/virobject.h \ util/virpidfile.c util/virpidfile.h \ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e0e76e6..9c35406 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -50,7 +50,7 @@ #include "nodeinfo.h" #include "uuid.h" #include "stats_linux.h" -#include "hooks.h" +#include "virhooks.h" #include "virfile.h" #include "virpidfile.h" #include "fdstream.h" diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 7f66dc7..d59bd2e 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -43,7 +43,7 @@ #include "virterror_internal.h" #include "logging.h" #include "vircommand.h" -#include "hooks.h" +#include "virhooks.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0ebbf7d..0733f4e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -80,7 +80,7 @@ #include "cpu/cpu.h" #include "sysinfo.h" #include "domain_nwfilter.h" -#include "hooks.h" +#include "virhooks.h" #include "storage_file.h" #include "virfile.h" #include "fdstream.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 5dcbb07..468a92f 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -49,7 +49,7 @@ #include "rpc/virnetsocket.h" #include "storage_file.h" #include "viruri.h" -#include "hooks.h" +#include "virhooks.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 969cbc7..e528d78 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -54,7 +54,7 @@ #include "logging.h" #include "virterror_internal.h" #include "memory.h" -#include "hooks.h" +#include "virhooks.h" #include "virfile.h" #include "virpidfile.h" #include "util.h" diff --git a/src/util/hooks.c b/src/util/hooks.c deleted file mode 100644 index a6c056d..0000000 --- a/src/util/hooks.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * hooks.c: implementation of the synchronous hooks support - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * Copyright (C) 2010 Daniel Veillard - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel Veillard <veillard@redhat.com> - */ - -#include <config.h> - -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> - -#include "virterror_internal.h" -#include "hooks.h" -#include "util.h" -#include "logging.h" -#include "memory.h" -#include "virfile.h" -#include "configmake.h" -#include "vircommand.h" - -#define VIR_FROM_THIS VIR_FROM_HOOK - -#define LIBVIRT_HOOK_DIR SYSCONFDIR "/libvirt/hooks" - -VIR_ENUM_DECL(virHookDriver) -VIR_ENUM_DECL(virHookDaemonOp) -VIR_ENUM_DECL(virHookSubop) -VIR_ENUM_DECL(virHookQemuOp) -VIR_ENUM_DECL(virHookLxcOp) - -VIR_ENUM_IMPL(virHookDriver, - VIR_HOOK_DRIVER_LAST, - "daemon", - "qemu", - "lxc") - -VIR_ENUM_IMPL(virHookDaemonOp, VIR_HOOK_DAEMON_OP_LAST, - "start", - "shutdown", - "reload") - -VIR_ENUM_IMPL(virHookSubop, VIR_HOOK_SUBOP_LAST, - "-", - "begin", - "end") - -VIR_ENUM_IMPL(virHookQemuOp, VIR_HOOK_QEMU_OP_LAST, - "start", - "stopped", - "prepare", - "release", - "migrate", - "started", - "reconnect", - "attach") - -VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST, - "start", - "stopped", - "prepare", - "release", - "started", - "reconnect") - -static int virHooksFound = -1; - -/** - * virHookCheck: - * @driver: the driver name "daemon", "qemu", "lxc"... - * - * Check is there is an installed hook for the given driver, if this - * is the case register it. Then subsequent calls to virHookCall - * will call the hook if found. - * - * Returns 1 if found, 0 if not found, and -1 in case of error - */ -static int -virHookCheck(int no, const char *driver) { - char *path; - int ret; - - if (driver == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Invalid hook name for #%d"), no); - return -1; - } - - ret = virBuildPath(&path, LIBVIRT_HOOK_DIR, driver); - if ((ret < 0) || (path == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to build path for %s hook"), - driver); - return -1; - } - - if (!virFileExists(path)) { - ret = 0; - VIR_DEBUG("No hook script %s", path); - } else if (!virFileIsExecutable(path)) { - ret = 0; - VIR_WARN("Non-executable hook script %s", path); - } else { - ret = 1; - VIR_DEBUG("Found hook script %s", path); - } - - VIR_FREE(path); - return ret; -} - -/* - * virHookInitialize: - * - * Initialize synchronous hooks support. - * Check is there is an installed hook for all the drivers - * - * Returns the number of hooks found or -1 in case of failure - */ -int -virHookInitialize(void) { - int i, res, ret = 0; - - virHooksFound = 0; - for (i = 0;i < VIR_HOOK_DRIVER_LAST;i++) { - res = virHookCheck(i, virHookDriverTypeToString(i)); - if (res < 0) - return -1; - - if (res == 1) { - virHooksFound |= (1 << i); - ret++; - } - } - return ret; -} - -/** - * virHookPresent: - * @driver: the driver number (from virHookDriver enum) - * - * Check if a hook exists for the given driver, this is needed - * to avoid unnecessary work if the hook is not present - * - * Returns 1 if present, 0 otherwise - */ -int -virHookPresent(int driver) { - if ((driver < VIR_HOOK_DRIVER_DAEMON) || - (driver >= VIR_HOOK_DRIVER_LAST)) - return 0; - if (virHooksFound == -1) - return 0; - - if ((virHooksFound & (1 << driver)) == 0) - return 0; - return 1; -} - -/** - * virHookCall: - * @driver: the driver number (from virHookDriver enum) - * @id: an id for the object '-' if non available for example on daemon hooks - * @op: the operation on the id e.g. VIR_HOOK_QEMU_OP_START - * @sub_op: a sub_operation, currently unused - * @extra: optional string information - * @input: extra input given to the script on stdin - * @output: optional address of variable to store malloced result buffer - * - * Implement a hook call, where the external script for the driver is - * called with the given information. This is a synchronous call, we wait for - * execution completion. If @output is non-NULL, *output is guaranteed to be - * allocated after successful virHookCall, and is best-effort allocated after - * failed virHookCall; the caller is responsible for freeing *output. - * - * Returns: 0 if the execution succeeded, 1 if the script was not found or - * invalid parameters, and -1 if script returned an error - */ -int -virHookCall(int driver, - const char *id, - int op, - int sub_op, - const char *extra, - const char *input, - char **output) -{ - int ret; - char *path; - virCommandPtr cmd; - const char *drvstr; - const char *opstr; - const char *subopstr; - - if (output) - *output = NULL; - - if ((driver < VIR_HOOK_DRIVER_DAEMON) || - (driver >= VIR_HOOK_DRIVER_LAST)) - return 1; - - /* - * We cache the availability of the script to minimize impact at - * runtime if no script is defined, this is being reset on SIGHUP - */ - if ((virHooksFound == -1) || - ((driver == VIR_HOOK_DRIVER_DAEMON) && - (op == VIR_HOOK_DAEMON_OP_RELOAD || - op == VIR_HOOK_DAEMON_OP_SHUTDOWN))) - virHookInitialize(); - - if ((virHooksFound & (1 << driver)) == 0) - return 1; - - drvstr = virHookDriverTypeToString(driver); - - opstr = NULL; - switch (driver) { - case VIR_HOOK_DRIVER_DAEMON: - opstr = virHookDaemonOpTypeToString(op); - break; - case VIR_HOOK_DRIVER_QEMU: - opstr = virHookQemuOpTypeToString(op); - break; - case VIR_HOOK_DRIVER_LXC: - opstr = virHookLxcOpTypeToString(op); - break; - } - if (opstr == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Hook for %s, failed to find operation #%d"), - drvstr, op); - return 1; - } - subopstr = virHookSubopTypeToString(sub_op); - if (subopstr == NULL) - subopstr = "-"; - if (extra == NULL) - extra = "-"; - - ret = virBuildPath(&path, LIBVIRT_HOOK_DIR, drvstr); - if ((ret < 0) || (path == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to build path for %s hook"), - drvstr); - return -1; - } - - VIR_DEBUG("Calling hook opstr=%s subopstr=%s extra=%s", - opstr, subopstr, extra); - - cmd = virCommandNewArgList(path, id, opstr, subopstr, extra, NULL); - - virCommandAddEnvPassCommon(cmd); - - if (input) - virCommandSetInputBuffer(cmd, input); - if (output) - virCommandSetOutputBuffer(cmd, output); - - ret = virCommandRun(cmd, NULL); - if (ret < 0) { - /* Convert INTERNAL_ERROR into known error. */ - virErrorPtr err = virGetLastError(); - virReportError(VIR_ERR_HOOK_SCRIPT_FAILED, "%s", err->message); - } - - virCommandFree(cmd); - - VIR_FREE(path); - - return ret; -} diff --git a/src/util/hooks.h b/src/util/hooks.h deleted file mode 100644 index 0ca376f..0000000 --- a/src/util/hooks.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * hook.h: internal entry points needed for synchronous hooks support - * - * Copyright (C) 2010 Red Hat, Inc. - * Copyright (C) 2010 Daniel Veillard - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel Veillard <veillard@redhat.com> - */ - -#ifndef __VIR_HOOKS_H__ -# define __VIR_HOOKS_H__ - -# include "internal.h" -# include "util.h" - -enum virHookDriverType { - VIR_HOOK_DRIVER_DAEMON = 0, /* Daemon related events */ - VIR_HOOK_DRIVER_QEMU, /* QEmu domains related events */ - VIR_HOOK_DRIVER_LXC, /* LXC domains related events */ - - VIR_HOOK_DRIVER_LAST, -}; - -enum virHookDaemonOpType { - VIR_HOOK_DAEMON_OP_START, /* daemon is about to start */ - VIR_HOOK_DAEMON_OP_SHUTDOWN, /* daemon is about to shutdown */ - VIR_HOOK_DAEMON_OP_RELOAD, /* driver reload with SIGHUP */ - - VIR_HOOK_DAEMON_OP_LAST, -}; - -enum virHookSubopType { - VIR_HOOK_SUBOP_NONE, /* no sub-operation */ - VIR_HOOK_SUBOP_BEGIN, /* beginning of the operation */ - VIR_HOOK_SUBOP_END, /* end of the operation */ - - VIR_HOOK_SUBOP_LAST, -}; - -enum virHookQemuOpType { - VIR_HOOK_QEMU_OP_START, /* domain is about to start */ - VIR_HOOK_QEMU_OP_STOPPED, /* domain has stopped */ - VIR_HOOK_QEMU_OP_PREPARE, /* domain startup initiated */ - VIR_HOOK_QEMU_OP_RELEASE, /* domain destruction is over */ - VIR_HOOK_QEMU_OP_MIGRATE, /* domain is being migrated */ - VIR_HOOK_QEMU_OP_STARTED, /* domain has started */ - VIR_HOOK_QEMU_OP_RECONNECT, /* domain is being reconnected by libvirt */ - VIR_HOOK_QEMU_OP_ATTACH, /* domain is being attached to be libvirt */ - - VIR_HOOK_QEMU_OP_LAST, -}; - -enum virHookLxcOpType { - VIR_HOOK_LXC_OP_START, /* domain is about to start */ - VIR_HOOK_LXC_OP_STOPPED, /* domain has stopped */ - VIR_HOOK_LXC_OP_PREPARE, /* domain startup initiated */ - VIR_HOOK_LXC_OP_RELEASE, /* domain destruction is over */ - VIR_HOOK_LXC_OP_STARTED, /* domain has started */ - VIR_HOOK_LXC_OP_RECONNECT, /* domain is being reconnected by libvirt */ - - VIR_HOOK_LXC_OP_LAST, -}; - -int virHookInitialize(void); - -int virHookPresent(int driver); - -int virHookCall(int driver, const char *id, int op, int sub_op, - const char *extra, const char *input, char **output); - -#endif /* __VIR_HOOKS_H__ */ diff --git a/src/util/virhooks.c b/src/util/virhooks.c new file mode 100644 index 0000000..4a732ff --- /dev/null +++ b/src/util/virhooks.c @@ -0,0 +1,293 @@ +/* + * hooks.c: implementation of the synchronous hooks support + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright (C) 2010 Daniel Veillard + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#include "virterror_internal.h" +#include "virhooks.h" +#include "util.h" +#include "logging.h" +#include "memory.h" +#include "virfile.h" +#include "configmake.h" +#include "vircommand.h" + +#define VIR_FROM_THIS VIR_FROM_HOOK + +#define LIBVIRT_HOOK_DIR SYSCONFDIR "/libvirt/hooks" + +VIR_ENUM_DECL(virHookDriver) +VIR_ENUM_DECL(virHookDaemonOp) +VIR_ENUM_DECL(virHookSubop) +VIR_ENUM_DECL(virHookQemuOp) +VIR_ENUM_DECL(virHookLxcOp) + +VIR_ENUM_IMPL(virHookDriver, + VIR_HOOK_DRIVER_LAST, + "daemon", + "qemu", + "lxc") + +VIR_ENUM_IMPL(virHookDaemonOp, VIR_HOOK_DAEMON_OP_LAST, + "start", + "shutdown", + "reload") + +VIR_ENUM_IMPL(virHookSubop, VIR_HOOK_SUBOP_LAST, + "-", + "begin", + "end") + +VIR_ENUM_IMPL(virHookQemuOp, VIR_HOOK_QEMU_OP_LAST, + "start", + "stopped", + "prepare", + "release", + "migrate", + "started", + "reconnect", + "attach") + +VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST, + "start", + "stopped", + "prepare", + "release", + "started", + "reconnect") + +static int virHooksFound = -1; + +/** + * virHookCheck: + * @driver: the driver name "daemon", "qemu", "lxc"... + * + * Check is there is an installed hook for the given driver, if this + * is the case register it. Then subsequent calls to virHookCall + * will call the hook if found. + * + * Returns 1 if found, 0 if not found, and -1 in case of error + */ +static int +virHookCheck(int no, const char *driver) { + char *path; + int ret; + + if (driver == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid hook name for #%d"), no); + return -1; + } + + ret = virBuildPath(&path, LIBVIRT_HOOK_DIR, driver); + if ((ret < 0) || (path == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to build path for %s hook"), + driver); + return -1; + } + + if (!virFileExists(path)) { + ret = 0; + VIR_DEBUG("No hook script %s", path); + } else if (!virFileIsExecutable(path)) { + ret = 0; + VIR_WARN("Non-executable hook script %s", path); + } else { + ret = 1; + VIR_DEBUG("Found hook script %s", path); + } + + VIR_FREE(path); + return ret; +} + +/* + * virHookInitialize: + * + * Initialize synchronous hooks support. + * Check is there is an installed hook for all the drivers + * + * Returns the number of hooks found or -1 in case of failure + */ +int +virHookInitialize(void) { + int i, res, ret = 0; + + virHooksFound = 0; + for (i = 0;i < VIR_HOOK_DRIVER_LAST;i++) { + res = virHookCheck(i, virHookDriverTypeToString(i)); + if (res < 0) + return -1; + + if (res == 1) { + virHooksFound |= (1 << i); + ret++; + } + } + return ret; +} + +/** + * virHookPresent: + * @driver: the driver number (from virHookDriver enum) + * + * Check if a hook exists for the given driver, this is needed + * to avoid unnecessary work if the hook is not present + * + * Returns 1 if present, 0 otherwise + */ +int +virHookPresent(int driver) { + if ((driver < VIR_HOOK_DRIVER_DAEMON) || + (driver >= VIR_HOOK_DRIVER_LAST)) + return 0; + if (virHooksFound == -1) + return 0; + + if ((virHooksFound & (1 << driver)) == 0) + return 0; + return 1; +} + +/** + * virHookCall: + * @driver: the driver number (from virHookDriver enum) + * @id: an id for the object '-' if non available for example on daemon hooks + * @op: the operation on the id e.g. VIR_HOOK_QEMU_OP_START + * @sub_op: a sub_operation, currently unused + * @extra: optional string information + * @input: extra input given to the script on stdin + * @output: optional address of variable to store malloced result buffer + * + * Implement a hook call, where the external script for the driver is + * called with the given information. This is a synchronous call, we wait for + * execution completion. If @output is non-NULL, *output is guaranteed to be + * allocated after successful virHookCall, and is best-effort allocated after + * failed virHookCall; the caller is responsible for freeing *output. + * + * Returns: 0 if the execution succeeded, 1 if the script was not found or + * invalid parameters, and -1 if script returned an error + */ +int +virHookCall(int driver, + const char *id, + int op, + int sub_op, + const char *extra, + const char *input, + char **output) +{ + int ret; + char *path; + virCommandPtr cmd; + const char *drvstr; + const char *opstr; + const char *subopstr; + + if (output) + *output = NULL; + + if ((driver < VIR_HOOK_DRIVER_DAEMON) || + (driver >= VIR_HOOK_DRIVER_LAST)) + return 1; + + /* + * We cache the availability of the script to minimize impact at + * runtime if no script is defined, this is being reset on SIGHUP + */ + if ((virHooksFound == -1) || + ((driver == VIR_HOOK_DRIVER_DAEMON) && + (op == VIR_HOOK_DAEMON_OP_RELOAD || + op == VIR_HOOK_DAEMON_OP_SHUTDOWN))) + virHookInitialize(); + + if ((virHooksFound & (1 << driver)) == 0) + return 1; + + drvstr = virHookDriverTypeToString(driver); + + opstr = NULL; + switch (driver) { + case VIR_HOOK_DRIVER_DAEMON: + opstr = virHookDaemonOpTypeToString(op); + break; + case VIR_HOOK_DRIVER_QEMU: + opstr = virHookQemuOpTypeToString(op); + break; + case VIR_HOOK_DRIVER_LXC: + opstr = virHookLxcOpTypeToString(op); + break; + } + if (opstr == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Hook for %s, failed to find operation #%d"), + drvstr, op); + return 1; + } + subopstr = virHookSubopTypeToString(sub_op); + if (subopstr == NULL) + subopstr = "-"; + if (extra == NULL) + extra = "-"; + + ret = virBuildPath(&path, LIBVIRT_HOOK_DIR, drvstr); + if ((ret < 0) || (path == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to build path for %s hook"), + drvstr); + return -1; + } + + VIR_DEBUG("Calling hook opstr=%s subopstr=%s extra=%s", + opstr, subopstr, extra); + + cmd = virCommandNewArgList(path, id, opstr, subopstr, extra, NULL); + + virCommandAddEnvPassCommon(cmd); + + if (input) + virCommandSetInputBuffer(cmd, input); + if (output) + virCommandSetOutputBuffer(cmd, output); + + ret = virCommandRun(cmd, NULL); + if (ret < 0) { + /* Convert INTERNAL_ERROR into known error. */ + virErrorPtr err = virGetLastError(); + virReportError(VIR_ERR_HOOK_SCRIPT_FAILED, "%s", err->message); + } + + virCommandFree(cmd); + + VIR_FREE(path); + + return ret; +} diff --git a/src/util/virhooks.h b/src/util/virhooks.h new file mode 100644 index 0000000..0ca376f --- /dev/null +++ b/src/util/virhooks.h @@ -0,0 +1,85 @@ +/* + * hook.h: internal entry points needed for synchronous hooks support + * + * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2010 Daniel Veillard + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + +#ifndef __VIR_HOOKS_H__ +# define __VIR_HOOKS_H__ + +# include "internal.h" +# include "util.h" + +enum virHookDriverType { + VIR_HOOK_DRIVER_DAEMON = 0, /* Daemon related events */ + VIR_HOOK_DRIVER_QEMU, /* QEmu domains related events */ + VIR_HOOK_DRIVER_LXC, /* LXC domains related events */ + + VIR_HOOK_DRIVER_LAST, +}; + +enum virHookDaemonOpType { + VIR_HOOK_DAEMON_OP_START, /* daemon is about to start */ + VIR_HOOK_DAEMON_OP_SHUTDOWN, /* daemon is about to shutdown */ + VIR_HOOK_DAEMON_OP_RELOAD, /* driver reload with SIGHUP */ + + VIR_HOOK_DAEMON_OP_LAST, +}; + +enum virHookSubopType { + VIR_HOOK_SUBOP_NONE, /* no sub-operation */ + VIR_HOOK_SUBOP_BEGIN, /* beginning of the operation */ + VIR_HOOK_SUBOP_END, /* end of the operation */ + + VIR_HOOK_SUBOP_LAST, +}; + +enum virHookQemuOpType { + VIR_HOOK_QEMU_OP_START, /* domain is about to start */ + VIR_HOOK_QEMU_OP_STOPPED, /* domain has stopped */ + VIR_HOOK_QEMU_OP_PREPARE, /* domain startup initiated */ + VIR_HOOK_QEMU_OP_RELEASE, /* domain destruction is over */ + VIR_HOOK_QEMU_OP_MIGRATE, /* domain is being migrated */ + VIR_HOOK_QEMU_OP_STARTED, /* domain has started */ + VIR_HOOK_QEMU_OP_RECONNECT, /* domain is being reconnected by libvirt */ + VIR_HOOK_QEMU_OP_ATTACH, /* domain is being attached to be libvirt */ + + VIR_HOOK_QEMU_OP_LAST, +}; + +enum virHookLxcOpType { + VIR_HOOK_LXC_OP_START, /* domain is about to start */ + VIR_HOOK_LXC_OP_STOPPED, /* domain has stopped */ + VIR_HOOK_LXC_OP_PREPARE, /* domain startup initiated */ + VIR_HOOK_LXC_OP_RELEASE, /* domain destruction is over */ + VIR_HOOK_LXC_OP_STARTED, /* domain has started */ + VIR_HOOK_LXC_OP_RECONNECT, /* domain is being reconnected by libvirt */ + + VIR_HOOK_LXC_OP_LAST, +}; + +int virHookInitialize(void); + +int virHookPresent(int driver); + +int virHookCall(int driver, const char *id, int op, int sub_op, + const char *extra, const char *input, char **output); + +#endif /* __VIR_HOOKS_H__ */ -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/qemu/qemu_cgroup.h | 2 +- src/qemu/qemu_conf.h | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hostdev.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_selinux.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/util/hostusb.c | 506 --------------------------------------- src/util/hostusb.h | 87 ------- src/util/virusb.c | 506 +++++++++++++++++++++++++++++++++++++++ src/util/virusb.h | 87 +++++++ 14 files changed, 603 insertions(+), 603 deletions(-) delete mode 100644 src/util/hostusb.c delete mode 100644 src/util/hostusb.h create mode 100644 src/util/virusb.c create mode 100644 src/util/virusb.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 18d96c8..3f3362c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -137,7 +137,6 @@ src/storage/storage_driver.c src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c -src/util/hostusb.c src/util/iohelper.c src/util/iptables.c src/util/json.c @@ -181,6 +180,7 @@ src/util/virterror_internal.h src/util/virtime.c src/util/virtypedparam.c src/util/viruri.c +src/util/virusb.c src/util/xml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c diff --git a/src/Makefile.am b/src/Makefile.am index 07ace32..4f89bdc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,7 +59,6 @@ UTIL_SOURCES = \ util/memory.c util/memory.h \ util/pci.c util/pci.h \ util/processinfo.c util/processinfo.h \ - util/hostusb.c util/hostusb.h \ util/sexpr.c util/sexpr.h \ util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ @@ -115,6 +114,7 @@ UTIL_SOURCES = \ util/virsocketaddr.h util/virsocketaddr.c \ util/virstring.h util/virstring.c \ util/virtime.h util/virtime.c \ + util/virusb.c util/virusb.h \ util/viruri.h util/viruri.c EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \ diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h index e212581..75ef514 100644 --- a/src/qemu/qemu_cgroup.h +++ b/src/qemu/qemu_cgroup.h @@ -24,7 +24,7 @@ #ifndef __QEMU_CGROUP_H__ # define __QEMU_CGROUP_H__ -# include "hostusb.h" +# include "virusb.h" # include "domain_conf.h" # include "qemu_conf.h" diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 5499203..283251a 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -36,7 +36,7 @@ # include "security/security_manager.h" # include "vircgroup.h" # include "pci.h" -# include "hostusb.h" +# include "virusb.h" # include "cpu_conf.h" # include "driver.h" # include "virbitmap.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0733f4e..79f42fb 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -73,7 +73,7 @@ #include "domain_audit.h" #include "node_device_conf.h" #include "pci.h" -#include "hostusb.h" +#include "virusb.h" #include "processinfo.h" #include "libvirt_internal.h" #include "xml.h" diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index a748b8b..aa000d1 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -28,7 +28,7 @@ #include "virterror_internal.h" #include "memory.h" #include "pci.h" -#include "hostusb.h" +#include "virusb.h" #include "virnetdev.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index ff8aea1..034eb04 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -44,7 +44,7 @@ #include "datatypes.h" #include "uuid.h" #include "pci.h" -#include "hostusb.h" +#include "virusb.h" #include "virfile.h" #include "configmake.h" #include "vircommand.h" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index b07c132..9f5d39d 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -29,7 +29,7 @@ #include "memory.h" #include "logging.h" #include "pci.h" -#include "hostusb.h" +#include "virusb.h" #include "storage_file.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 287312a..eb4f253 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -38,7 +38,7 @@ #include "memory.h" #include "logging.h" #include "pci.h" -#include "hostusb.h" +#include "virusb.h" #include "storage_file.h" #include "virfile.h" #include "virhash.h" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index bfd6305..d92b3d4 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -50,7 +50,7 @@ #include "domain_conf.h" #include "xml.h" #include "uuid.h" -#include "hostusb.h" +#include "virusb.h" #include "pci.h" #include "virfile.h" #include "configmake.h" diff --git a/src/util/hostusb.c b/src/util/hostusb.c deleted file mode 100644 index 81a9f5a..0000000 --- a/src/util/hostusb.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright (C) 2009-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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_SYSFS "/sys/bus/usb" -#define USB_DEVFS "/dev/bus/usb/" -#define USB_ID_LEN 10 /* "1234 5678" */ -#define USB_ADDR_LEN 8 /* "123:456" */ - -/* For virReportOOMError() and virReportSystemError() */ -#define VIR_FROM_THIS VIR_FROM_NONE - -struct _usbDevice { - unsigned int bus; - unsigned int dev; - - char name[USB_ADDR_LEN]; /* domain:bus:slot.function */ - char id[USB_ID_LEN]; /* product vendor */ - char *path; - const char *used_by; /* name of the domain using this dev */ -}; - -struct _usbDeviceList { - unsigned int count; - usbDevice **devs; -}; - -typedef enum { - USB_DEVICE_ALL = 0, - USB_DEVICE_FIND_BY_VENDOR = 1 << 0, - USB_DEVICE_FIND_BY_BUS = 1 << 1, -} usbDeviceFindFlags; - -static int usbSysReadFile(const char *f_name, const char *d_name, - int base, unsigned int *value) -{ - int ret = -1, tmp; - char *buf = NULL; - char *filename = NULL; - char *ignore = NULL; - - tmp = virAsprintf(&filename, USB_SYSFS "/devices/%s/%s", d_name, f_name); - if (tmp < 0) { - virReportOOMError(); - goto cleanup; - } - - if (virFileReadAll(filename, 1024, &buf) < 0) - goto cleanup; - - if (virStrToLong_ui(buf, &ignore, base, value) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Could not parse usb file %s"), filename); - goto cleanup; - } - - ret = 0; -cleanup: - VIR_FREE(filename); - VIR_FREE(buf); - return ret; -} - -static usbDeviceList * -usbDeviceSearch(unsigned int vendor, - unsigned int product, - unsigned int bus, - unsigned int devno, - unsigned int flags) -{ - DIR *dir = NULL; - bool found = false; - char *ignore = NULL; - struct dirent *de; - usbDeviceList *list = NULL, *ret = NULL; - usbDevice *usb; - - if (!(list = usbDeviceListNew())) - goto cleanup; - - dir = opendir(USB_SYSFS "/devices"); - if (!dir) { - virReportSystemError(errno, - _("Could not open directory %s"), - USB_SYSFS "/devices"); - goto cleanup; - } - - while ((de = readdir(dir))) { - unsigned int found_prod, found_vend, found_bus, found_devno; - char *tmpstr = de->d_name; - - if (de->d_name[0] == '.' || strchr(de->d_name, ':')) - continue; - - if (usbSysReadFile("idVendor", de->d_name, - 16, &found_vend) < 0) - goto cleanup; - - if (usbSysReadFile("idProduct", de->d_name, - 16, &found_prod) < 0) - goto cleanup; - - if (STRPREFIX(de->d_name, "usb")) - tmpstr += 3; - - if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to parse dir name '%s'"), - de->d_name); - goto cleanup; - } - - if (usbSysReadFile("devnum", de->d_name, - 10, &found_devno) < 0) - goto cleanup; - - if ((flags & USB_DEVICE_FIND_BY_VENDOR) && - (found_prod != product || found_vend != vendor)) - continue; - - if (flags & USB_DEVICE_FIND_BY_BUS) { - if (found_bus != bus || found_devno != devno) - continue; - found = true; - } - - usb = usbGetDevice(found_bus, found_devno); - if (!usb) - goto cleanup; - - if (usbDeviceListAdd(list, usb) < 0) { - usbFreeDevice(usb); - goto cleanup; - } - - if (found) - break; - } - ret = list; - -cleanup: - if (dir) { - int saved_errno = errno; - closedir(dir); - errno = saved_errno; - } - - if (!ret) - usbDeviceListFree(list); - return ret; -} - -int -usbFindDeviceByVendor(unsigned int vendor, - unsigned product, - bool mandatory, - usbDeviceList **devices) -{ - usbDeviceList *list; - int count; - - if (!(list = usbDeviceSearch(vendor, product, 0 , 0, - USB_DEVICE_FIND_BY_VENDOR))) - return -1; - - if (list->count == 0) { - usbDeviceListFree(list); - if (!mandatory) { - VIR_DEBUG("Did not find USB device %x:%x", - vendor, product); - if (devices) - *devices = NULL; - return 0; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Did not find USB device %x:%x"), vendor, product); - return -1; - } - - count = list->count; - if (devices) - *devices = list; - else - usbDeviceListFree(list); - - return count; -} - -int -usbFindDeviceByBus(unsigned int bus, - unsigned devno, - bool mandatory, - usbDevice **usb) -{ - usbDeviceList *list; - - if (!(list = usbDeviceSearch(0, 0, bus, devno, - USB_DEVICE_FIND_BY_BUS))) - return -1; - - if (list->count == 0) { - usbDeviceListFree(list); - if (!mandatory) { - VIR_DEBUG("Did not find USB device bus:%u device:%u", - bus, devno); - if (usb) - *usb = NULL; - return 0; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Did not find USB device bus:%u device:%u"), - bus, devno); - return -1; - } - - if (usb) { - *usb = usbDeviceListGet(list, 0); - usbDeviceListSteal(list, *usb); - } - usbDeviceListFree(list); - - return 0; -} - -int -usbFindDevice(unsigned int vendor, - unsigned int product, - unsigned int bus, - unsigned int devno, - bool mandatory, - usbDevice **usb) -{ - usbDeviceList *list; - - unsigned int flags = USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BUS; - if (!(list = usbDeviceSearch(vendor, product, bus, devno, flags))) - return -1; - - if (list->count == 0) { - usbDeviceListFree(list); - if (!mandatory) { - VIR_DEBUG("Did not find USB device %x:%x bus:%u device:%u", - vendor, product, bus, devno); - if (usb) - *usb = NULL; - return 0; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Did not find USB device %x:%x bus:%u device:%u"), - vendor, product, bus, devno); - return -1; - } - - if (usb) { - *usb = usbDeviceListGet(list, 0); - usbDeviceListSteal(list, *usb); - } - usbDeviceListFree(list); - - return 0; -} - -usbDevice * -usbGetDevice(unsigned int bus, - unsigned int devno) -{ - usbDevice *dev; - - if (VIR_ALLOC(dev) < 0) { - virReportOOMError(); - return NULL; - } - - dev->bus = bus; - dev->dev = devno; - - if (snprintf(dev->name, sizeof(dev->name), "%.3o:%.3o", - dev->bus, dev->dev) >= sizeof(dev->name)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("dev->name buffer overflow: %.3o:%.3o"), - dev->bus, dev->dev); - usbFreeDevice(dev); - return NULL; - } - if (virAsprintf(&dev->path, USB_DEVFS "%03d/%03d", - dev->bus, dev->dev) < 0) { - virReportOOMError(); - usbFreeDevice(dev); - return NULL; - } - - /* XXX fixme. this should be product/vendor */ - if (snprintf(dev->id, sizeof(dev->id), "%d %d", dev->bus, - dev->dev) >= sizeof(dev->id)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("dev->id buffer overflow: %d %d"), - dev->bus, dev->dev); - usbFreeDevice(dev); - return NULL; - } - - VIR_DEBUG("%s %s: initialized", dev->id, dev->name); - - return dev; -} - -void -usbFreeDevice(usbDevice *dev) -{ - VIR_DEBUG("%s %s: freeing", dev->id, dev->name); - VIR_FREE(dev->path); - VIR_FREE(dev); -} - - -void usbDeviceSetUsedBy(usbDevice *dev, - const char *name) -{ - dev->used_by = name; -} - -const char * usbDeviceGetUsedBy(usbDevice *dev) -{ - return dev->used_by; -} - -const char *usbDeviceGetName(usbDevice *dev) -{ - return dev->name; -} - -unsigned int usbDeviceGetBus(usbDevice *dev) -{ - return dev->bus; -} - - -unsigned int usbDeviceGetDevno(usbDevice *dev) -{ - return dev->dev; -} - - -int usbDeviceFileIterate(usbDevice *dev, - usbDeviceFileActor actor, - void *opaque) -{ - return (actor)(dev, dev->path, opaque); -} - -usbDeviceList * -usbDeviceListNew(void) -{ - usbDeviceList *list; - - if (VIR_ALLOC(list) < 0) { - virReportOOMError(); - return NULL; - } - - return list; -} - -void -usbDeviceListFree(usbDeviceList *list) -{ - int i; - - if (!list) - return; - - for (i = 0; i < list->count; i++) - usbFreeDevice(list->devs[i]); - - VIR_FREE(list->devs); - VIR_FREE(list); -} - -int -usbDeviceListAdd(usbDeviceList *list, - usbDevice *dev) -{ - if (usbDeviceListFind(list, dev)) { - virReportError(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(); - return -1; - } - - list->devs[list->count++] = dev; - - return 0; -} - -usbDevice * -usbDeviceListGet(usbDeviceList *list, - int idx) -{ - if (idx >= list->count || - idx < 0) - return NULL; - - return list->devs[idx]; -} - -int -usbDeviceListCount(usbDeviceList *list) -{ - return list->count; -} - -usbDevice * -usbDeviceListSteal(usbDeviceList *list, - usbDevice *dev) -{ - usbDevice *ret = NULL; - int i; - - for (i = 0; i < list->count; i++) { - if (list->devs[i]->bus != dev->bus || - list->devs[i]->dev != dev->dev) - continue; - - ret = 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; - } - return ret; -} - -void -usbDeviceListDel(usbDeviceList *list, - usbDevice *dev) -{ - usbDevice *ret = usbDeviceListSteal(list, dev); - if (ret) - usbFreeDevice(ret); -} - -usbDevice * -usbDeviceListFind(usbDeviceList *list, - usbDevice *dev) -{ - int i; - - for (i = 0; i < list->count; i++) { - if (list->devs[i]->bus == dev->bus && - list->devs[i]->dev == dev->dev) - return list->devs[i]; - } - - return NULL; -} diff --git a/src/util/hostusb.h b/src/util/hostusb.h deleted file mode 100644 index 4f55fdc..0000000 --- a/src/util/hostusb.h +++ /dev/null @@ -1,87 +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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Daniel P. Berrange <berrange@redhat.com> - * Michal Privoznik <mprivozn@redhat.com> - */ - -#ifndef __VIR_USB_H__ -# define __VIR_USB_H__ - -# include "internal.h" - -typedef struct _usbDevice usbDevice; -typedef struct _usbDeviceList usbDeviceList; - -usbDevice *usbGetDevice(unsigned int bus, - unsigned int devno); - -int usbFindDeviceByBus(unsigned int bus, - unsigned int devno, - bool mandatory, - usbDevice **usb); - -int usbFindDeviceByVendor(unsigned int vendor, - unsigned int product, - bool mandatory, - usbDeviceList **devices); - -int usbFindDevice(unsigned int vendor, - unsigned int product, - unsigned int bus, - unsigned int devno, - bool mandatory, - usbDevice **usb); - -void usbFreeDevice (usbDevice *dev); -void usbDeviceSetUsedBy(usbDevice *dev, const char *name); -const char *usbDeviceGetUsedBy(usbDevice *dev); -const char *usbDeviceGetName(usbDevice *dev); - -unsigned int usbDeviceGetBus(usbDevice *dev); -unsigned int usbDeviceGetDevno(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)(usbDevice *dev, - const char *path, void *opaque); - -int usbDeviceFileIterate(usbDevice *dev, - usbDeviceFileActor actor, - void *opaque); - -usbDeviceList *usbDeviceListNew(void); -void usbDeviceListFree(usbDeviceList *list); -int usbDeviceListAdd(usbDeviceList *list, - usbDevice *dev); -usbDevice * usbDeviceListGet(usbDeviceList *list, - int idx); -int usbDeviceListCount(usbDeviceList *list); -usbDevice * usbDeviceListSteal(usbDeviceList *list, - usbDevice *dev); -void usbDeviceListDel(usbDeviceList *list, - usbDevice *dev); -usbDevice * usbDeviceListFind(usbDeviceList *list, - usbDevice *dev); - -#endif /* __VIR_USB_H__ */ diff --git a/src/util/virusb.c b/src/util/virusb.c new file mode 100644 index 0000000..b9c81ed --- /dev/null +++ b/src/util/virusb.c @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2009-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * 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 "virusb.h" +#include "logging.h" +#include "memory.h" +#include "util.h" +#include "virterror_internal.h" + +#define USB_SYSFS "/sys/bus/usb" +#define USB_DEVFS "/dev/bus/usb/" +#define USB_ID_LEN 10 /* "1234 5678" */ +#define USB_ADDR_LEN 8 /* "123:456" */ + +/* For virReportOOMError() and virReportSystemError() */ +#define VIR_FROM_THIS VIR_FROM_NONE + +struct _usbDevice { + unsigned int bus; + unsigned int dev; + + char name[USB_ADDR_LEN]; /* domain:bus:slot.function */ + char id[USB_ID_LEN]; /* product vendor */ + char *path; + const char *used_by; /* name of the domain using this dev */ +}; + +struct _usbDeviceList { + unsigned int count; + usbDevice **devs; +}; + +typedef enum { + USB_DEVICE_ALL = 0, + USB_DEVICE_FIND_BY_VENDOR = 1 << 0, + USB_DEVICE_FIND_BY_BUS = 1 << 1, +} usbDeviceFindFlags; + +static int usbSysReadFile(const char *f_name, const char *d_name, + int base, unsigned int *value) +{ + int ret = -1, tmp; + char *buf = NULL; + char *filename = NULL; + char *ignore = NULL; + + tmp = virAsprintf(&filename, USB_SYSFS "/devices/%s/%s", d_name, f_name); + if (tmp < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(filename, 1024, &buf) < 0) + goto cleanup; + + if (virStrToLong_ui(buf, &ignore, base, value) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse usb file %s"), filename); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(filename); + VIR_FREE(buf); + return ret; +} + +static usbDeviceList * +usbDeviceSearch(unsigned int vendor, + unsigned int product, + unsigned int bus, + unsigned int devno, + unsigned int flags) +{ + DIR *dir = NULL; + bool found = false; + char *ignore = NULL; + struct dirent *de; + usbDeviceList *list = NULL, *ret = NULL; + usbDevice *usb; + + if (!(list = usbDeviceListNew())) + goto cleanup; + + dir = opendir(USB_SYSFS "/devices"); + if (!dir) { + virReportSystemError(errno, + _("Could not open directory %s"), + USB_SYSFS "/devices"); + goto cleanup; + } + + while ((de = readdir(dir))) { + unsigned int found_prod, found_vend, found_bus, found_devno; + char *tmpstr = de->d_name; + + if (de->d_name[0] == '.' || strchr(de->d_name, ':')) + continue; + + if (usbSysReadFile("idVendor", de->d_name, + 16, &found_vend) < 0) + goto cleanup; + + if (usbSysReadFile("idProduct", de->d_name, + 16, &found_prod) < 0) + goto cleanup; + + if (STRPREFIX(de->d_name, "usb")) + tmpstr += 3; + + if (virStrToLong_ui(tmpstr, &ignore, 10, &found_bus) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to parse dir name '%s'"), + de->d_name); + goto cleanup; + } + + if (usbSysReadFile("devnum", de->d_name, + 10, &found_devno) < 0) + goto cleanup; + + if ((flags & USB_DEVICE_FIND_BY_VENDOR) && + (found_prod != product || found_vend != vendor)) + continue; + + if (flags & USB_DEVICE_FIND_BY_BUS) { + if (found_bus != bus || found_devno != devno) + continue; + found = true; + } + + usb = usbGetDevice(found_bus, found_devno); + if (!usb) + goto cleanup; + + if (usbDeviceListAdd(list, usb) < 0) { + usbFreeDevice(usb); + goto cleanup; + } + + if (found) + break; + } + ret = list; + +cleanup: + if (dir) { + int saved_errno = errno; + closedir(dir); + errno = saved_errno; + } + + if (!ret) + usbDeviceListFree(list); + return ret; +} + +int +usbFindDeviceByVendor(unsigned int vendor, + unsigned product, + bool mandatory, + usbDeviceList **devices) +{ + usbDeviceList *list; + int count; + + if (!(list = usbDeviceSearch(vendor, product, 0 , 0, + USB_DEVICE_FIND_BY_VENDOR))) + return -1; + + if (list->count == 0) { + usbDeviceListFree(list); + if (!mandatory) { + VIR_DEBUG("Did not find USB device %x:%x", + vendor, product); + if (devices) + *devices = NULL; + return 0; + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Did not find USB device %x:%x"), vendor, product); + return -1; + } + + count = list->count; + if (devices) + *devices = list; + else + usbDeviceListFree(list); + + return count; +} + +int +usbFindDeviceByBus(unsigned int bus, + unsigned devno, + bool mandatory, + usbDevice **usb) +{ + usbDeviceList *list; + + if (!(list = usbDeviceSearch(0, 0, bus, devno, + USB_DEVICE_FIND_BY_BUS))) + return -1; + + if (list->count == 0) { + usbDeviceListFree(list); + if (!mandatory) { + VIR_DEBUG("Did not find USB device bus:%u device:%u", + bus, devno); + if (usb) + *usb = NULL; + return 0; + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Did not find USB device bus:%u device:%u"), + bus, devno); + return -1; + } + + if (usb) { + *usb = usbDeviceListGet(list, 0); + usbDeviceListSteal(list, *usb); + } + usbDeviceListFree(list); + + return 0; +} + +int +usbFindDevice(unsigned int vendor, + unsigned int product, + unsigned int bus, + unsigned int devno, + bool mandatory, + usbDevice **usb) +{ + usbDeviceList *list; + + unsigned int flags = USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BUS; + if (!(list = usbDeviceSearch(vendor, product, bus, devno, flags))) + return -1; + + if (list->count == 0) { + usbDeviceListFree(list); + if (!mandatory) { + VIR_DEBUG("Did not find USB device %x:%x bus:%u device:%u", + vendor, product, bus, devno); + if (usb) + *usb = NULL; + return 0; + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Did not find USB device %x:%x bus:%u device:%u"), + vendor, product, bus, devno); + return -1; + } + + if (usb) { + *usb = usbDeviceListGet(list, 0); + usbDeviceListSteal(list, *usb); + } + usbDeviceListFree(list); + + return 0; +} + +usbDevice * +usbGetDevice(unsigned int bus, + unsigned int devno) +{ + usbDevice *dev; + + if (VIR_ALLOC(dev) < 0) { + virReportOOMError(); + return NULL; + } + + dev->bus = bus; + dev->dev = devno; + + if (snprintf(dev->name, sizeof(dev->name), "%.3o:%.3o", + dev->bus, dev->dev) >= sizeof(dev->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("dev->name buffer overflow: %.3o:%.3o"), + dev->bus, dev->dev); + usbFreeDevice(dev); + return NULL; + } + if (virAsprintf(&dev->path, USB_DEVFS "%03d/%03d", + dev->bus, dev->dev) < 0) { + virReportOOMError(); + usbFreeDevice(dev); + return NULL; + } + + /* XXX fixme. this should be product/vendor */ + if (snprintf(dev->id, sizeof(dev->id), "%d %d", dev->bus, + dev->dev) >= sizeof(dev->id)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("dev->id buffer overflow: %d %d"), + dev->bus, dev->dev); + usbFreeDevice(dev); + return NULL; + } + + VIR_DEBUG("%s %s: initialized", dev->id, dev->name); + + return dev; +} + +void +usbFreeDevice(usbDevice *dev) +{ + VIR_DEBUG("%s %s: freeing", dev->id, dev->name); + VIR_FREE(dev->path); + VIR_FREE(dev); +} + + +void usbDeviceSetUsedBy(usbDevice *dev, + const char *name) +{ + dev->used_by = name; +} + +const char * usbDeviceGetUsedBy(usbDevice *dev) +{ + return dev->used_by; +} + +const char *usbDeviceGetName(usbDevice *dev) +{ + return dev->name; +} + +unsigned int usbDeviceGetBus(usbDevice *dev) +{ + return dev->bus; +} + + +unsigned int usbDeviceGetDevno(usbDevice *dev) +{ + return dev->dev; +} + + +int usbDeviceFileIterate(usbDevice *dev, + usbDeviceFileActor actor, + void *opaque) +{ + return (actor)(dev, dev->path, opaque); +} + +usbDeviceList * +usbDeviceListNew(void) +{ + usbDeviceList *list; + + if (VIR_ALLOC(list) < 0) { + virReportOOMError(); + return NULL; + } + + return list; +} + +void +usbDeviceListFree(usbDeviceList *list) +{ + int i; + + if (!list) + return; + + for (i = 0; i < list->count; i++) + usbFreeDevice(list->devs[i]); + + VIR_FREE(list->devs); + VIR_FREE(list); +} + +int +usbDeviceListAdd(usbDeviceList *list, + usbDevice *dev) +{ + if (usbDeviceListFind(list, dev)) { + virReportError(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(); + return -1; + } + + list->devs[list->count++] = dev; + + return 0; +} + +usbDevice * +usbDeviceListGet(usbDeviceList *list, + int idx) +{ + if (idx >= list->count || + idx < 0) + return NULL; + + return list->devs[idx]; +} + +int +usbDeviceListCount(usbDeviceList *list) +{ + return list->count; +} + +usbDevice * +usbDeviceListSteal(usbDeviceList *list, + usbDevice *dev) +{ + usbDevice *ret = NULL; + int i; + + for (i = 0; i < list->count; i++) { + if (list->devs[i]->bus != dev->bus || + list->devs[i]->dev != dev->dev) + continue; + + ret = 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; + } + return ret; +} + +void +usbDeviceListDel(usbDeviceList *list, + usbDevice *dev) +{ + usbDevice *ret = usbDeviceListSteal(list, dev); + if (ret) + usbFreeDevice(ret); +} + +usbDevice * +usbDeviceListFind(usbDeviceList *list, + usbDevice *dev) +{ + int i; + + for (i = 0; i < list->count; i++) { + if (list->devs[i]->bus == dev->bus && + list->devs[i]->dev == dev->dev) + return list->devs[i]; + } + + return NULL; +} diff --git a/src/util/virusb.h b/src/util/virusb.h new file mode 100644 index 0000000..4f55fdc --- /dev/null +++ b/src/util/virusb.h @@ -0,0 +1,87 @@ +/* + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Daniel P. Berrange <berrange@redhat.com> + * Michal Privoznik <mprivozn@redhat.com> + */ + +#ifndef __VIR_USB_H__ +# define __VIR_USB_H__ + +# include "internal.h" + +typedef struct _usbDevice usbDevice; +typedef struct _usbDeviceList usbDeviceList; + +usbDevice *usbGetDevice(unsigned int bus, + unsigned int devno); + +int usbFindDeviceByBus(unsigned int bus, + unsigned int devno, + bool mandatory, + usbDevice **usb); + +int usbFindDeviceByVendor(unsigned int vendor, + unsigned int product, + bool mandatory, + usbDeviceList **devices); + +int usbFindDevice(unsigned int vendor, + unsigned int product, + unsigned int bus, + unsigned int devno, + bool mandatory, + usbDevice **usb); + +void usbFreeDevice (usbDevice *dev); +void usbDeviceSetUsedBy(usbDevice *dev, const char *name); +const char *usbDeviceGetUsedBy(usbDevice *dev); +const char *usbDeviceGetName(usbDevice *dev); + +unsigned int usbDeviceGetBus(usbDevice *dev); +unsigned int usbDeviceGetDevno(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)(usbDevice *dev, + const char *path, void *opaque); + +int usbDeviceFileIterate(usbDevice *dev, + usbDeviceFileActor actor, + void *opaque); + +usbDeviceList *usbDeviceListNew(void); +void usbDeviceListFree(usbDeviceList *list); +int usbDeviceListAdd(usbDeviceList *list, + usbDevice *dev); +usbDevice * usbDeviceListGet(usbDeviceList *list, + int idx); +int usbDeviceListCount(usbDeviceList *list); +usbDevice * usbDeviceListSteal(usbDeviceList *list, + usbDevice *dev); +void usbDeviceListDel(usbDeviceList *list, + usbDevice *dev); +usbDevice * usbDeviceListFind(usbDeviceList *list, + usbDevice *dev); + +#endif /* __VIR_USB_H__ */ -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/network/bridge_driver.c | 2 +- src/util/iptables.c | 970 -------------------------------------------- src/util/iptables.h | 121 ------ src/util/viriptables.c | 970 ++++++++++++++++++++++++++++++++++++++++++++ src/util/viriptables.h | 121 ++++++ 7 files changed, 1094 insertions(+), 1094 deletions(-) delete mode 100644 src/util/iptables.c delete mode 100644 src/util/iptables.h create mode 100644 src/util/viriptables.c create mode 100644 src/util/viriptables.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 3f3362c..f55a1b1 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/iptables.c src/util/json.c src/util/pci.c src/util/processinfo.c @@ -160,6 +159,7 @@ src/util/virfile.c src/util/virhash.c src/util/virhooks.c src/util/virinitctl.c +src/util/viriptables.c src/util/virkeyfile.c src/util/virlockspace.c src/util/virnetdev.c diff --git a/src/Makefile.am b/src/Makefile.am index 4f89bdc..45e6169 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/iptables.c util/iptables.h \ util/json.c util/json.h \ util/logging.c util/logging.h \ util/memory.c util/memory.h \ @@ -84,6 +83,7 @@ UTIL_SOURCES = \ util/virfile.c util/virfile.h \ util/virhooks.c util/virhooks.h \ util/virnodesuspend.c util/virnodesuspend.h \ + util/viriptables.c util/viriptables.h \ util/virobject.c util/virobject.h \ util/virpidfile.c util/virpidfile.h \ util/virprocess.c util/virprocess.h \ diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 1110208..bc37bde 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -56,7 +56,7 @@ #include "vircommand.h" #include "memory.h" #include "uuid.h" -#include "iptables.h" +#include "viriptables.h" #include "logging.h" #include "virdnsmasq.h" #include "configmake.h" diff --git a/src/util/iptables.c b/src/util/iptables.c deleted file mode 100644 index 25253ff..0000000 --- a/src/util/iptables.c +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Copyright (C) 2007-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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> -#include <sys/wait.h> - -#ifdef HAVE_PATHS_H -# include <paths.h> -#endif - -#include "internal.h" -#include "iptables.h" -#include "vircommand.h" -#include "memory.h" -#include "virterror_internal.h" -#include "logging.h" -#include "threads.h" - -#if HAVE_FIREWALLD -static char *firewall_cmd_path = NULL; - -static int -virIpTablesOnceInit(void) -{ - firewall_cmd_path = virFindFileInPath("firewall-cmd"); - if (!firewall_cmd_path) { - VIR_INFO("firewall-cmd not found on system. " - "firewalld support disabled for iptables."); - } else { - virCommandPtr cmd = virCommandNew(firewall_cmd_path); - int status; - - virCommandAddArgList(cmd, "--state", NULL); - if (virCommandRun(cmd, &status) < 0 || status != 0) { - VIR_INFO("firewall-cmd found but disabled for iptables"); - VIR_FREE(firewall_cmd_path); - firewall_cmd_path = NULL; - } else { - VIR_INFO("using firewalld for iptables commands"); - } - virCommandFree(cmd); - } - return 0; -} - -VIR_ONCE_GLOBAL_INIT(virIpTables) - -#endif - -#define VIR_FROM_THIS VIR_FROM_NONE - -enum { - ADD = 0, - REMOVE -}; - -typedef struct -{ - char *table; - char *chain; -} iptRules; - -struct _iptablesContext -{ - iptRules *input_filter; - iptRules *forward_filter; - iptRules *nat_postrouting; - iptRules *mangle_postrouting; -}; - -static void -iptRulesFree(iptRules *rules) -{ - VIR_FREE(rules->table); - VIR_FREE(rules->chain); - 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; - - return rules; - - error: - iptRulesFree(rules); - return NULL; -} - -static int ATTRIBUTE_SENTINEL -iptablesAddRemoveRule(iptRules *rules, int family, int action, - const char *arg, ...) -{ - va_list args; - int ret; - virCommandPtr cmd = NULL; - const char *s; - -#if HAVE_FIREWALLD - virIpTablesInitialize(); - if (firewall_cmd_path) { - cmd = virCommandNew(firewall_cmd_path); - virCommandAddArgList(cmd, "--direct", "--passthrough", - (family == AF_INET6) ? "ipv6" : "ipv4", NULL); - } -#endif - - if (cmd == NULL) { - cmd = virCommandNew((family == AF_INET6) - ? IP6TABLES_PATH : IPTABLES_PATH); - } - - virCommandAddArgList(cmd, "--table", rules->table, - action == ADD ? "--insert" : "--delete", - rules->chain, arg, NULL); - - va_start(args, arg); - while ((s = va_arg(args, const char *))) - virCommandAddArg(cmd, s); - va_end(args); - - ret = virCommandRun(cmd, NULL); - virCommandFree(cmd); - return ret; -} - -/** - * 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; - - if (!(ctx->mangle_postrouting = iptRulesNew("mangle", "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); - if (ctx->mangle_postrouting) - iptRulesFree(ctx->mangle_postrouting); - VIR_FREE(ctx); -} - -static int -iptablesInput(iptablesContext *ctx, - int family, - 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, - family, - 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, - int family, - const char *iface, - int port) -{ - return iptablesInput(ctx, family, 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, - int family, - const char *iface, - int port) -{ - return iptablesInput(ctx, family, 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, - int family, - const char *iface, - int port) -{ - return iptablesInput(ctx, family, 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, - int family, - const char *iface, - int port) -{ - return iptablesInput(ctx, family, iface, port, REMOVE, 0); -} - - -static char *iptablesFormatNetwork(virSocketAddr *netaddr, - unsigned int prefix) -{ - virSocketAddr network; - char *netstr; - char *ret; - - if (!(VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET) || - VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET6))) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Only IPv4 or IPv6 addresses can be used with iptables")); - return NULL; - } - - if (virSocketAddrMaskByPrefix(netaddr, prefix, &network) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Failure to mask address")); - return NULL; - } - - netstr = virSocketAddrFormat(&network); - - if (!netstr) - return NULL; - - if (virAsprintf(&ret, "%s/%d", netstr, prefix) < 0) - virReportOOMError(); - - VIR_FREE(netstr); - return ret; -} - - -/* Allow all traffic coming from the bridge, with a valid network address - * to proceed to WAN - */ -static int -iptablesForwardAllowOut(iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev, - int action) -{ - int ret; - char *networkstr; - - if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) - return -1; - - if (physdev && physdev[0]) { - ret = iptablesAddRemoveRule(ctx->forward_filter, - VIR_SOCKET_ADDR_FAMILY(netaddr), - action, - "--source", networkstr, - "--in-interface", iface, - "--out-interface", physdev, - "--jump", "ACCEPT", - NULL); - } else { - ret = iptablesAddRemoveRule(ctx->forward_filter, - VIR_SOCKET_ADDR_FAMILY(netaddr), - action, - "--source", networkstr, - "--in-interface", iface, - "--jump", "ACCEPT", - NULL); - } - VIR_FREE(networkstr); - return ret; -} - -/** - * 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev) -{ - return iptablesForwardAllowOut(ctx, netaddr, prefix, 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev) -{ - return iptablesForwardAllowOut(ctx, netaddr, prefix, 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev, - int action) -{ - int ret; - char *networkstr; - - if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) - return -1; - - if (physdev && physdev[0]) { - ret = iptablesAddRemoveRule(ctx->forward_filter, - VIR_SOCKET_ADDR_FAMILY(netaddr), - action, - "--destination", networkstr, - "--in-interface", physdev, - "--out-interface", iface, - "--match", "state", - "--state", "ESTABLISHED,RELATED", - "--jump", "ACCEPT", - NULL); - } else { - ret = iptablesAddRemoveRule(ctx->forward_filter, - VIR_SOCKET_ADDR_FAMILY(netaddr), - action, - "--destination", networkstr, - "--out-interface", iface, - "--match", "state", - "--state", "ESTABLISHED,RELATED", - "--jump", "ACCEPT", - NULL); - } - VIR_FREE(networkstr); - return ret; -} - -/** - * 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev) -{ - return iptablesForwardAllowRelatedIn(ctx, netaddr, prefix, 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev) -{ - return iptablesForwardAllowRelatedIn(ctx, netaddr, prefix, iface, physdev, REMOVE); -} - -/* Allow all traffic destined to the bridge, with a valid network address - */ -static int -iptablesForwardAllowIn(iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev, - int action) -{ - int ret; - char *networkstr; - - if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) - return -1; - - if (physdev && physdev[0]) { - ret = iptablesAddRemoveRule(ctx->forward_filter, - VIR_SOCKET_ADDR_FAMILY(netaddr), - action, - "--destination", networkstr, - "--in-interface", physdev, - "--out-interface", iface, - "--jump", "ACCEPT", - NULL); - } else { - ret = iptablesAddRemoveRule(ctx->forward_filter, - VIR_SOCKET_ADDR_FAMILY(netaddr), - action, - "--destination", networkstr, - "--out-interface", iface, - "--jump", "ACCEPT", - NULL); - } - VIR_FREE(networkstr); - return ret; -} - -/** - * 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev) -{ - return iptablesForwardAllowIn(ctx, netaddr, prefix, 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev) -{ - return iptablesForwardAllowIn(ctx, netaddr, prefix, iface, physdev, REMOVE); -} - - -/* Allow all traffic between guests on the same bridge, - * with a valid network address - */ -static int -iptablesForwardAllowCross(iptablesContext *ctx, - int family, - const char *iface, - int action) -{ - return iptablesAddRemoveRule(ctx->forward_filter, - family, - 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, - int family, - const char *iface) -{ - return iptablesForwardAllowCross(ctx, family, 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, - int family, - const char *iface) -{ - return iptablesForwardAllowCross(ctx, family, iface, REMOVE); -} - - -/* Drop all traffic trying to forward from the bridge. - * ie the bridge is the in interface - */ -static int -iptablesForwardRejectOut(iptablesContext *ctx, - int family, - const char *iface, - int action) -{ - return iptablesAddRemoveRule(ctx->forward_filter, - family, - 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, - int family, - const char *iface) -{ - return iptablesForwardRejectOut(ctx, family, 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, - int family, - const char *iface) -{ - return iptablesForwardRejectOut(ctx, family, iface, REMOVE); -} - - - - -/* Drop all traffic trying to forward to the bridge. - * ie the bridge is the out interface - */ -static int -iptablesForwardRejectIn(iptablesContext *ctx, - int family, - const char *iface, - int action) -{ - return iptablesAddRemoveRule(ctx->forward_filter, - family, - 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, - int family, - const char *iface) -{ - return iptablesForwardRejectIn(ctx, family, 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, - int family, - const char *iface) -{ - return iptablesForwardRejectIn(ctx, family, iface, REMOVE); -} - - -/* Masquerade all traffic coming from the network associated - * with the bridge - */ -static int -iptablesForwardMasquerade(iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *physdev, - const char *protocol, - int action) -{ - int ret; - char *networkstr; - - if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) - return -1; - - if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) { - /* Higher level code *should* guaranteee it's impossible to get here. */ - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Attempted to NAT '%s'. NAT is only supported for IPv4."), - networkstr); - VIR_FREE(networkstr); - return -1; - } - - if (protocol && protocol[0]) { - if (physdev && physdev[0]) { - ret = iptablesAddRemoveRule(ctx->nat_postrouting, - AF_INET, - action, - "--source", networkstr, - "-p", protocol, - "!", "--destination", networkstr, - "--out-interface", physdev, - "--jump", "MASQUERADE", - "--to-ports", "1024-65535", - NULL); - } else { - ret = iptablesAddRemoveRule(ctx->nat_postrouting, - AF_INET, - action, - "--source", networkstr, - "-p", protocol, - "!", "--destination", networkstr, - "--jump", "MASQUERADE", - "--to-ports", "1024-65535", - NULL); - } - } else { - if (physdev && physdev[0]) { - ret = iptablesAddRemoveRule(ctx->nat_postrouting, - AF_INET, - action, - "--source", networkstr, - "!", "--destination", networkstr, - "--out-interface", physdev, - "--jump", "MASQUERADE", - NULL); - } else { - ret = iptablesAddRemoveRule(ctx->nat_postrouting, - AF_INET, - action, - "--source", networkstr, - "!", "--destination", networkstr, - "--jump", "MASQUERADE", - NULL); - } - } - VIR_FREE(networkstr); - return ret; -} - -/** - * iptablesAddForwardMasquerade: - * @ctx: pointer to the IP table context - * @network: the source network name - * @physdev: the physical input device or NULL - * @protocol: the network protocol 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *physdev, - const char *protocol) -{ - return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, protocol, ADD); -} - -/** - * iptablesRemoveForwardMasquerade: - * @ctx: pointer to the IP table context - * @network: the source network name - * @physdev: the physical input device or NULL - * @protocol: the network protocol 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, - virSocketAddr *netaddr, - unsigned int prefix, - const char *physdev, - const char *protocol) -{ - return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, protocol, REMOVE); -} - - -static int -iptablesOutputFixUdpChecksum(iptablesContext *ctx, - const char *iface, - int port, - int action) -{ - char portstr[32]; - - snprintf(portstr, sizeof(portstr), "%d", port); - portstr[sizeof(portstr) - 1] = '\0'; - - return iptablesAddRemoveRule(ctx->mangle_postrouting, - AF_INET, - action, - "--out-interface", iface, - "--protocol", "udp", - "--destination-port", portstr, - "--jump", "CHECKSUM", "--checksum-fill", - NULL); -} - -/** - * iptablesAddOutputFixUdpChecksum: - * @ctx: pointer to the IP table context - * @iface: the interface name - * @port: the UDP port to match - * - * Add a rule to the mangle table's POSTROUTING chain that fixes up the - * checksum of packets with the given destination @port. - * the given @iface interface for TCP packets. - * - * Returns 0 in case of success or an error code in case of error. - * (NB: if the system's iptables does not support checksum mangling, - * this will return an error, which should be ignored.) - */ - -int -iptablesAddOutputFixUdpChecksum(iptablesContext *ctx, - const char *iface, - int port) -{ - return iptablesOutputFixUdpChecksum(ctx, iface, port, ADD); -} - -/** - * iptablesRemoveOutputFixUdpChecksum: - * @ctx: pointer to the IP table context - * @iface: the interface name - * @port: the UDP port of the rule to remove - * - * Removes the checksum fixup rule that was previous added with - * iptablesAddOutputFixUdpChecksum. - * - * Returns 0 in case of success or an error code in case of error - * (again, if iptables doesn't support checksum fixup, this will - * return an error, which should be ignored) - */ -int -iptablesRemoveOutputFixUdpChecksum(iptablesContext *ctx, - const char *iface, - int port) -{ - return iptablesOutputFixUdpChecksum(ctx, iface, port, REMOVE); -} diff --git a/src/util/iptables.h b/src/util/iptables.h deleted file mode 100644 index e54f8b1..0000000 --- a/src/util/iptables.h +++ /dev/null @@ -1,121 +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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Mark McLoughlin <markmc@redhat.com> - */ - -#ifndef __QEMUD_IPTABLES_H__ -# define __QEMUD_IPTABLES_H__ - -# include "virsocketaddr.h" - -typedef struct _iptablesContext iptablesContext; - -iptablesContext *iptablesContextNew (void); -void iptablesContextFree (iptablesContext *ctx); - -int iptablesAddTcpInput (iptablesContext *ctx, - int family, - const char *iface, - int port); -int iptablesRemoveTcpInput (iptablesContext *ctx, - int family, - const char *iface, - int port); - -int iptablesAddUdpInput (iptablesContext *ctx, - int family, - const char *iface, - int port); -int iptablesRemoveUdpInput (iptablesContext *ctx, - int family, - const char *iface, - int port); - -int iptablesAddForwardAllowOut (iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev); -int iptablesRemoveForwardAllowOut (iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev); - -int iptablesAddForwardAllowRelatedIn(iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev); -int iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev); - -int iptablesAddForwardAllowIn (iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev); -int iptablesRemoveForwardAllowIn (iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *iface, - const char *physdev); - -int iptablesAddForwardAllowCross (iptablesContext *ctx, - int family, - const char *iface); -int iptablesRemoveForwardAllowCross (iptablesContext *ctx, - int family, - const char *iface); - -int iptablesAddForwardRejectOut (iptablesContext *ctx, - int family, - const char *iface); -int iptablesRemoveForwardRejectOut (iptablesContext *ctx, - int family, - const char *iface); - -int iptablesAddForwardRejectIn (iptablesContext *ctx, - int family, - const char *iface); -int iptablesRemoveForwardRejectIn (iptablesContext *ctx, - int family, - const char *iface); - -int iptablesAddForwardMasquerade (iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *physdev, - const char *protocol); -int iptablesRemoveForwardMasquerade (iptablesContext *ctx, - virSocketAddr *netaddr, - unsigned int prefix, - const char *physdev, - const char *protocol); -int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx, - const char *iface, - int port); -int iptablesRemoveOutputFixUdpChecksum (iptablesContext *ctx, - const char *iface, - int port); - -#endif /* __QEMUD_IPTABLES_H__ */ diff --git a/src/util/viriptables.c b/src/util/viriptables.c new file mode 100644 index 0000000..8831920 --- /dev/null +++ b/src/util/viriptables.c @@ -0,0 +1,970 @@ +/* + * Copyright (C) 2007-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * 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> +#include <sys/wait.h> + +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif + +#include "internal.h" +#include "viriptables.h" +#include "vircommand.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" +#include "threads.h" + +#if HAVE_FIREWALLD +static char *firewall_cmd_path = NULL; + +static int +virIpTablesOnceInit(void) +{ + firewall_cmd_path = virFindFileInPath("firewall-cmd"); + if (!firewall_cmd_path) { + VIR_INFO("firewall-cmd not found on system. " + "firewalld support disabled for iptables."); + } else { + virCommandPtr cmd = virCommandNew(firewall_cmd_path); + int status; + + virCommandAddArgList(cmd, "--state", NULL); + if (virCommandRun(cmd, &status) < 0 || status != 0) { + VIR_INFO("firewall-cmd found but disabled for iptables"); + VIR_FREE(firewall_cmd_path); + firewall_cmd_path = NULL; + } else { + VIR_INFO("using firewalld for iptables commands"); + } + virCommandFree(cmd); + } + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virIpTables) + +#endif + +#define VIR_FROM_THIS VIR_FROM_NONE + +enum { + ADD = 0, + REMOVE +}; + +typedef struct +{ + char *table; + char *chain; +} iptRules; + +struct _iptablesContext +{ + iptRules *input_filter; + iptRules *forward_filter; + iptRules *nat_postrouting; + iptRules *mangle_postrouting; +}; + +static void +iptRulesFree(iptRules *rules) +{ + VIR_FREE(rules->table); + VIR_FREE(rules->chain); + 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; + + return rules; + + error: + iptRulesFree(rules); + return NULL; +} + +static int ATTRIBUTE_SENTINEL +iptablesAddRemoveRule(iptRules *rules, int family, int action, + const char *arg, ...) +{ + va_list args; + int ret; + virCommandPtr cmd = NULL; + const char *s; + +#if HAVE_FIREWALLD + virIpTablesInitialize(); + if (firewall_cmd_path) { + cmd = virCommandNew(firewall_cmd_path); + virCommandAddArgList(cmd, "--direct", "--passthrough", + (family == AF_INET6) ? "ipv6" : "ipv4", NULL); + } +#endif + + if (cmd == NULL) { + cmd = virCommandNew((family == AF_INET6) + ? IP6TABLES_PATH : IPTABLES_PATH); + } + + virCommandAddArgList(cmd, "--table", rules->table, + action == ADD ? "--insert" : "--delete", + rules->chain, arg, NULL); + + va_start(args, arg); + while ((s = va_arg(args, const char *))) + virCommandAddArg(cmd, s); + va_end(args); + + ret = virCommandRun(cmd, NULL); + virCommandFree(cmd); + return ret; +} + +/** + * 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; + + if (!(ctx->mangle_postrouting = iptRulesNew("mangle", "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); + if (ctx->mangle_postrouting) + iptRulesFree(ctx->mangle_postrouting); + VIR_FREE(ctx); +} + +static int +iptablesInput(iptablesContext *ctx, + int family, + 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, + family, + 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, + int family, + const char *iface, + int port) +{ + return iptablesInput(ctx, family, 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, + int family, + const char *iface, + int port) +{ + return iptablesInput(ctx, family, 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, + int family, + const char *iface, + int port) +{ + return iptablesInput(ctx, family, 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, + int family, + const char *iface, + int port) +{ + return iptablesInput(ctx, family, iface, port, REMOVE, 0); +} + + +static char *iptablesFormatNetwork(virSocketAddr *netaddr, + unsigned int prefix) +{ + virSocketAddr network; + char *netstr; + char *ret; + + if (!(VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET) || + VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET6))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Only IPv4 or IPv6 addresses can be used with iptables")); + return NULL; + } + + if (virSocketAddrMaskByPrefix(netaddr, prefix, &network) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failure to mask address")); + return NULL; + } + + netstr = virSocketAddrFormat(&network); + + if (!netstr) + return NULL; + + if (virAsprintf(&ret, "%s/%d", netstr, prefix) < 0) + virReportOOMError(); + + VIR_FREE(netstr); + return ret; +} + + +/* Allow all traffic coming from the bridge, with a valid network address + * to proceed to WAN + */ +static int +iptablesForwardAllowOut(iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev, + int action) +{ + int ret; + char *networkstr; + + if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) + return -1; + + if (physdev && physdev[0]) { + ret = iptablesAddRemoveRule(ctx->forward_filter, + VIR_SOCKET_ADDR_FAMILY(netaddr), + action, + "--source", networkstr, + "--in-interface", iface, + "--out-interface", physdev, + "--jump", "ACCEPT", + NULL); + } else { + ret = iptablesAddRemoveRule(ctx->forward_filter, + VIR_SOCKET_ADDR_FAMILY(netaddr), + action, + "--source", networkstr, + "--in-interface", iface, + "--jump", "ACCEPT", + NULL); + } + VIR_FREE(networkstr); + return ret; +} + +/** + * 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowOut(ctx, netaddr, prefix, 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowOut(ctx, netaddr, prefix, 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev, + int action) +{ + int ret; + char *networkstr; + + if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) + return -1; + + if (physdev && physdev[0]) { + ret = iptablesAddRemoveRule(ctx->forward_filter, + VIR_SOCKET_ADDR_FAMILY(netaddr), + action, + "--destination", networkstr, + "--in-interface", physdev, + "--out-interface", iface, + "--match", "state", + "--state", "ESTABLISHED,RELATED", + "--jump", "ACCEPT", + NULL); + } else { + ret = iptablesAddRemoveRule(ctx->forward_filter, + VIR_SOCKET_ADDR_FAMILY(netaddr), + action, + "--destination", networkstr, + "--out-interface", iface, + "--match", "state", + "--state", "ESTABLISHED,RELATED", + "--jump", "ACCEPT", + NULL); + } + VIR_FREE(networkstr); + return ret; +} + +/** + * 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowRelatedIn(ctx, netaddr, prefix, 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowRelatedIn(ctx, netaddr, prefix, iface, physdev, REMOVE); +} + +/* Allow all traffic destined to the bridge, with a valid network address + */ +static int +iptablesForwardAllowIn(iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev, + int action) +{ + int ret; + char *networkstr; + + if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) + return -1; + + if (physdev && physdev[0]) { + ret = iptablesAddRemoveRule(ctx->forward_filter, + VIR_SOCKET_ADDR_FAMILY(netaddr), + action, + "--destination", networkstr, + "--in-interface", physdev, + "--out-interface", iface, + "--jump", "ACCEPT", + NULL); + } else { + ret = iptablesAddRemoveRule(ctx->forward_filter, + VIR_SOCKET_ADDR_FAMILY(netaddr), + action, + "--destination", networkstr, + "--out-interface", iface, + "--jump", "ACCEPT", + NULL); + } + VIR_FREE(networkstr); + return ret; +} + +/** + * 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowIn(ctx, netaddr, prefix, 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev) +{ + return iptablesForwardAllowIn(ctx, netaddr, prefix, iface, physdev, REMOVE); +} + + +/* Allow all traffic between guests on the same bridge, + * with a valid network address + */ +static int +iptablesForwardAllowCross(iptablesContext *ctx, + int family, + const char *iface, + int action) +{ + return iptablesAddRemoveRule(ctx->forward_filter, + family, + 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, + int family, + const char *iface) +{ + return iptablesForwardAllowCross(ctx, family, 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, + int family, + const char *iface) +{ + return iptablesForwardAllowCross(ctx, family, iface, REMOVE); +} + + +/* Drop all traffic trying to forward from the bridge. + * ie the bridge is the in interface + */ +static int +iptablesForwardRejectOut(iptablesContext *ctx, + int family, + const char *iface, + int action) +{ + return iptablesAddRemoveRule(ctx->forward_filter, + family, + 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, + int family, + const char *iface) +{ + return iptablesForwardRejectOut(ctx, family, 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, + int family, + const char *iface) +{ + return iptablesForwardRejectOut(ctx, family, iface, REMOVE); +} + + + + +/* Drop all traffic trying to forward to the bridge. + * ie the bridge is the out interface + */ +static int +iptablesForwardRejectIn(iptablesContext *ctx, + int family, + const char *iface, + int action) +{ + return iptablesAddRemoveRule(ctx->forward_filter, + family, + 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, + int family, + const char *iface) +{ + return iptablesForwardRejectIn(ctx, family, 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, + int family, + const char *iface) +{ + return iptablesForwardRejectIn(ctx, family, iface, REMOVE); +} + + +/* Masquerade all traffic coming from the network associated + * with the bridge + */ +static int +iptablesForwardMasquerade(iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *physdev, + const char *protocol, + int action) +{ + int ret; + char *networkstr; + + if (!(networkstr = iptablesFormatNetwork(netaddr, prefix))) + return -1; + + if (!VIR_SOCKET_ADDR_IS_FAMILY(netaddr, AF_INET)) { + /* Higher level code *should* guaranteee it's impossible to get here. */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Attempted to NAT '%s'. NAT is only supported for IPv4."), + networkstr); + VIR_FREE(networkstr); + return -1; + } + + if (protocol && protocol[0]) { + if (physdev && physdev[0]) { + ret = iptablesAddRemoveRule(ctx->nat_postrouting, + AF_INET, + action, + "--source", networkstr, + "-p", protocol, + "!", "--destination", networkstr, + "--out-interface", physdev, + "--jump", "MASQUERADE", + "--to-ports", "1024-65535", + NULL); + } else { + ret = iptablesAddRemoveRule(ctx->nat_postrouting, + AF_INET, + action, + "--source", networkstr, + "-p", protocol, + "!", "--destination", networkstr, + "--jump", "MASQUERADE", + "--to-ports", "1024-65535", + NULL); + } + } else { + if (physdev && physdev[0]) { + ret = iptablesAddRemoveRule(ctx->nat_postrouting, + AF_INET, + action, + "--source", networkstr, + "!", "--destination", networkstr, + "--out-interface", physdev, + "--jump", "MASQUERADE", + NULL); + } else { + ret = iptablesAddRemoveRule(ctx->nat_postrouting, + AF_INET, + action, + "--source", networkstr, + "!", "--destination", networkstr, + "--jump", "MASQUERADE", + NULL); + } + } + VIR_FREE(networkstr); + return ret; +} + +/** + * iptablesAddForwardMasquerade: + * @ctx: pointer to the IP table context + * @network: the source network name + * @physdev: the physical input device or NULL + * @protocol: the network protocol 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *physdev, + const char *protocol) +{ + return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, protocol, ADD); +} + +/** + * iptablesRemoveForwardMasquerade: + * @ctx: pointer to the IP table context + * @network: the source network name + * @physdev: the physical input device or NULL + * @protocol: the network protocol 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, + virSocketAddr *netaddr, + unsigned int prefix, + const char *physdev, + const char *protocol) +{ + return iptablesForwardMasquerade(ctx, netaddr, prefix, physdev, protocol, REMOVE); +} + + +static int +iptablesOutputFixUdpChecksum(iptablesContext *ctx, + const char *iface, + int port, + int action) +{ + char portstr[32]; + + snprintf(portstr, sizeof(portstr), "%d", port); + portstr[sizeof(portstr) - 1] = '\0'; + + return iptablesAddRemoveRule(ctx->mangle_postrouting, + AF_INET, + action, + "--out-interface", iface, + "--protocol", "udp", + "--destination-port", portstr, + "--jump", "CHECKSUM", "--checksum-fill", + NULL); +} + +/** + * iptablesAddOutputFixUdpChecksum: + * @ctx: pointer to the IP table context + * @iface: the interface name + * @port: the UDP port to match + * + * Add a rule to the mangle table's POSTROUTING chain that fixes up the + * checksum of packets with the given destination @port. + * the given @iface interface for TCP packets. + * + * Returns 0 in case of success or an error code in case of error. + * (NB: if the system's iptables does not support checksum mangling, + * this will return an error, which should be ignored.) + */ + +int +iptablesAddOutputFixUdpChecksum(iptablesContext *ctx, + const char *iface, + int port) +{ + return iptablesOutputFixUdpChecksum(ctx, iface, port, ADD); +} + +/** + * iptablesRemoveOutputFixUdpChecksum: + * @ctx: pointer to the IP table context + * @iface: the interface name + * @port: the UDP port of the rule to remove + * + * Removes the checksum fixup rule that was previous added with + * iptablesAddOutputFixUdpChecksum. + * + * Returns 0 in case of success or an error code in case of error + * (again, if iptables doesn't support checksum fixup, this will + * return an error, which should be ignored) + */ +int +iptablesRemoveOutputFixUdpChecksum(iptablesContext *ctx, + const char *iface, + int port) +{ + return iptablesOutputFixUdpChecksum(ctx, iface, port, REMOVE); +} diff --git a/src/util/viriptables.h b/src/util/viriptables.h new file mode 100644 index 0000000..e54f8b1 --- /dev/null +++ b/src/util/viriptables.h @@ -0,0 +1,121 @@ +/* + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Mark McLoughlin <markmc@redhat.com> + */ + +#ifndef __QEMUD_IPTABLES_H__ +# define __QEMUD_IPTABLES_H__ + +# include "virsocketaddr.h" + +typedef struct _iptablesContext iptablesContext; + +iptablesContext *iptablesContextNew (void); +void iptablesContextFree (iptablesContext *ctx); + +int iptablesAddTcpInput (iptablesContext *ctx, + int family, + const char *iface, + int port); +int iptablesRemoveTcpInput (iptablesContext *ctx, + int family, + const char *iface, + int port); + +int iptablesAddUdpInput (iptablesContext *ctx, + int family, + const char *iface, + int port); +int iptablesRemoveUdpInput (iptablesContext *ctx, + int family, + const char *iface, + int port); + +int iptablesAddForwardAllowOut (iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev); +int iptablesRemoveForwardAllowOut (iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev); + +int iptablesAddForwardAllowRelatedIn(iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev); +int iptablesRemoveForwardAllowRelatedIn(iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev); + +int iptablesAddForwardAllowIn (iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev); +int iptablesRemoveForwardAllowIn (iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *iface, + const char *physdev); + +int iptablesAddForwardAllowCross (iptablesContext *ctx, + int family, + const char *iface); +int iptablesRemoveForwardAllowCross (iptablesContext *ctx, + int family, + const char *iface); + +int iptablesAddForwardRejectOut (iptablesContext *ctx, + int family, + const char *iface); +int iptablesRemoveForwardRejectOut (iptablesContext *ctx, + int family, + const char *iface); + +int iptablesAddForwardRejectIn (iptablesContext *ctx, + int family, + const char *iface); +int iptablesRemoveForwardRejectIn (iptablesContext *ctx, + int family, + const char *iface); + +int iptablesAddForwardMasquerade (iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *physdev, + const char *protocol); +int iptablesRemoveForwardMasquerade (iptablesContext *ctx, + virSocketAddr *netaddr, + unsigned int prefix, + const char *physdev, + const char *protocol); +int iptablesAddOutputFixUdpChecksum (iptablesContext *ctx, + const char *iface, + int port); +int iptablesRemoveOutputFixUdpChecksum (iptablesContext *ctx, + const char *iface, + int port); + +#endif /* __QEMUD_IPTABLES_H__ */ -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/parallels/parallels_utils.c | 2 +- src/parallels/parallels_utils.h | 2 +- src/qemu/qemu_agent.c | 2 +- src/qemu/qemu_monitor.h | 2 +- src/qemu/qemu_monitor_json.c | 2 +- src/rpc/virnetserver.h | 2 +- src/rpc/virnetserverclient.h | 2 +- src/rpc/virnetsocket.h | 2 +- src/util/json.c | 1122 --------------------------------------- src/util/json.h | 138 ----- src/util/virjson.c | 1122 +++++++++++++++++++++++++++++++++++++++ src/util/virjson.h | 138 +++++ src/util/virlockspace.h | 2 +- tests/jsontest.c | 2 +- tools/virsh-host.c | 2 +- 17 files changed, 1273 insertions(+), 1273 deletions(-) delete mode 100644 src/util/json.c delete mode 100644 src/util/json.h create mode 100644 src/util/virjson.c create mode 100644 src/util/virjson.h diff --git a/po/POTFILES.in b/po/POTFILES.in index f55a1b1..a9dfcf4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/json.c src/util/pci.c src/util/processinfo.c src/util/sexpr.c @@ -160,6 +159,7 @@ src/util/virhash.c src/util/virhooks.c src/util/virinitctl.c src/util/viriptables.c +src/util/virjson.c src/util/virkeyfile.c src/util/virlockspace.c src/util/virnetdev.c diff --git a/src/Makefile.am b/src/Makefile.am index 45e6169..dd49851 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/json.c util/json.h \ util/logging.c util/logging.h \ util/memory.c util/memory.h \ util/pci.c util/pci.h \ @@ -84,6 +83,7 @@ UTIL_SOURCES = \ util/virhooks.c util/virhooks.h \ util/virnodesuspend.c util/virnodesuspend.h \ util/viriptables.c util/viriptables.h \ + util/virjson.c util/virjson.h \ util/virobject.c util/virobject.h \ util/virpidfile.c util/virpidfile.h \ util/virprocess.c util/virprocess.h \ diff --git a/src/parallels/parallels_utils.c b/src/parallels/parallels_utils.c index e47ff76..b032882 100644 --- a/src/parallels/parallels_utils.c +++ b/src/parallels/parallels_utils.c @@ -27,7 +27,7 @@ #include "vircommand.h" #include "virterror_internal.h" #include "memory.h" -#include "json.h" +#include "virjson.h" #include "parallels_utils.h" diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index 0010f85..7c31707 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -29,7 +29,7 @@ # include "conf/storage_conf.h" # include "conf/domain_event.h" # include "conf/network_conf.h" -# include "json.h" +# include "virjson.h" # define parallelsParseError() \ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 893f7f2..6727294 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -37,7 +37,7 @@ #include "memory.h" #include "logging.h" #include "virterror_internal.h" -#include "json.h" +#include "virjson.h" #include "virfile.h" #include "virprocess.h" #include "virtime.h" diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 8c42b12..d7faa90 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -30,7 +30,7 @@ # include "domain_conf.h" # include "virbitmap.h" # include "virhash.h" -# include "json.h" +# include "virjson.h" # include "device_conf.h" typedef struct _qemuMonitor qemuMonitor; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 0cd66b6..6181668 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -40,7 +40,7 @@ #include "driver.h" #include "datatypes.h" #include "virterror_internal.h" -#include "json.h" +#include "virjson.h" #ifdef WITH_DTRACE_PROBES # include "libvirt_qemu_probes.h" diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index 38cccfe..da7dc9e 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -31,7 +31,7 @@ # include "virnetserverclient.h" # include "virnetserverservice.h" # include "virobject.h" -# include "json.h" +# include "virjson.h" virNetServerPtr virNetServerNew(size_t min_workers, size_t max_workers, diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h index 041ffde..65084e2 100644 --- a/src/rpc/virnetserverclient.h +++ b/src/rpc/virnetserverclient.h @@ -27,7 +27,7 @@ # include "virnetsocket.h" # include "virnetmessage.h" # include "virobject.h" -# include "json.h" +# include "virjson.h" typedef struct _virNetServerClient virNetServerClient; typedef virNetServerClient *virNetServerClientPtr; diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h index fcd54dd..7016c09 100644 --- a/src/rpc/virnetsocket.h +++ b/src/rpc/virnetsocket.h @@ -31,7 +31,7 @@ # ifdef HAVE_SASL # include "virnetsaslcontext.h" # endif -# include "json.h" +# include "virjson.h" typedef struct _virNetSocket virNetSocket; typedef virNetSocket *virNetSocketPtr; diff --git a/src/util/json.c b/src/util/json.c deleted file mode 100644 index 41e0311..0000000 --- a/src/util/json.c +++ /dev/null @@ -1,1122 +0,0 @@ -/* - * json.c: JSON object parsing/formatting - * - * Copyright (C) 2009-2010, 2012 Red Hat, Inc. - * Copyright (C) 2009 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, see - * <http://www.gnu.org/licenses/>. - * - */ - - -#include <config.h> - -#include "json.h" -#include "memory.h" -#include "virterror_internal.h" -#include "logging.h" -#include "util.h" - -#if HAVE_YAJL -# include <yajl/yajl_gen.h> -# include <yajl/yajl_parse.h> - -# ifdef HAVE_YAJL2 -# define yajl_size_t size_t -# else -# define yajl_size_t unsigned int -# endif - -#endif - -/* XXX fixme */ -#define VIR_FROM_THIS VIR_FROM_NONE - - -typedef struct _virJSONParserState virJSONParserState; -typedef virJSONParserState *virJSONParserStatePtr; -struct _virJSONParserState { - virJSONValuePtr value; - char *key; -}; - -typedef struct _virJSONParser virJSONParser; -typedef virJSONParser *virJSONParserPtr; -struct _virJSONParser { - virJSONValuePtr head; - virJSONParserStatePtr state; - unsigned int nstate; -}; - - -void virJSONValueFree(virJSONValuePtr value) -{ - int i; - if (!value || value->protect) - return; - - switch ((virJSONType) value->type) { - case VIR_JSON_TYPE_OBJECT: - for (i = 0 ; i < value->data.object.npairs; i++) { - VIR_FREE(value->data.object.pairs[i].key); - virJSONValueFree(value->data.object.pairs[i].value); - } - VIR_FREE(value->data.object.pairs); - break; - case VIR_JSON_TYPE_ARRAY: - for (i = 0 ; i < value->data.array.nvalues ; i++) - virJSONValueFree(value->data.array.values[i]); - VIR_FREE(value->data.array.values); - break; - case VIR_JSON_TYPE_STRING: - VIR_FREE(value->data.string); - break; - case VIR_JSON_TYPE_NUMBER: - VIR_FREE(value->data.number); - break; - case VIR_JSON_TYPE_BOOLEAN: - case VIR_JSON_TYPE_NULL: - break; - } - - VIR_FREE(value); -} - - -virJSONValuePtr virJSONValueNewString(const char *data) -{ - virJSONValuePtr val; - - if (!data) - return virJSONValueNewNull(); - - if (VIR_ALLOC(val) < 0) - return NULL; - - val->type = VIR_JSON_TYPE_STRING; - if (!(val->data.string = strdup(data))) { - VIR_FREE(val); - return NULL; - } - - return val; -} - -virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length) -{ - virJSONValuePtr val; - - if (!data) - return virJSONValueNewNull(); - - if (VIR_ALLOC(val) < 0) - return NULL; - - val->type = VIR_JSON_TYPE_STRING; - if (!(val->data.string = strndup(data, length))) { - VIR_FREE(val); - return NULL; - } - - return val; -} - -static virJSONValuePtr virJSONValueNewNumber(const char *data) -{ - virJSONValuePtr val; - - if (VIR_ALLOC(val) < 0) - return NULL; - - val->type = VIR_JSON_TYPE_NUMBER; - if (!(val->data.number = strdup(data))) { - VIR_FREE(val); - return NULL; - } - - return val; -} - -virJSONValuePtr virJSONValueNewNumberInt(int data) -{ - virJSONValuePtr val = NULL; - char *str; - if (virAsprintf(&str, "%i", data) < 0) - return NULL; - val = virJSONValueNewNumber(str); - VIR_FREE(str); - return val; -} - - -virJSONValuePtr virJSONValueNewNumberUint(unsigned int data) -{ - virJSONValuePtr val = NULL; - char *str; - if (virAsprintf(&str, "%u", data) < 0) - return NULL; - val = virJSONValueNewNumber(str); - VIR_FREE(str); - return val; -} - - -virJSONValuePtr virJSONValueNewNumberLong(long long data) -{ - virJSONValuePtr val = NULL; - char *str; - if (virAsprintf(&str, "%lld", data) < 0) - return NULL; - val = virJSONValueNewNumber(str); - VIR_FREE(str); - return val; -} - - -virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data) -{ - virJSONValuePtr val = NULL; - char *str; - if (virAsprintf(&str, "%llu", data) < 0) - return NULL; - val = virJSONValueNewNumber(str); - VIR_FREE(str); - return val; -} - - -virJSONValuePtr virJSONValueNewNumberDouble(double data) -{ - virJSONValuePtr val = NULL; - char *str; - if (virDoubleToStr(&str, data) < 0) - return NULL; - val = virJSONValueNewNumber(str); - VIR_FREE(str); - return val; -} - - -virJSONValuePtr virJSONValueNewBoolean(int boolean_) -{ - virJSONValuePtr val; - - if (VIR_ALLOC(val) < 0) - return NULL; - - val->type = VIR_JSON_TYPE_BOOLEAN; - val->data.boolean = boolean_; - - return val; -} - -virJSONValuePtr virJSONValueNewNull(void) -{ - virJSONValuePtr val; - - if (VIR_ALLOC(val) < 0) - return NULL; - - val->type = VIR_JSON_TYPE_NULL; - - return val; -} - -virJSONValuePtr virJSONValueNewArray(void) -{ - virJSONValuePtr val; - - if (VIR_ALLOC(val) < 0) - return NULL; - - val->type = VIR_JSON_TYPE_ARRAY; - - return val; -} - -virJSONValuePtr virJSONValueNewObject(void) -{ - virJSONValuePtr val; - - if (VIR_ALLOC(val) < 0) - return NULL; - - val->type = VIR_JSON_TYPE_OBJECT; - - return val; -} - -int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr value) -{ - char *newkey; - - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - if (virJSONValueObjectHasKey(object, key)) - return -1; - - if (!(newkey = strdup(key))) - return -1; - - if (VIR_REALLOC_N(object->data.object.pairs, - object->data.object.npairs + 1) < 0) { - VIR_FREE(newkey); - return -1; - } - - object->data.object.pairs[object->data.object.npairs].key = newkey; - object->data.object.pairs[object->data.object.npairs].value = value; - object->data.object.npairs++; - - return 0; -} - - -int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char *value) -{ - virJSONValuePtr jvalue = virJSONValueNewString(value); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - -int virJSONValueObjectAppendNumberInt(virJSONValuePtr object, const char *key, int number) -{ - virJSONValuePtr jvalue = virJSONValueNewNumberInt(number); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - - -int virJSONValueObjectAppendNumberUint(virJSONValuePtr object, const char *key, unsigned int number) -{ - virJSONValuePtr jvalue = virJSONValueNewNumberUint(number); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - -int virJSONValueObjectAppendNumberLong(virJSONValuePtr object, const char *key, long long number) -{ - virJSONValuePtr jvalue = virJSONValueNewNumberLong(number); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - -int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned long long number) -{ - virJSONValuePtr jvalue = virJSONValueNewNumberUlong(number); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - -int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double number) -{ - virJSONValuePtr jvalue = virJSONValueNewNumberDouble(number); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - -int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean_) -{ - virJSONValuePtr jvalue = virJSONValueNewBoolean(boolean_); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - -int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key) -{ - virJSONValuePtr jvalue = virJSONValueNewNull(); - if (!jvalue) - return -1; - if (virJSONValueObjectAppend(object, key, jvalue) < 0) { - virJSONValueFree(jvalue); - return -1; - } - return 0; -} - - -int virJSONValueArrayAppend(virJSONValuePtr array, virJSONValuePtr value) -{ - if (array->type != VIR_JSON_TYPE_ARRAY) - return -1; - - if (VIR_REALLOC_N(array->data.array.values, - array->data.array.nvalues + 1) < 0) - return -1; - - array->data.array.values[array->data.array.nvalues] = value; - array->data.array.nvalues++; - - return 0; -} - -int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key) -{ - int i; - - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - for (i = 0 ; i < object->data.object.npairs ; i++) { - if (STREQ(object->data.object.pairs[i].key, key)) - return 1; - } - - return 0; -} - -virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key) -{ - int i; - - if (object->type != VIR_JSON_TYPE_OBJECT) - return NULL; - - for (i = 0 ; i < object->data.object.npairs ; i++) { - if (STREQ(object->data.object.pairs[i].key, key)) - return object->data.object.pairs[i].value; - } - - return NULL; -} - -int virJSONValueObjectKeysNumber(virJSONValuePtr object) -{ - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - return object->data.object.npairs; -} - -const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n) -{ - if (object->type != VIR_JSON_TYPE_OBJECT) - return NULL; - - if (n >= object->data.object.npairs) - return NULL; - - return object->data.object.pairs[n].key; -} - -virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n) -{ - if (object->type != VIR_JSON_TYPE_OBJECT) - return NULL; - - if (n >= object->data.object.npairs) - return NULL; - - return object->data.object.pairs[n].value; -} - -int virJSONValueArraySize(virJSONValuePtr array) -{ - if (array->type != VIR_JSON_TYPE_ARRAY) - return -1; - - return array->data.array.nvalues; -} - - -virJSONValuePtr virJSONValueArrayGet(virJSONValuePtr array, unsigned int element) -{ - if (array->type != VIR_JSON_TYPE_ARRAY) - return NULL; - - if (element >= array->data.array.nvalues) - return NULL; - - return array->data.array.values[element]; -} - -const char *virJSONValueGetString(virJSONValuePtr string) -{ - if (string->type != VIR_JSON_TYPE_STRING) - return NULL; - - return string->data.string; -} - - -int virJSONValueGetNumberInt(virJSONValuePtr number, int *value) -{ - if (number->type != VIR_JSON_TYPE_NUMBER) - return -1; - - return virStrToLong_i(number->data.number, NULL, 10, value); -} - -int virJSONValueGetNumberUint(virJSONValuePtr number, unsigned int *value) -{ - if (number->type != VIR_JSON_TYPE_NUMBER) - return -1; - - return virStrToLong_ui(number->data.number, NULL, 10, value); -} - -int virJSONValueGetNumberLong(virJSONValuePtr number, long long *value) -{ - if (number->type != VIR_JSON_TYPE_NUMBER) - return -1; - - return virStrToLong_ll(number->data.number, NULL, 10, value); -} - -int virJSONValueGetNumberUlong(virJSONValuePtr number, unsigned long long *value) -{ - if (number->type != VIR_JSON_TYPE_NUMBER) - return -1; - - return virStrToLong_ull(number->data.number, NULL, 10, value); -} - -int virJSONValueGetNumberDouble(virJSONValuePtr number, double *value) -{ - if (number->type != VIR_JSON_TYPE_NUMBER) - return -1; - - return virStrToDouble(number->data.number, NULL, value); -} - - -int virJSONValueGetBoolean(virJSONValuePtr val, bool *value) -{ - if (val->type != VIR_JSON_TYPE_BOOLEAN) - return -1; - - *value = val->data.boolean; - return 0; -} - - -int virJSONValueIsNull(virJSONValuePtr val) -{ - if (val->type != VIR_JSON_TYPE_NULL) - return 0; - - return 1; -} - - -const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return NULL; - - val = virJSONValueObjectGet(object, key); - if (!val) - return NULL; - - return virJSONValueGetString(val); -} - - -int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - val = virJSONValueObjectGet(object, key); - if (!val) - return -1; - - return virJSONValueGetNumberInt(val, value); -} - - -int virJSONValueObjectGetNumberUint(virJSONValuePtr object, const char *key, unsigned int *value) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - val = virJSONValueObjectGet(object, key); - if (!val) - return -1; - - return virJSONValueGetNumberUint(val, value); -} - - -int virJSONValueObjectGetNumberLong(virJSONValuePtr object, const char *key, long long *value) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - val = virJSONValueObjectGet(object, key); - if (!val) - return -1; - - return virJSONValueGetNumberLong(val, value); -} - - -int virJSONValueObjectGetNumberUlong(virJSONValuePtr object, const char *key, unsigned long long *value) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - val = virJSONValueObjectGet(object, key); - if (!val) - return -1; - - return virJSONValueGetNumberUlong(val, value); -} - - -int virJSONValueObjectGetNumberDouble(virJSONValuePtr object, const char *key, double *value) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - val = virJSONValueObjectGet(object, key); - if (!val) - return -1; - - return virJSONValueGetNumberDouble(val, value); -} - - -int virJSONValueObjectGetBoolean(virJSONValuePtr object, const char *key, bool *value) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - val = virJSONValueObjectGet(object, key); - if (!val) - return -1; - - return virJSONValueGetBoolean(val, value); -} - - -int virJSONValueObjectIsNull(virJSONValuePtr object, const char *key) -{ - virJSONValuePtr val; - if (object->type != VIR_JSON_TYPE_OBJECT) - return -1; - - val = virJSONValueObjectGet(object, key); - if (!val) - return -1; - - return virJSONValueIsNull(val); -} - - -#if HAVE_YAJL -static int virJSONParserInsertValue(virJSONParserPtr parser, - virJSONValuePtr value) -{ - if (!parser->head) { - parser->head = value; - } else { - virJSONParserStatePtr state; - if (!parser->nstate) { - VIR_DEBUG("got a value to insert without a container"); - return -1; - } - - state = &parser->state[parser->nstate-1]; - - switch (state->value->type) { - case VIR_JSON_TYPE_OBJECT: { - if (!state->key) { - VIR_DEBUG("missing key when inserting object value"); - return -1; - } - - if (virJSONValueObjectAppend(state->value, - state->key, - value) < 0) - return -1; - - VIR_FREE(state->key); - } break; - - case VIR_JSON_TYPE_ARRAY: { - if (state->key) { - VIR_DEBUG("unexpected key when inserting array value"); - return -1; - } - - if (virJSONValueArrayAppend(state->value, - value) < 0) - return -1; - } break; - - default: - VIR_DEBUG("unexpected value type, not a container"); - return -1; - } - } - - return 0; -} - -static int virJSONParserHandleNull(void *ctx) -{ - virJSONParserPtr parser = ctx; - virJSONValuePtr value = virJSONValueNewNull(); - - VIR_DEBUG("parser=%p", parser); - - if (!value) - return 0; - - if (virJSONParserInsertValue(parser, value) < 0) { - virJSONValueFree(value); - return 0; - } - - return 1; -} - -static int virJSONParserHandleBoolean(void *ctx, int boolean_) -{ - virJSONParserPtr parser = ctx; - virJSONValuePtr value = virJSONValueNewBoolean(boolean_); - - VIR_DEBUG("parser=%p boolean=%d", parser, boolean_); - - if (!value) - return 0; - - if (virJSONParserInsertValue(parser, value) < 0) { - virJSONValueFree(value); - return 0; - } - - return 1; -} - -static int virJSONParserHandleNumber(void *ctx, - const char *s, - yajl_size_t l) -{ - virJSONParserPtr parser = ctx; - char *str = strndup(s, l); - virJSONValuePtr value; - - if (!str) - return -1; - value = virJSONValueNewNumber(str); - VIR_FREE(str); - - VIR_DEBUG("parser=%p str=%s", parser, str); - - if (!value) - return 0; - - if (virJSONParserInsertValue(parser, value) < 0) { - virJSONValueFree(value); - return 0; - } - - return 1; -} - -static int virJSONParserHandleString(void *ctx, - const unsigned char *stringVal, - yajl_size_t stringLen) -{ - virJSONParserPtr parser = ctx; - virJSONValuePtr value = virJSONValueNewStringLen((const char *)stringVal, - stringLen); - - VIR_DEBUG("parser=%p str=%p", parser, (const char *)stringVal); - - if (!value) - return 0; - - if (virJSONParserInsertValue(parser, value) < 0) { - virJSONValueFree(value); - return 0; - } - - return 1; -} - -static int virJSONParserHandleMapKey(void *ctx, - const unsigned char *stringVal, - yajl_size_t stringLen) -{ - virJSONParserPtr parser = ctx; - virJSONParserStatePtr state; - - VIR_DEBUG("parser=%p key=%p", parser, (const char *)stringVal); - - if (!parser->nstate) - return 0; - - state = &parser->state[parser->nstate-1]; - if (state->key) - return 0; - state->key = strndup((const char *)stringVal, stringLen); - if (!state->key) - return 0; - return 1; -} - -static int virJSONParserHandleStartMap(void *ctx) -{ - virJSONParserPtr parser = ctx; - virJSONValuePtr value = virJSONValueNewObject(); - - VIR_DEBUG("parser=%p", parser); - - if (!value) - return 0; - - if (virJSONParserInsertValue(parser, value) < 0) { - virJSONValueFree(value); - return 0; - } - - if (VIR_REALLOC_N(parser->state, - parser->nstate + 1) < 0) { - virJSONValueFree(value); - return 0; - } - - parser->state[parser->nstate].value = value; - parser->state[parser->nstate].key = NULL; - parser->nstate++; - - return 1; -} - - -static int virJSONParserHandleEndMap(void *ctx) -{ - virJSONParserPtr parser = ctx; - virJSONParserStatePtr state; - - VIR_DEBUG("parser=%p", parser); - - if (!parser->nstate) - return 0; - - state = &(parser->state[parser->nstate-1]); - if (state->key) { - VIR_FREE(state->key); - return 0; - } - - if (VIR_REALLOC_N(parser->state, - parser->nstate - 1) < 0) - return 0; - parser->nstate--; - - return 1; -} - -static int virJSONParserHandleStartArray(void *ctx) -{ - virJSONParserPtr parser = ctx; - virJSONValuePtr value = virJSONValueNewArray(); - - VIR_DEBUG("parser=%p", parser); - - if (!value) - return 0; - - if (virJSONParserInsertValue(parser, value) < 0) { - virJSONValueFree(value); - return 0; - } - - if (VIR_REALLOC_N(parser->state, - parser->nstate + 1) < 0) - return 0; - - parser->state[parser->nstate].value = value; - parser->state[parser->nstate].key = NULL; - parser->nstate++; - - return 1; -} - -static int virJSONParserHandleEndArray(void *ctx) -{ - virJSONParserPtr parser = ctx; - virJSONParserStatePtr state; - - VIR_DEBUG("parser=%p", parser); - - if (!parser->nstate) - return 0; - - state = &(parser->state[parser->nstate-1]); - if (state->key) { - VIR_FREE(state->key); - return 0; - } - - if (VIR_REALLOC_N(parser->state, - parser->nstate - 1) < 0) - return 0; - parser->nstate--; - - return 1; -} - -static const yajl_callbacks parserCallbacks = { - virJSONParserHandleNull, - virJSONParserHandleBoolean, - NULL, - NULL, - virJSONParserHandleNumber, - virJSONParserHandleString, - virJSONParserHandleStartMap, - virJSONParserHandleMapKey, - virJSONParserHandleEndMap, - virJSONParserHandleStartArray, - virJSONParserHandleEndArray -}; - - -/* XXX add an incremental streaming parser - yajl trivially supports it */ -virJSONValuePtr virJSONValueFromString(const char *jsonstring) -{ - yajl_handle hand; - virJSONParser parser = { NULL, NULL, 0 }; - virJSONValuePtr ret = NULL; -# ifndef HAVE_YAJL2 - yajl_parser_config cfg = { 1, 1 }; -# endif - - VIR_DEBUG("string=%s", jsonstring); - -# ifdef HAVE_YAJL2 - hand = yajl_alloc(&parserCallbacks, NULL, &parser); - if (hand) { - yajl_config(hand, yajl_allow_comments, 1); - yajl_config(hand, yajl_dont_validate_strings, 0); - } -# else - hand = yajl_alloc(&parserCallbacks, &cfg, NULL, &parser); -# endif - if (!hand) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to create JSON parser")); - goto cleanup; - } - - if (yajl_parse(hand, - (const unsigned char *)jsonstring, - strlen(jsonstring)) != yajl_status_ok) { - unsigned char *errstr = yajl_get_error(hand, 1, - (const unsigned char*)jsonstring, - strlen(jsonstring)); - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot parse json %s: %s"), - jsonstring, (const char*) errstr); - VIR_FREE(errstr); - virJSONValueFree(parser.head); - goto cleanup; - } - - ret = parser.head; - -cleanup: - yajl_free(hand); - - if (parser.nstate) { - int i; - for (i = 0 ; i < parser.nstate ; i++) { - VIR_FREE(parser.state[i].key); - } - } - - VIR_DEBUG("result=%p", parser.head); - - return ret; -} - - -static int virJSONValueToStringOne(virJSONValuePtr object, - yajl_gen g) -{ - int i; - - VIR_DEBUG("object=%p type=%d gen=%p", object, object->type, g); - - switch (object->type) { - case VIR_JSON_TYPE_OBJECT: - if (yajl_gen_map_open(g) != yajl_gen_status_ok) - return -1; - for (i = 0; i < object->data.object.npairs ; i++) { - if (yajl_gen_string(g, - (unsigned char *)object->data.object.pairs[i].key, - strlen(object->data.object.pairs[i].key)) - != yajl_gen_status_ok) - return -1; - if (virJSONValueToStringOne(object->data.object.pairs[i].value, g) < 0) - return -1; - } - if (yajl_gen_map_close(g) != yajl_gen_status_ok) - return -1; - break; - case VIR_JSON_TYPE_ARRAY: - if (yajl_gen_array_open(g) != yajl_gen_status_ok) - return -1; - for (i = 0; i < object->data.array.nvalues ; i++) { - if (virJSONValueToStringOne(object->data.array.values[i], g) < 0) - return -1; - } - if (yajl_gen_array_close(g) != yajl_gen_status_ok) - return -1; - break; - - case VIR_JSON_TYPE_STRING: - if (yajl_gen_string(g, (unsigned char *)object->data.string, - strlen(object->data.string)) != yajl_gen_status_ok) - return -1; - break; - - case VIR_JSON_TYPE_NUMBER: - if (yajl_gen_number(g, object->data.number, - strlen(object->data.number)) != yajl_gen_status_ok) - return -1; - break; - - case VIR_JSON_TYPE_BOOLEAN: - if (yajl_gen_bool(g, object->data.boolean) != yajl_gen_status_ok) - return -1; - break; - - case VIR_JSON_TYPE_NULL: - if (yajl_gen_null(g) != yajl_gen_status_ok) - return -1; - break; - - default: - return -1; - } - - return 0; -} - -char *virJSONValueToString(virJSONValuePtr object, - bool pretty) -{ - yajl_gen g; - const unsigned char *str; - char *ret = NULL; - yajl_size_t len; -# ifndef HAVE_YAJL2 - yajl_gen_config conf = { pretty ? 1 : 0, pretty ? " " : " "}; -# endif - - VIR_DEBUG("object=%p", object); - -# ifdef HAVE_YAJL2 - g = yajl_gen_alloc(NULL); - if (g) { - yajl_gen_config(g, yajl_gen_beautify, pretty ? 1 : 0); - yajl_gen_config(g, yajl_gen_indent_string, pretty ? " " : " "); - yajl_gen_config(g, yajl_gen_validate_utf8, 1); - } -# else - g = yajl_gen_alloc(&conf, NULL); -# endif - if (!g) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to create JSON formatter")); - goto cleanup; - } - - if (virJSONValueToStringOne(object, g) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (yajl_gen_get_buf(g, &str, &len) != yajl_gen_status_ok) { - virReportOOMError(); - goto cleanup; - } - - if (!(ret = strdup((const char *)str))) - virReportOOMError(); - -cleanup: - yajl_gen_free(g); - - VIR_DEBUG("result=%s", NULLSTR(ret)); - - return ret; -} - - -#else -virJSONValuePtr virJSONValueFromString(const char *jsonstring ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("No JSON parser implementation is available")); - return NULL; -} -char *virJSONValueToString(virJSONValuePtr object ATTRIBUTE_UNUSED, - bool pretty ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("No JSON parser implementation is available")); - return NULL; -} -#endif diff --git a/src/util/json.h b/src/util/json.h deleted file mode 100644 index 0a76b3a..0000000 --- a/src/util/json.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * json.h: JSON object parsing/formatting - * - * Copyright (C) 2009, 2012 Red Hat, Inc. - * Copyright (C) 2009 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, see - * <http://www.gnu.org/licenses/>. - * - */ - - -#ifndef __VIR_JSON_H_ -# define __VIR_JSON_H_ - -# include "internal.h" - - -typedef enum { - VIR_JSON_TYPE_OBJECT, - VIR_JSON_TYPE_ARRAY, - VIR_JSON_TYPE_STRING, - VIR_JSON_TYPE_NUMBER, - VIR_JSON_TYPE_BOOLEAN, - VIR_JSON_TYPE_NULL, -} virJSONType; - -typedef struct _virJSONValue virJSONValue; -typedef virJSONValue *virJSONValuePtr; - -typedef struct _virJSONObject virJSONObject; -typedef virJSONObject *virJSONObjectPtr; - -typedef struct _virJSONObjectPair virJSONObjectPair; -typedef virJSONObjectPair *virJSONObjectPairPtr; - -typedef struct _virJSONArray virJSONArray; -typedef virJSONArray *virJSONArrayPtr; - - -struct _virJSONObjectPair { - char *key; - virJSONValuePtr value; -}; - -struct _virJSONObject { - unsigned int npairs; - virJSONObjectPairPtr pairs; -}; - -struct _virJSONArray { - unsigned int nvalues; - virJSONValuePtr *values; -}; - -struct _virJSONValue { - int type; /* enum virJSONType */ - bool protect; /* prevents deletion when embedded in another object */ - - union { - virJSONObject object; - virJSONArray array; - char *string; - char *number; /* int/float/etc format is context defined so we can't parse it here :-( */ - int boolean; - } data; -}; - -void virJSONValueFree(virJSONValuePtr value); - -virJSONValuePtr virJSONValueNewString(const char *data); -virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length); -virJSONValuePtr virJSONValueNewNumberInt(int data); -virJSONValuePtr virJSONValueNewNumberUint(unsigned int data); -virJSONValuePtr virJSONValueNewNumberLong(long long data); -virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data); -virJSONValuePtr virJSONValueNewNumberDouble(double data); -virJSONValuePtr virJSONValueNewBoolean(int boolean); -virJSONValuePtr virJSONValueNewNull(void); -virJSONValuePtr virJSONValueNewArray(void); -virJSONValuePtr virJSONValueNewObject(void); - -int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr value); -int virJSONValueArrayAppend(virJSONValuePtr object, virJSONValuePtr value); - -int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key); -virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key); - -int virJSONValueArraySize(virJSONValuePtr object); -virJSONValuePtr virJSONValueArrayGet(virJSONValuePtr object, unsigned int element); - -int virJSONValueObjectKeysNumber(virJSONValuePtr object); -const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n); -virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n); - -const char *virJSONValueGetString(virJSONValuePtr object); -int virJSONValueGetNumberInt(virJSONValuePtr object, int *value); -int virJSONValueGetNumberUint(virJSONValuePtr object, unsigned int *value); -int virJSONValueGetNumberLong(virJSONValuePtr object, long long *value); -int virJSONValueGetNumberUlong(virJSONValuePtr object, unsigned long long *value); -int virJSONValueGetNumberDouble(virJSONValuePtr object, double *value); -int virJSONValueGetBoolean(virJSONValuePtr object, bool *value); -int virJSONValueIsNull(virJSONValuePtr object); - -const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key); -int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value); -int virJSONValueObjectGetNumberUint(virJSONValuePtr object, const char *key, unsigned int *value); -int virJSONValueObjectGetNumberLong(virJSONValuePtr object, const char *key, long long *value); -int virJSONValueObjectGetNumberUlong(virJSONValuePtr object, const char *key, unsigned long long *value); -int virJSONValueObjectGetNumberDouble(virJSONValuePtr object, const char *key, double *value); -int virJSONValueObjectGetBoolean(virJSONValuePtr object, const char *key, bool *value); -int virJSONValueObjectIsNull(virJSONValuePtr object, const char *key); - -int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char *value); -int virJSONValueObjectAppendNumberInt(virJSONValuePtr object, const char *key, int number); -int virJSONValueObjectAppendNumberUint(virJSONValuePtr object, const char *key, unsigned int number); -int virJSONValueObjectAppendNumberLong(virJSONValuePtr object, const char *key, long long number); -int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned long long number); -int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double number); -int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean); -int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key); - -virJSONValuePtr virJSONValueFromString(const char *jsonstring); -char *virJSONValueToString(virJSONValuePtr object, - bool pretty); - -#endif /* __VIR_JSON_H_ */ diff --git a/src/util/virjson.c b/src/util/virjson.c new file mode 100644 index 0000000..a07dd5c --- /dev/null +++ b/src/util/virjson.c @@ -0,0 +1,1122 @@ +/* + * json.c: JSON object parsing/formatting + * + * Copyright (C) 2009-2010, 2012 Red Hat, Inc. + * Copyright (C) 2009 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, see + * <http://www.gnu.org/licenses/>. + * + */ + + +#include <config.h> + +#include "virjson.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" +#include "util.h" + +#if HAVE_YAJL +# include <yajl/yajl_gen.h> +# include <yajl/yajl_parse.h> + +# ifdef HAVE_YAJL2 +# define yajl_size_t size_t +# else +# define yajl_size_t unsigned int +# endif + +#endif + +/* XXX fixme */ +#define VIR_FROM_THIS VIR_FROM_NONE + + +typedef struct _virJSONParserState virJSONParserState; +typedef virJSONParserState *virJSONParserStatePtr; +struct _virJSONParserState { + virJSONValuePtr value; + char *key; +}; + +typedef struct _virJSONParser virJSONParser; +typedef virJSONParser *virJSONParserPtr; +struct _virJSONParser { + virJSONValuePtr head; + virJSONParserStatePtr state; + unsigned int nstate; +}; + + +void virJSONValueFree(virJSONValuePtr value) +{ + int i; + if (!value || value->protect) + return; + + switch ((virJSONType) value->type) { + case VIR_JSON_TYPE_OBJECT: + for (i = 0 ; i < value->data.object.npairs; i++) { + VIR_FREE(value->data.object.pairs[i].key); + virJSONValueFree(value->data.object.pairs[i].value); + } + VIR_FREE(value->data.object.pairs); + break; + case VIR_JSON_TYPE_ARRAY: + for (i = 0 ; i < value->data.array.nvalues ; i++) + virJSONValueFree(value->data.array.values[i]); + VIR_FREE(value->data.array.values); + break; + case VIR_JSON_TYPE_STRING: + VIR_FREE(value->data.string); + break; + case VIR_JSON_TYPE_NUMBER: + VIR_FREE(value->data.number); + break; + case VIR_JSON_TYPE_BOOLEAN: + case VIR_JSON_TYPE_NULL: + break; + } + + VIR_FREE(value); +} + + +virJSONValuePtr virJSONValueNewString(const char *data) +{ + virJSONValuePtr val; + + if (!data) + return virJSONValueNewNull(); + + if (VIR_ALLOC(val) < 0) + return NULL; + + val->type = VIR_JSON_TYPE_STRING; + if (!(val->data.string = strdup(data))) { + VIR_FREE(val); + return NULL; + } + + return val; +} + +virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length) +{ + virJSONValuePtr val; + + if (!data) + return virJSONValueNewNull(); + + if (VIR_ALLOC(val) < 0) + return NULL; + + val->type = VIR_JSON_TYPE_STRING; + if (!(val->data.string = strndup(data, length))) { + VIR_FREE(val); + return NULL; + } + + return val; +} + +static virJSONValuePtr virJSONValueNewNumber(const char *data) +{ + virJSONValuePtr val; + + if (VIR_ALLOC(val) < 0) + return NULL; + + val->type = VIR_JSON_TYPE_NUMBER; + if (!(val->data.number = strdup(data))) { + VIR_FREE(val); + return NULL; + } + + return val; +} + +virJSONValuePtr virJSONValueNewNumberInt(int data) +{ + virJSONValuePtr val = NULL; + char *str; + if (virAsprintf(&str, "%i", data) < 0) + return NULL; + val = virJSONValueNewNumber(str); + VIR_FREE(str); + return val; +} + + +virJSONValuePtr virJSONValueNewNumberUint(unsigned int data) +{ + virJSONValuePtr val = NULL; + char *str; + if (virAsprintf(&str, "%u", data) < 0) + return NULL; + val = virJSONValueNewNumber(str); + VIR_FREE(str); + return val; +} + + +virJSONValuePtr virJSONValueNewNumberLong(long long data) +{ + virJSONValuePtr val = NULL; + char *str; + if (virAsprintf(&str, "%lld", data) < 0) + return NULL; + val = virJSONValueNewNumber(str); + VIR_FREE(str); + return val; +} + + +virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data) +{ + virJSONValuePtr val = NULL; + char *str; + if (virAsprintf(&str, "%llu", data) < 0) + return NULL; + val = virJSONValueNewNumber(str); + VIR_FREE(str); + return val; +} + + +virJSONValuePtr virJSONValueNewNumberDouble(double data) +{ + virJSONValuePtr val = NULL; + char *str; + if (virDoubleToStr(&str, data) < 0) + return NULL; + val = virJSONValueNewNumber(str); + VIR_FREE(str); + return val; +} + + +virJSONValuePtr virJSONValueNewBoolean(int boolean_) +{ + virJSONValuePtr val; + + if (VIR_ALLOC(val) < 0) + return NULL; + + val->type = VIR_JSON_TYPE_BOOLEAN; + val->data.boolean = boolean_; + + return val; +} + +virJSONValuePtr virJSONValueNewNull(void) +{ + virJSONValuePtr val; + + if (VIR_ALLOC(val) < 0) + return NULL; + + val->type = VIR_JSON_TYPE_NULL; + + return val; +} + +virJSONValuePtr virJSONValueNewArray(void) +{ + virJSONValuePtr val; + + if (VIR_ALLOC(val) < 0) + return NULL; + + val->type = VIR_JSON_TYPE_ARRAY; + + return val; +} + +virJSONValuePtr virJSONValueNewObject(void) +{ + virJSONValuePtr val; + + if (VIR_ALLOC(val) < 0) + return NULL; + + val->type = VIR_JSON_TYPE_OBJECT; + + return val; +} + +int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr value) +{ + char *newkey; + + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + if (virJSONValueObjectHasKey(object, key)) + return -1; + + if (!(newkey = strdup(key))) + return -1; + + if (VIR_REALLOC_N(object->data.object.pairs, + object->data.object.npairs + 1) < 0) { + VIR_FREE(newkey); + return -1; + } + + object->data.object.pairs[object->data.object.npairs].key = newkey; + object->data.object.pairs[object->data.object.npairs].value = value; + object->data.object.npairs++; + + return 0; +} + + +int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char *value) +{ + virJSONValuePtr jvalue = virJSONValueNewString(value); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + +int virJSONValueObjectAppendNumberInt(virJSONValuePtr object, const char *key, int number) +{ + virJSONValuePtr jvalue = virJSONValueNewNumberInt(number); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + + +int virJSONValueObjectAppendNumberUint(virJSONValuePtr object, const char *key, unsigned int number) +{ + virJSONValuePtr jvalue = virJSONValueNewNumberUint(number); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + +int virJSONValueObjectAppendNumberLong(virJSONValuePtr object, const char *key, long long number) +{ + virJSONValuePtr jvalue = virJSONValueNewNumberLong(number); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + +int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned long long number) +{ + virJSONValuePtr jvalue = virJSONValueNewNumberUlong(number); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + +int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double number) +{ + virJSONValuePtr jvalue = virJSONValueNewNumberDouble(number); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + +int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean_) +{ + virJSONValuePtr jvalue = virJSONValueNewBoolean(boolean_); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + +int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key) +{ + virJSONValuePtr jvalue = virJSONValueNewNull(); + if (!jvalue) + return -1; + if (virJSONValueObjectAppend(object, key, jvalue) < 0) { + virJSONValueFree(jvalue); + return -1; + } + return 0; +} + + +int virJSONValueArrayAppend(virJSONValuePtr array, virJSONValuePtr value) +{ + if (array->type != VIR_JSON_TYPE_ARRAY) + return -1; + + if (VIR_REALLOC_N(array->data.array.values, + array->data.array.nvalues + 1) < 0) + return -1; + + array->data.array.values[array->data.array.nvalues] = value; + array->data.array.nvalues++; + + return 0; +} + +int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key) +{ + int i; + + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + for (i = 0 ; i < object->data.object.npairs ; i++) { + if (STREQ(object->data.object.pairs[i].key, key)) + return 1; + } + + return 0; +} + +virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key) +{ + int i; + + if (object->type != VIR_JSON_TYPE_OBJECT) + return NULL; + + for (i = 0 ; i < object->data.object.npairs ; i++) { + if (STREQ(object->data.object.pairs[i].key, key)) + return object->data.object.pairs[i].value; + } + + return NULL; +} + +int virJSONValueObjectKeysNumber(virJSONValuePtr object) +{ + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + return object->data.object.npairs; +} + +const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n) +{ + if (object->type != VIR_JSON_TYPE_OBJECT) + return NULL; + + if (n >= object->data.object.npairs) + return NULL; + + return object->data.object.pairs[n].key; +} + +virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n) +{ + if (object->type != VIR_JSON_TYPE_OBJECT) + return NULL; + + if (n >= object->data.object.npairs) + return NULL; + + return object->data.object.pairs[n].value; +} + +int virJSONValueArraySize(virJSONValuePtr array) +{ + if (array->type != VIR_JSON_TYPE_ARRAY) + return -1; + + return array->data.array.nvalues; +} + + +virJSONValuePtr virJSONValueArrayGet(virJSONValuePtr array, unsigned int element) +{ + if (array->type != VIR_JSON_TYPE_ARRAY) + return NULL; + + if (element >= array->data.array.nvalues) + return NULL; + + return array->data.array.values[element]; +} + +const char *virJSONValueGetString(virJSONValuePtr string) +{ + if (string->type != VIR_JSON_TYPE_STRING) + return NULL; + + return string->data.string; +} + + +int virJSONValueGetNumberInt(virJSONValuePtr number, int *value) +{ + if (number->type != VIR_JSON_TYPE_NUMBER) + return -1; + + return virStrToLong_i(number->data.number, NULL, 10, value); +} + +int virJSONValueGetNumberUint(virJSONValuePtr number, unsigned int *value) +{ + if (number->type != VIR_JSON_TYPE_NUMBER) + return -1; + + return virStrToLong_ui(number->data.number, NULL, 10, value); +} + +int virJSONValueGetNumberLong(virJSONValuePtr number, long long *value) +{ + if (number->type != VIR_JSON_TYPE_NUMBER) + return -1; + + return virStrToLong_ll(number->data.number, NULL, 10, value); +} + +int virJSONValueGetNumberUlong(virJSONValuePtr number, unsigned long long *value) +{ + if (number->type != VIR_JSON_TYPE_NUMBER) + return -1; + + return virStrToLong_ull(number->data.number, NULL, 10, value); +} + +int virJSONValueGetNumberDouble(virJSONValuePtr number, double *value) +{ + if (number->type != VIR_JSON_TYPE_NUMBER) + return -1; + + return virStrToDouble(number->data.number, NULL, value); +} + + +int virJSONValueGetBoolean(virJSONValuePtr val, bool *value) +{ + if (val->type != VIR_JSON_TYPE_BOOLEAN) + return -1; + + *value = val->data.boolean; + return 0; +} + + +int virJSONValueIsNull(virJSONValuePtr val) +{ + if (val->type != VIR_JSON_TYPE_NULL) + return 0; + + return 1; +} + + +const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return NULL; + + val = virJSONValueObjectGet(object, key); + if (!val) + return NULL; + + return virJSONValueGetString(val); +} + + +int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + val = virJSONValueObjectGet(object, key); + if (!val) + return -1; + + return virJSONValueGetNumberInt(val, value); +} + + +int virJSONValueObjectGetNumberUint(virJSONValuePtr object, const char *key, unsigned int *value) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + val = virJSONValueObjectGet(object, key); + if (!val) + return -1; + + return virJSONValueGetNumberUint(val, value); +} + + +int virJSONValueObjectGetNumberLong(virJSONValuePtr object, const char *key, long long *value) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + val = virJSONValueObjectGet(object, key); + if (!val) + return -1; + + return virJSONValueGetNumberLong(val, value); +} + + +int virJSONValueObjectGetNumberUlong(virJSONValuePtr object, const char *key, unsigned long long *value) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + val = virJSONValueObjectGet(object, key); + if (!val) + return -1; + + return virJSONValueGetNumberUlong(val, value); +} + + +int virJSONValueObjectGetNumberDouble(virJSONValuePtr object, const char *key, double *value) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + val = virJSONValueObjectGet(object, key); + if (!val) + return -1; + + return virJSONValueGetNumberDouble(val, value); +} + + +int virJSONValueObjectGetBoolean(virJSONValuePtr object, const char *key, bool *value) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + val = virJSONValueObjectGet(object, key); + if (!val) + return -1; + + return virJSONValueGetBoolean(val, value); +} + + +int virJSONValueObjectIsNull(virJSONValuePtr object, const char *key) +{ + virJSONValuePtr val; + if (object->type != VIR_JSON_TYPE_OBJECT) + return -1; + + val = virJSONValueObjectGet(object, key); + if (!val) + return -1; + + return virJSONValueIsNull(val); +} + + +#if HAVE_YAJL +static int virJSONParserInsertValue(virJSONParserPtr parser, + virJSONValuePtr value) +{ + if (!parser->head) { + parser->head = value; + } else { + virJSONParserStatePtr state; + if (!parser->nstate) { + VIR_DEBUG("got a value to insert without a container"); + return -1; + } + + state = &parser->state[parser->nstate-1]; + + switch (state->value->type) { + case VIR_JSON_TYPE_OBJECT: { + if (!state->key) { + VIR_DEBUG("missing key when inserting object value"); + return -1; + } + + if (virJSONValueObjectAppend(state->value, + state->key, + value) < 0) + return -1; + + VIR_FREE(state->key); + } break; + + case VIR_JSON_TYPE_ARRAY: { + if (state->key) { + VIR_DEBUG("unexpected key when inserting array value"); + return -1; + } + + if (virJSONValueArrayAppend(state->value, + value) < 0) + return -1; + } break; + + default: + VIR_DEBUG("unexpected value type, not a container"); + return -1; + } + } + + return 0; +} + +static int virJSONParserHandleNull(void *ctx) +{ + virJSONParserPtr parser = ctx; + virJSONValuePtr value = virJSONValueNewNull(); + + VIR_DEBUG("parser=%p", parser); + + if (!value) + return 0; + + if (virJSONParserInsertValue(parser, value) < 0) { + virJSONValueFree(value); + return 0; + } + + return 1; +} + +static int virJSONParserHandleBoolean(void *ctx, int boolean_) +{ + virJSONParserPtr parser = ctx; + virJSONValuePtr value = virJSONValueNewBoolean(boolean_); + + VIR_DEBUG("parser=%p boolean=%d", parser, boolean_); + + if (!value) + return 0; + + if (virJSONParserInsertValue(parser, value) < 0) { + virJSONValueFree(value); + return 0; + } + + return 1; +} + +static int virJSONParserHandleNumber(void *ctx, + const char *s, + yajl_size_t l) +{ + virJSONParserPtr parser = ctx; + char *str = strndup(s, l); + virJSONValuePtr value; + + if (!str) + return -1; + value = virJSONValueNewNumber(str); + VIR_FREE(str); + + VIR_DEBUG("parser=%p str=%s", parser, str); + + if (!value) + return 0; + + if (virJSONParserInsertValue(parser, value) < 0) { + virJSONValueFree(value); + return 0; + } + + return 1; +} + +static int virJSONParserHandleString(void *ctx, + const unsigned char *stringVal, + yajl_size_t stringLen) +{ + virJSONParserPtr parser = ctx; + virJSONValuePtr value = virJSONValueNewStringLen((const char *)stringVal, + stringLen); + + VIR_DEBUG("parser=%p str=%p", parser, (const char *)stringVal); + + if (!value) + return 0; + + if (virJSONParserInsertValue(parser, value) < 0) { + virJSONValueFree(value); + return 0; + } + + return 1; +} + +static int virJSONParserHandleMapKey(void *ctx, + const unsigned char *stringVal, + yajl_size_t stringLen) +{ + virJSONParserPtr parser = ctx; + virJSONParserStatePtr state; + + VIR_DEBUG("parser=%p key=%p", parser, (const char *)stringVal); + + if (!parser->nstate) + return 0; + + state = &parser->state[parser->nstate-1]; + if (state->key) + return 0; + state->key = strndup((const char *)stringVal, stringLen); + if (!state->key) + return 0; + return 1; +} + +static int virJSONParserHandleStartMap(void *ctx) +{ + virJSONParserPtr parser = ctx; + virJSONValuePtr value = virJSONValueNewObject(); + + VIR_DEBUG("parser=%p", parser); + + if (!value) + return 0; + + if (virJSONParserInsertValue(parser, value) < 0) { + virJSONValueFree(value); + return 0; + } + + if (VIR_REALLOC_N(parser->state, + parser->nstate + 1) < 0) { + virJSONValueFree(value); + return 0; + } + + parser->state[parser->nstate].value = value; + parser->state[parser->nstate].key = NULL; + parser->nstate++; + + return 1; +} + + +static int virJSONParserHandleEndMap(void *ctx) +{ + virJSONParserPtr parser = ctx; + virJSONParserStatePtr state; + + VIR_DEBUG("parser=%p", parser); + + if (!parser->nstate) + return 0; + + state = &(parser->state[parser->nstate-1]); + if (state->key) { + VIR_FREE(state->key); + return 0; + } + + if (VIR_REALLOC_N(parser->state, + parser->nstate - 1) < 0) + return 0; + parser->nstate--; + + return 1; +} + +static int virJSONParserHandleStartArray(void *ctx) +{ + virJSONParserPtr parser = ctx; + virJSONValuePtr value = virJSONValueNewArray(); + + VIR_DEBUG("parser=%p", parser); + + if (!value) + return 0; + + if (virJSONParserInsertValue(parser, value) < 0) { + virJSONValueFree(value); + return 0; + } + + if (VIR_REALLOC_N(parser->state, + parser->nstate + 1) < 0) + return 0; + + parser->state[parser->nstate].value = value; + parser->state[parser->nstate].key = NULL; + parser->nstate++; + + return 1; +} + +static int virJSONParserHandleEndArray(void *ctx) +{ + virJSONParserPtr parser = ctx; + virJSONParserStatePtr state; + + VIR_DEBUG("parser=%p", parser); + + if (!parser->nstate) + return 0; + + state = &(parser->state[parser->nstate-1]); + if (state->key) { + VIR_FREE(state->key); + return 0; + } + + if (VIR_REALLOC_N(parser->state, + parser->nstate - 1) < 0) + return 0; + parser->nstate--; + + return 1; +} + +static const yajl_callbacks parserCallbacks = { + virJSONParserHandleNull, + virJSONParserHandleBoolean, + NULL, + NULL, + virJSONParserHandleNumber, + virJSONParserHandleString, + virJSONParserHandleStartMap, + virJSONParserHandleMapKey, + virJSONParserHandleEndMap, + virJSONParserHandleStartArray, + virJSONParserHandleEndArray +}; + + +/* XXX add an incremental streaming parser - yajl trivially supports it */ +virJSONValuePtr virJSONValueFromString(const char *jsonstring) +{ + yajl_handle hand; + virJSONParser parser = { NULL, NULL, 0 }; + virJSONValuePtr ret = NULL; +# ifndef HAVE_YAJL2 + yajl_parser_config cfg = { 1, 1 }; +# endif + + VIR_DEBUG("string=%s", jsonstring); + +# ifdef HAVE_YAJL2 + hand = yajl_alloc(&parserCallbacks, NULL, &parser); + if (hand) { + yajl_config(hand, yajl_allow_comments, 1); + yajl_config(hand, yajl_dont_validate_strings, 0); + } +# else + hand = yajl_alloc(&parserCallbacks, &cfg, NULL, &parser); +# endif + if (!hand) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to create JSON parser")); + goto cleanup; + } + + if (yajl_parse(hand, + (const unsigned char *)jsonstring, + strlen(jsonstring)) != yajl_status_ok) { + unsigned char *errstr = yajl_get_error(hand, 1, + (const unsigned char*)jsonstring, + strlen(jsonstring)); + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse json %s: %s"), + jsonstring, (const char*) errstr); + VIR_FREE(errstr); + virJSONValueFree(parser.head); + goto cleanup; + } + + ret = parser.head; + +cleanup: + yajl_free(hand); + + if (parser.nstate) { + int i; + for (i = 0 ; i < parser.nstate ; i++) { + VIR_FREE(parser.state[i].key); + } + } + + VIR_DEBUG("result=%p", parser.head); + + return ret; +} + + +static int virJSONValueToStringOne(virJSONValuePtr object, + yajl_gen g) +{ + int i; + + VIR_DEBUG("object=%p type=%d gen=%p", object, object->type, g); + + switch (object->type) { + case VIR_JSON_TYPE_OBJECT: + if (yajl_gen_map_open(g) != yajl_gen_status_ok) + return -1; + for (i = 0; i < object->data.object.npairs ; i++) { + if (yajl_gen_string(g, + (unsigned char *)object->data.object.pairs[i].key, + strlen(object->data.object.pairs[i].key)) + != yajl_gen_status_ok) + return -1; + if (virJSONValueToStringOne(object->data.object.pairs[i].value, g) < 0) + return -1; + } + if (yajl_gen_map_close(g) != yajl_gen_status_ok) + return -1; + break; + case VIR_JSON_TYPE_ARRAY: + if (yajl_gen_array_open(g) != yajl_gen_status_ok) + return -1; + for (i = 0; i < object->data.array.nvalues ; i++) { + if (virJSONValueToStringOne(object->data.array.values[i], g) < 0) + return -1; + } + if (yajl_gen_array_close(g) != yajl_gen_status_ok) + return -1; + break; + + case VIR_JSON_TYPE_STRING: + if (yajl_gen_string(g, (unsigned char *)object->data.string, + strlen(object->data.string)) != yajl_gen_status_ok) + return -1; + break; + + case VIR_JSON_TYPE_NUMBER: + if (yajl_gen_number(g, object->data.number, + strlen(object->data.number)) != yajl_gen_status_ok) + return -1; + break; + + case VIR_JSON_TYPE_BOOLEAN: + if (yajl_gen_bool(g, object->data.boolean) != yajl_gen_status_ok) + return -1; + break; + + case VIR_JSON_TYPE_NULL: + if (yajl_gen_null(g) != yajl_gen_status_ok) + return -1; + break; + + default: + return -1; + } + + return 0; +} + +char *virJSONValueToString(virJSONValuePtr object, + bool pretty) +{ + yajl_gen g; + const unsigned char *str; + char *ret = NULL; + yajl_size_t len; +# ifndef HAVE_YAJL2 + yajl_gen_config conf = { pretty ? 1 : 0, pretty ? " " : " "}; +# endif + + VIR_DEBUG("object=%p", object); + +# ifdef HAVE_YAJL2 + g = yajl_gen_alloc(NULL); + if (g) { + yajl_gen_config(g, yajl_gen_beautify, pretty ? 1 : 0); + yajl_gen_config(g, yajl_gen_indent_string, pretty ? " " : " "); + yajl_gen_config(g, yajl_gen_validate_utf8, 1); + } +# else + g = yajl_gen_alloc(&conf, NULL); +# endif + if (!g) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to create JSON formatter")); + goto cleanup; + } + + if (virJSONValueToStringOne(object, g) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (yajl_gen_get_buf(g, &str, &len) != yajl_gen_status_ok) { + virReportOOMError(); + goto cleanup; + } + + if (!(ret = strdup((const char *)str))) + virReportOOMError(); + +cleanup: + yajl_gen_free(g); + + VIR_DEBUG("result=%s", NULLSTR(ret)); + + return ret; +} + + +#else +virJSONValuePtr virJSONValueFromString(const char *jsonstring ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No JSON parser implementation is available")); + return NULL; +} +char *virJSONValueToString(virJSONValuePtr object ATTRIBUTE_UNUSED, + bool pretty ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("No JSON parser implementation is available")); + return NULL; +} +#endif diff --git a/src/util/virjson.h b/src/util/virjson.h new file mode 100644 index 0000000..0a76b3a --- /dev/null +++ b/src/util/virjson.h @@ -0,0 +1,138 @@ +/* + * json.h: JSON object parsing/formatting + * + * Copyright (C) 2009, 2012 Red Hat, Inc. + * Copyright (C) 2009 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, see + * <http://www.gnu.org/licenses/>. + * + */ + + +#ifndef __VIR_JSON_H_ +# define __VIR_JSON_H_ + +# include "internal.h" + + +typedef enum { + VIR_JSON_TYPE_OBJECT, + VIR_JSON_TYPE_ARRAY, + VIR_JSON_TYPE_STRING, + VIR_JSON_TYPE_NUMBER, + VIR_JSON_TYPE_BOOLEAN, + VIR_JSON_TYPE_NULL, +} virJSONType; + +typedef struct _virJSONValue virJSONValue; +typedef virJSONValue *virJSONValuePtr; + +typedef struct _virJSONObject virJSONObject; +typedef virJSONObject *virJSONObjectPtr; + +typedef struct _virJSONObjectPair virJSONObjectPair; +typedef virJSONObjectPair *virJSONObjectPairPtr; + +typedef struct _virJSONArray virJSONArray; +typedef virJSONArray *virJSONArrayPtr; + + +struct _virJSONObjectPair { + char *key; + virJSONValuePtr value; +}; + +struct _virJSONObject { + unsigned int npairs; + virJSONObjectPairPtr pairs; +}; + +struct _virJSONArray { + unsigned int nvalues; + virJSONValuePtr *values; +}; + +struct _virJSONValue { + int type; /* enum virJSONType */ + bool protect; /* prevents deletion when embedded in another object */ + + union { + virJSONObject object; + virJSONArray array; + char *string; + char *number; /* int/float/etc format is context defined so we can't parse it here :-( */ + int boolean; + } data; +}; + +void virJSONValueFree(virJSONValuePtr value); + +virJSONValuePtr virJSONValueNewString(const char *data); +virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length); +virJSONValuePtr virJSONValueNewNumberInt(int data); +virJSONValuePtr virJSONValueNewNumberUint(unsigned int data); +virJSONValuePtr virJSONValueNewNumberLong(long long data); +virJSONValuePtr virJSONValueNewNumberUlong(unsigned long long data); +virJSONValuePtr virJSONValueNewNumberDouble(double data); +virJSONValuePtr virJSONValueNewBoolean(int boolean); +virJSONValuePtr virJSONValueNewNull(void); +virJSONValuePtr virJSONValueNewArray(void); +virJSONValuePtr virJSONValueNewObject(void); + +int virJSONValueObjectAppend(virJSONValuePtr object, const char *key, virJSONValuePtr value); +int virJSONValueArrayAppend(virJSONValuePtr object, virJSONValuePtr value); + +int virJSONValueObjectHasKey(virJSONValuePtr object, const char *key); +virJSONValuePtr virJSONValueObjectGet(virJSONValuePtr object, const char *key); + +int virJSONValueArraySize(virJSONValuePtr object); +virJSONValuePtr virJSONValueArrayGet(virJSONValuePtr object, unsigned int element); + +int virJSONValueObjectKeysNumber(virJSONValuePtr object); +const char *virJSONValueObjectGetKey(virJSONValuePtr object, unsigned int n); +virJSONValuePtr virJSONValueObjectGetValue(virJSONValuePtr object, unsigned int n); + +const char *virJSONValueGetString(virJSONValuePtr object); +int virJSONValueGetNumberInt(virJSONValuePtr object, int *value); +int virJSONValueGetNumberUint(virJSONValuePtr object, unsigned int *value); +int virJSONValueGetNumberLong(virJSONValuePtr object, long long *value); +int virJSONValueGetNumberUlong(virJSONValuePtr object, unsigned long long *value); +int virJSONValueGetNumberDouble(virJSONValuePtr object, double *value); +int virJSONValueGetBoolean(virJSONValuePtr object, bool *value); +int virJSONValueIsNull(virJSONValuePtr object); + +const char *virJSONValueObjectGetString(virJSONValuePtr object, const char *key); +int virJSONValueObjectGetNumberInt(virJSONValuePtr object, const char *key, int *value); +int virJSONValueObjectGetNumberUint(virJSONValuePtr object, const char *key, unsigned int *value); +int virJSONValueObjectGetNumberLong(virJSONValuePtr object, const char *key, long long *value); +int virJSONValueObjectGetNumberUlong(virJSONValuePtr object, const char *key, unsigned long long *value); +int virJSONValueObjectGetNumberDouble(virJSONValuePtr object, const char *key, double *value); +int virJSONValueObjectGetBoolean(virJSONValuePtr object, const char *key, bool *value); +int virJSONValueObjectIsNull(virJSONValuePtr object, const char *key); + +int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char *value); +int virJSONValueObjectAppendNumberInt(virJSONValuePtr object, const char *key, int number); +int virJSONValueObjectAppendNumberUint(virJSONValuePtr object, const char *key, unsigned int number); +int virJSONValueObjectAppendNumberLong(virJSONValuePtr object, const char *key, long long number); +int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned long long number); +int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double number); +int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean); +int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key); + +virJSONValuePtr virJSONValueFromString(const char *jsonstring); +char *virJSONValueToString(virJSONValuePtr object, + bool pretty); + +#endif /* __VIR_JSON_H_ */ diff --git a/src/util/virlockspace.h b/src/util/virlockspace.h index 9c5128b..041cf20 100644 --- a/src/util/virlockspace.h +++ b/src/util/virlockspace.h @@ -23,7 +23,7 @@ # define __VIR_LOCK_SPACE_H__ # include "internal.h" -# include "json.h" +# include "virjson.h" typedef struct _virLockSpace virLockSpace; typedef virLockSpace *virLockSpacePtr; diff --git a/tests/jsontest.c b/tests/jsontest.c index 412f475..98a6069 100644 --- a/tests/jsontest.c +++ b/tests/jsontest.c @@ -6,7 +6,7 @@ #include <time.h> #include "internal.h" -#include "json.h" +#include "virjson.h" #include "testutils.h" struct testInfo { diff --git a/tools/virsh-host.c b/tools/virsh-host.c index f687780..6f129d1 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -38,7 +38,7 @@ #include "virsh-domain.h" #include "xml.h" #include "virtypedparam.h" -#include "json.h" +#include "virjson.h" /* * "capabilities" command -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- daemon/libvirtd-config.c | 2 +- daemon/libvirtd.h | 2 +- daemon/remote.c | 2 +- daemon/stream.c | 2 +- src/Makefile.am | 2 +- src/conf/domain_audit.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_event.c | 2 +- src/conf/nwfilter_params.c | 2 +- src/conf/secret_conf.c | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/virconsole.c | 2 +- src/cpu/cpu.c | 2 +- src/cpu/cpu_powerpc.c | 2 +- src/cpu/cpu_x86.c | 2 +- src/datatypes.c | 2 +- src/driver.c | 2 +- src/esx/esx_device_monitor.c | 2 +- src/esx/esx_driver.c | 2 +- src/esx/esx_interface_driver.c | 2 +- src/esx/esx_network_driver.c | 2 +- src/esx/esx_nwfilter_driver.c | 2 +- src/esx/esx_secret_driver.c | 2 +- src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/esx/esx_util.c | 2 +- src/esx/esx_vi.c | 2 +- src/esx/esx_vi_methods.c | 2 +- src/esx/esx_vi_types.c | 2 +- src/fdstream.c | 2 +- src/hyperv/hyperv_device_monitor.c | 2 +- src/hyperv/hyperv_driver.c | 2 +- src/hyperv/hyperv_interface_driver.c | 2 +- src/hyperv/hyperv_network_driver.c | 2 +- src/hyperv/hyperv_nwfilter_driver.c | 2 +- src/hyperv/hyperv_secret_driver.c | 2 +- src/hyperv/hyperv_storage_driver.c | 2 +- src/hyperv/hyperv_util.c | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/interface/interface_backend_netcf.c | 2 +- src/libvirt-qemu.c | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/locking/domain_lock.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_daemon_config.c | 2 +- src/locking/lock_daemon_dispatch.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_nop.c | 2 +- src/locking/lock_driver_sanlock.c | 2 +- src/locking/lock_manager.c | 2 +- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_controller.c | 2 +- src/lxc/lxc_domain.c | 2 +- src/lxc/lxc_driver.c | 2 +- src/lxc/lxc_fuse.c | 2 +- src/lxc/lxc_monitor.c | 2 +- src/lxc/lxc_process.c | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_driver.c | 2 +- src/node_device/node_device_hal.c | 2 +- src/node_device/node_device_linux_sysfs.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/nodeinfo.c | 2 +- src/nwfilter/nwfilter_dhcpsnoop.c | 2 +- src/nwfilter/nwfilter_driver.c | 2 +- src/nwfilter/nwfilter_ebiptables_driver.c | 2 +- src/nwfilter/nwfilter_gentech_driver.c | 2 +- src/nwfilter/nwfilter_learnipaddr.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_agent.c | 2 +- src/qemu/qemu_bridge_filter.c | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_cgroup.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_domain.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_text.c | 2 +- src/qemu/qemu_process.c | 2 +- src/remote/remote_driver.c | 2 +- src/rpc/virkeepalive.c | 2 +- src/rpc/virnetclient.c | 2 +- src/rpc/virnetclientprogram.c | 2 +- src/rpc/virnetclientstream.c | 2 +- src/rpc/virnetmessage.c | 2 +- src/rpc/virnetsaslcontext.c | 2 +- src/rpc/virnetserver.c | 2 +- src/rpc/virnetserverclient.c | 2 +- src/rpc/virnetservermdns.c | 2 +- src/rpc/virnetserverprogram.c | 2 +- src/rpc/virnetsocket.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/rpc/virnettlscontext.c | 2 +- src/secret/secret_driver.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_driver.c | 2 +- src/security/security_manager.c | 2 +- src/security/security_selinux.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_disk.c | 2 +- src/storage/storage_backend_fs.c | 2 +- src/storage/storage_backend_iscsi.c | 2 +- src/storage/storage_backend_logical.c | 2 +- src/storage/storage_backend_mpath.c | 2 +- src/storage/storage_backend_rbd.c | 2 +- src/storage/storage_backend_scsi.c | 2 +- src/storage/storage_backend_sheepdog.c | 2 +- src/storage/storage_driver.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/logging.c | 1590 ----------------------------- src/util/logging.h | 191 ---- src/util/memory.c | 2 +- src/util/pci.c | 2 +- src/util/storage_file.c | 2 +- src/util/sysinfo.c | 2 +- src/util/util.c | 2 +- src/util/uuid.c | 2 +- src/util/viraudit.c | 2 +- src/util/virauth.c | 2 +- src/util/virauthconfig.c | 2 +- src/util/vircgroup.c | 2 +- src/util/vircommand.c | 2 +- src/util/virconf.c | 2 +- src/util/virdbus.c | 2 +- src/util/virdnsmasq.c | 2 +- src/util/virebtables.c | 2 +- src/util/virevent.c | 2 +- src/util/vireventpoll.c | 2 +- src/util/virfile.c | 2 +- src/util/virhash.c | 2 +- src/util/virhooks.c | 2 +- src/util/viriptables.c | 2 +- src/util/virjson.c | 2 +- src/util/virkeyfile.c | 2 +- src/util/virlockspace.c | 2 +- src/util/virlog.c | 1590 +++++++++++++++++++++++++++++ src/util/virlog.h | 191 ++++ src/util/virnetdev.c | 2 +- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevtap.c | 2 +- src/util/virnetdevveth.c | 2 +- src/util/virnetdevvportprofile.c | 2 +- src/util/virnetlink.c | 2 +- src/util/virnodesuspend.c | 2 +- src/util/virobject.c | 2 +- src/util/virpidfile.c | 2 +- src/util/virprocess.c | 2 +- src/util/virrandom.c | 2 +- src/util/virterror.c | 2 +- src/util/virusb.c | 2 +- src/vbox/vbox_MSCOMGlue.c | 2 +- src/vbox/vbox_XPCOMCGlue.c | 2 +- src/vbox/vbox_driver.c | 2 +- src/vbox/vbox_tmpl.c | 2 +- src/vmx/vmx.c | 2 +- src/xen/xen_driver.c | 2 +- src/xen/xen_hypervisor.c | 2 +- src/xen/xen_inotify.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xm_internal.c | 2 +- src/xen/xs_internal.c | 2 +- src/xenapi/xenapi_utils.c | 2 +- src/xenxs/xen_sxpr.c | 2 +- tests/eventtest.c | 2 +- tests/libvirtdconftest.c | 2 +- tests/qemumonitortestutils.c | 2 +- tests/securityselinuxtest.c | 2 +- tests/sockettest.c | 2 +- tests/testutils.c | 2 +- tests/virauthconfigtest.c | 2 +- tests/virdrivermoduletest.c | 2 +- tests/virhashtest.c | 2 +- tests/virkeyfiletest.c | 2 +- tests/virlockspacetest.c | 2 +- tests/virnetmessagetest.c | 2 +- tests/virnetsockettest.c | 2 +- tests/virnettlscontexttest.c | 2 +- tests/virstringtest.c | 2 +- tests/virtimetest.c | 2 +- tests/viruritest.c | 2 +- tools/console.c | 2 +- 195 files changed, 1972 insertions(+), 1972 deletions(-) delete mode 100644 src/util/logging.c delete mode 100644 src/util/logging.h create mode 100644 src/util/virlog.c create mode 100644 src/util/virlog.h diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index 0ca185c..f61f08d 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -27,7 +27,7 @@ #include "virconf.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "rpc/virnetserver.h" #include "configmake.h" #include "remote/remote_protocol.h" diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index e389151..b04cc71 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -33,7 +33,7 @@ # include <rpc/xdr.h> # include "remote_protocol.h" # include "qemu_protocol.h" -# include "logging.h" +# include "virlog.h" # include "threads.h" # if HAVE_SASL # include "virnetsaslcontext.h" diff --git a/daemon/remote.c b/daemon/remote.c index 1746280..58ceb39 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -34,7 +34,7 @@ #include "libvirt_internal.h" #include "datatypes.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "stream.h" #include "uuid.h" diff --git a/daemon/stream.c b/daemon/stream.c index fa14eeb..d63e009 100644 --- a/daemon/stream.c +++ b/daemon/stream.c @@ -26,7 +26,7 @@ #include "stream.h" #include "remote.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virnetserverclient.h" #include "virterror_internal.h" diff --git a/src/Makefile.am b/src/Makefile.am index dd49851..93da171 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/logging.c util/logging.h \ util/memory.c util/memory.h \ util/pci.c util/pci.h \ util/processinfo.c util/processinfo.h \ @@ -84,6 +83,7 @@ UTIL_SOURCES = \ util/virnodesuspend.c util/virnodesuspend.h \ util/viriptables.c util/viriptables.h \ util/virjson.c util/virjson.h \ + util/virlog.c util/virlog.h \ util/virobject.c util/virobject.h \ util/virpidfile.c util/virpidfile.h \ util/virprocess.c util/virprocess.h \ diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 939d213..5fca6a6 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -29,7 +29,7 @@ #include "domain_audit.h" #include "viraudit.h" #include "uuid.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" /* Return nn:mm in hex for block and character devices, and NULL diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d1fadc3..c48adf5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -40,7 +40,7 @@ #include "uuid.h" #include "util.h" #include "virbuffer.h" -#include "logging.h" +#include "virlog.h" #include "nwfilter_conf.h" #include "storage_file.h" #include "virfile.h" diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index cf37308..f1e247b 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -24,7 +24,7 @@ #include <config.h> #include "domain_event.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "memory.h" #include "virterror_internal.h" diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c index 7254519..f8cf980 100644 --- a/src/conf/nwfilter_params.c +++ b/src/conf/nwfilter_params.c @@ -30,7 +30,7 @@ #include "datatypes.h" #include "nwfilter_params.h" #include "domain_conf.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_NWFILTER diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index ec67f57..24d7aa0 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -25,7 +25,7 @@ #include "internal.h" #include "virbuffer.h" #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "secret_conf.h" #include "virterror_internal.h" diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 38a3e2a..6361810 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -34,7 +34,7 @@ #include "count-one-bits.h" #include "datatypes.h" #include "domain_conf.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "netdev_bandwidth_conf.h" #include "netdev_vport_profile_conf.h" diff --git a/src/conf/virconsole.c b/src/conf/virconsole.c index 143c1a6..92179cc 100644 --- a/src/conf/virconsole.c +++ b/src/conf/virconsole.c @@ -34,7 +34,7 @@ #include "threads.h" #include "memory.h" #include "virpidfile.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "virfile.h" diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 4263b88..17a06f3 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -23,7 +23,7 @@ #include <config.h> -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "xml.h" #include "cpu.h" diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 363d6c1..c59bd1b 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -26,7 +26,7 @@ #include <config.h> #include <stdint.h> -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "util.h" #include "cpu.h" diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 563cd67..bea48a1 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -25,7 +25,7 @@ #include <stdint.h> -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "util.h" #include "cpu.h" diff --git a/src/datatypes.c b/src/datatypes.c index c0ed3a2..73a2fd0 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -24,7 +24,7 @@ #include "datatypes.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "uuid.h" #include "util.h" diff --git a/src/driver.c b/src/driver.c index 6d2feb9..4ef6fd2 100644 --- a/src/driver.c +++ b/src/driver.c @@ -26,7 +26,7 @@ #include "driver.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "configmake.h" diff --git a/src/esx/esx_device_monitor.c b/src/esx/esx_device_monitor.c index c3f9339..0ad95f5 100644 --- a/src/esx/esx_device_monitor.c +++ b/src/esx/esx_device_monitor.c @@ -27,7 +27,7 @@ #include "internal.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "esx_private.h" #include "esx_device_monitor.h" diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index a858298..a69d149 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -30,7 +30,7 @@ #include "virauth.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "vmx.h" #include "virtypedparam.h" diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 35bc7fa..4760264 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -27,7 +27,7 @@ #include "internal.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "interface_conf.h" #include "virsocketaddr.h" diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index 6a87abd..3e25aa2 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -28,7 +28,7 @@ #include "internal.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "network_conf.h" #include "esx_private.h" diff --git a/src/esx/esx_nwfilter_driver.c b/src/esx/esx_nwfilter_driver.c index 9780ca6..f5e710d 100644 --- a/src/esx/esx_nwfilter_driver.c +++ b/src/esx/esx_nwfilter_driver.c @@ -27,7 +27,7 @@ #include "internal.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "esx_private.h" #include "esx_nwfilter_driver.h" diff --git a/src/esx/esx_secret_driver.c b/src/esx/esx_secret_driver.c index 55b2e9a..2a98644 100644 --- a/src/esx/esx_secret_driver.c +++ b/src/esx/esx_secret_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "esx_private.h" #include "esx_secret_driver.h" diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index b6cde96..5d4eb3c 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -30,7 +30,7 @@ #include "md5.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "storage_conf.h" #include "storage_file.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index 5ef2981..c8bba9e 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -33,7 +33,7 @@ #include "md5.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "storage_conf.h" #include "storage_file.h" diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index b807607..6e27fe4 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -30,7 +30,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "vmx.h" #include "esx_private.h" diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index d645bfb..76192df 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -28,7 +28,7 @@ #include "virbuffer.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "uuid.h" #include "vmx.h" diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c index a3c3c8b..a3870ee 100644 --- a/src/esx/esx_vi_methods.c +++ b/src/esx/esx_vi_methods.c @@ -25,7 +25,7 @@ #include "virbuffer.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "esx_vi_methods.h" #include "esx_util.h" diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index 1654e1b..d0a2c6c 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -30,7 +30,7 @@ #include "virbuffer.h" #include "datatypes.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "esx_vi.h" #include "esx_vi_types.h" diff --git a/src/fdstream.c b/src/fdstream.c index d1eb04c..fdbd7a2 100644 --- a/src/fdstream.c +++ b/src/fdstream.c @@ -35,7 +35,7 @@ #include "fdstream.h" #include "virterror_internal.h" #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "util.h" #include "virfile.h" diff --git a/src/hyperv/hyperv_device_monitor.c b/src/hyperv/hyperv_device_monitor.c index e183798..1fa98b2 100644 --- a/src/hyperv/hyperv_device_monitor.c +++ b/src/hyperv/hyperv_device_monitor.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_device_monitor.h" diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 4aed41f..95b0cd9 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -29,7 +29,7 @@ #include "virauth.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_driver.h" #include "hyperv_interface_driver.h" diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c index 9b1bb37..6a3c2cb 100644 --- a/src/hyperv/hyperv_interface_driver.c +++ b/src/hyperv/hyperv_interface_driver.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_interface_driver.h" diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index 3a61fe6..2f9fcab 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_network_driver.h" diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c index 9d54f82..c490522 100644 --- a/src/hyperv/hyperv_nwfilter_driver.c +++ b/src/hyperv/hyperv_nwfilter_driver.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_nwfilter_driver.h" diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c index 7ee8ce9..3d58b01 100644 --- a/src/hyperv/hyperv_secret_driver.c +++ b/src/hyperv/hyperv_secret_driver.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_secret_driver.h" diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c index 2e03162..7fbc14d 100644 --- a/src/hyperv/hyperv_storage_driver.c +++ b/src/hyperv/hyperv_storage_driver.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_storage_driver.h" diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c index 3050d61..1ef6dae 100644 --- a/src/hyperv/hyperv_util.c +++ b/src/hyperv/hyperv_util.c @@ -26,7 +26,7 @@ #include "datatypes.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "hyperv_private.h" #include "hyperv_util.h" diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 0a6b107..069ebe6 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -27,7 +27,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "util.h" #include "uuid.h" diff --git a/src/interface/interface_backend_netcf.c b/src/interface/interface_backend_netcf.c index 226e020..1f42920 100644 --- a/src/interface/interface_backend_netcf.c +++ b/src/interface/interface_backend_netcf.c @@ -30,7 +30,7 @@ #include "interface_driver.h" #include "interface_conf.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_INTERFACE diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index cc98bbb..8d53b5c 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -24,7 +24,7 @@ #include <config.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "libvirt/libvirt-qemu.h" diff --git a/src/libvirt.c b/src/libvirt.c index 8f7a869..d078304 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -46,7 +46,7 @@ #endif #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "driver.h" diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 55d2ef4..460d15f 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -32,7 +32,7 @@ #include <sys/utsname.h> #include "internal.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "datatypes.h" #include "virfile.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 884fca8..ced7cfa 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -32,7 +32,7 @@ #include <fcntl.h> #include "internal.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "virconf.h" #include "datatypes.h" diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c index 1e3da5f..00861cf 100644 --- a/src/locking/domain_lock.c +++ b/src/locking/domain_lock.c @@ -25,7 +25,7 @@ #include "memory.h" #include "uuid.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_LOCKING diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index 08caa16..3c2a50c 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -38,7 +38,7 @@ #include "virpidfile.h" #include "virprocess.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "virconf.h" #include "rpc/virnetserver.h" diff --git a/src/locking/lock_daemon_config.c b/src/locking/lock_daemon_config.c index c2d9a76..9557b8c 100644 --- a/src/locking/lock_daemon_config.c +++ b/src/locking/lock_daemon_config.c @@ -27,7 +27,7 @@ #include "virconf.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "rpc/virnetserver.h" #include "configmake.h" diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c index bb4dcfa..78c9726 100644 --- a/src/locking/lock_daemon_dispatch.c +++ b/src/locking/lock_daemon_dispatch.c @@ -25,7 +25,7 @@ #include "rpc/virnetserver.h" #include "rpc/virnetserverclient.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "lock_daemon.h" #include "lock_protocol.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index c88c5af..d5d721d 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -24,7 +24,7 @@ #include "lock_driver.h" #include "virconf.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "util.h" #include "virfile.h" diff --git a/src/locking/lock_driver_nop.c b/src/locking/lock_driver_nop.c index c9ab806..745a0bf 100644 --- a/src/locking/lock_driver_nop.c +++ b/src/locking/lock_driver_nop.c @@ -23,7 +23,7 @@ #include "lock_driver_nop.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index 2eadc07..1e8df26 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -37,7 +37,7 @@ #include "dirname.h" #include "lock_driver.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "memory.h" #include "util.h" diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c index e6d9308..f038d4e 100644 --- a/src/locking/lock_manager.c +++ b/src/locking/lock_manager.c @@ -24,7 +24,7 @@ #include "lock_manager.h" #include "lock_driver_nop.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "memory.h" #include "uuid.h" diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index e354d6c..b8c4308 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -25,7 +25,7 @@ #include "lxc_container.h" #include "virfile.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "vircgroup.h" diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 77667bd..ca36965 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virconf.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "configmake.h" #include "lxc_container.h" diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 33ebf1f..4aae28e 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -54,7 +54,7 @@ #endif #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "lxc_container.h" #include "util.h" #include "memory.h" diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index c9cac5d..78f10ab 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -53,7 +53,7 @@ #endif #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "lxc_conf.h" diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index bd80d9f..77a64dd 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -24,7 +24,7 @@ #include "lxc_domain.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 9c35406..0ab2cb9 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -36,7 +36,7 @@ #include <wait.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "lxc_conf.h" #include "lxc_container.h" diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c index 4e7df55..485456e 100644 --- a/src/lxc/lxc_fuse.c +++ b/src/lxc/lxc_fuse.c @@ -32,7 +32,7 @@ #include "lxc_fuse.h" #include "lxc_cgroup.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "virbuffer.h" diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c index 4d177c9..9eb587d 100644 --- a/src/lxc/lxc_monitor.c +++ b/src/lxc/lxc_monitor.c @@ -28,7 +28,7 @@ #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "threads.h" #include "rpc/virnetclient.h" diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index d59bd2e..02ed226 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -41,7 +41,7 @@ #include "memory.h" #include "domain_audit.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "vircommand.h" #include "virhooks.h" diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index bc37bde..2a59b84 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -57,7 +57,7 @@ #include "memory.h" #include "uuid.h" #include "viriptables.h" -#include "logging.h" +#include "virlog.h" #include "virdnsmasq.h" #include "configmake.h" #include "virnetdev.h" diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 4d3e01b..48360e3 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "node_device_conf.h" #include "node_device_hal.h" #include "node_device_driver.h" diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 080aaed..59ba5c3 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -36,7 +36,7 @@ #include "memory.h" #include "uuid.h" #include "pci.h" -#include "logging.h" +#include "virlog.h" #include "node_device_driver.h" #include "virdbus.h" diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index 3048e33..fbe0da5 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -30,7 +30,7 @@ #include "node_device_hal.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index b3499fb..fef00ad 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -32,7 +32,7 @@ #include "node_device_driver.h" #include "driver.h" #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "uuid.h" #include "util.h" diff --git a/src/nodeinfo.c b/src/nodeinfo.c index 096000b..0019c2b 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -43,7 +43,7 @@ #include "nodeinfo.h" #include "physmem.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "count-one-bits.h" #include "intprops.h" diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c index e4c895f..68aa233 100644 --- a/src/nwfilter/nwfilter_dhcpsnoop.c +++ b/src/nwfilter/nwfilter_dhcpsnoop.c @@ -55,7 +55,7 @@ #include <net/if.h> #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "virterror_internal.h" #include "conf/domain_conf.h" diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c index 3aa026a..7fde656 100644 --- a/src/nwfilter/nwfilter_driver.c +++ b/src/nwfilter/nwfilter_driver.c @@ -28,7 +28,7 @@ #include <config.h> #include "virdbus.h" -#include "logging.h" +#include "virlog.h" #include "internal.h" diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index 6966acf..23a43d2 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -32,7 +32,7 @@ #include "virbuffer.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "domain_conf.h" #include "nwfilter_conf.h" diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c index 572acf4..6be4a93 100644 --- a/src/nwfilter/nwfilter_gentech_driver.c +++ b/src/nwfilter/nwfilter_gentech_driver.c @@ -27,7 +27,7 @@ #include "internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "domain_conf.h" #include "virterror_internal.h" #include "nwfilter_gentech_driver.h" diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c index 361bdce..110eae8 100644 --- a/src/nwfilter/nwfilter_learnipaddr.c +++ b/src/nwfilter/nwfilter_learnipaddr.c @@ -43,7 +43,7 @@ #include "intprops.h" #include "virbuffer.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "virnetdev.h" #include "virterror_internal.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 75d52e2..101fa32 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -56,7 +56,7 @@ #include "memory.h" #include "virfile.h" #include "virtypedparam.h" -#include "logging.h" +#include "virlog.h" #include "vircommand.h" #include "viruri.h" #include "stats_linux.h" diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 648cb48..4e6f903 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -45,7 +45,7 @@ #include "virterror_internal.h" #include "memory.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "vircommand.h" #include "configmake.h" #include "storage_file.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index e54f0f3..0ac2771 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -49,7 +49,7 @@ #include "datatypes.h" #include "virbuffer.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "driver.h" #include "libvirt/libvirt.h" #include "virterror_internal.h" diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 6727294..421e43f 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -35,7 +35,7 @@ #include "qemu_agent.h" #include "qemu_command.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "virjson.h" #include "virfile.h" diff --git a/src/qemu/qemu_bridge_filter.c b/src/qemu/qemu_bridge_filter.c index a6d0d4f..08a9f1a 100644 --- a/src/qemu/qemu_bridge_filter.c +++ b/src/qemu/qemu_bridge_filter.c @@ -27,7 +27,7 @@ #include "qemu_driver.h" #include "util.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "qemu_bridge_filter.h" diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index f68e081..5853180 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -25,7 +25,7 @@ #include "qemu_capabilities.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "util.h" #include "virfile.h" diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 6c6607d..8d9ccf9 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -27,7 +27,7 @@ #include "qemu_domain.h" #include "qemu_process.h" #include "vircgroup.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "virterror_internal.h" #include "util.h" diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 04a9512..8a35982 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -29,7 +29,7 @@ #include "qemu_bridge_filter.h" #include "cpu/cpu.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "util.h" #include "virfile.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 7c8d826..598fad7 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -48,7 +48,7 @@ #include "datatypes.h" #include "xml.h" #include "nodeinfo.h" -#include "logging.h" +#include "virlog.h" #include "cpu/cpu.h" #include "domain_nwfilter.h" #include "virfile.h" diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 8d8cf02..e6eaa58 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -28,7 +28,7 @@ #include "qemu_capabilities.h" #include "qemu_migration.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "c-ctype.h" #include "cpu/cpu.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 79f42fb..25e5738 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -60,7 +60,7 @@ #include "qemu_migration.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "virbuffer.h" #include "util.h" diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index aa000d1..3854520 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -24,7 +24,7 @@ #include <config.h> #include "qemu_hostdev.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "memory.h" #include "pci.h" diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e9a5e35..7edd125 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -32,7 +32,7 @@ #include "qemu_hostdev.h" #include "domain_audit.h" #include "domain_nwfilter.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "virterror_internal.h" #include "memory.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 468a92f..cabbe1a 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -36,7 +36,7 @@ #include "qemu_cgroup.h" #include "domain_audit.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "memory.h" #include "util.h" diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 131e8df..920453d 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -33,7 +33,7 @@ #include "qemu_monitor_json.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "virprocess.h" #include "virobject.h" diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 6181668..e14134b 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -36,7 +36,7 @@ #include "qemu_command.h" #include "qemu_capabilities.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "driver.h" #include "datatypes.h" #include "virterror_internal.h" diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index a12adb6..28690b1 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -35,7 +35,7 @@ #include "c-ctype.h" #include "c-strcasestr.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "driver.h" #include "datatypes.h" #include "virterror_internal.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index e528d78..a77b248 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -51,7 +51,7 @@ #endif #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "memory.h" #include "virhooks.h" diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 8b77e7d..1e9151a 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -30,7 +30,7 @@ #include "virnetclientprogram.h" #include "virnetclientstream.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "domain_event.h" #include "driver.h" diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index 309f22f..8fc1cba 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -25,7 +25,7 @@ #include "memory.h" #include "threads.h" #include "virfile.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "virterror_internal.h" #include "virnetsocket.h" diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index bf2547c..7370ae0 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -33,7 +33,7 @@ #include "memory.h" #include "threads.h" #include "virfile.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "virterror_internal.h" diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c index 1f08640..dec3943 100644 --- a/src/rpc/virnetclientprogram.c +++ b/src/rpc/virnetclientprogram.c @@ -30,7 +30,7 @@ #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "virfile.h" #include "threads.h" diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c index 0e7e38e..26dc292 100644 --- a/src/rpc/virnetclientstream.c +++ b/src/rpc/virnetclientstream.c @@ -26,7 +26,7 @@ #include "virnetclient.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "threads.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c index cf76e21..16d8e61 100644 --- a/src/rpc/virnetmessage.c +++ b/src/rpc/virnetmessage.c @@ -26,7 +26,7 @@ #include "virnetmessage.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "util.h" diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c index b6b68d5..e880127 100644 --- a/src/rpc/virnetsaslcontext.c +++ b/src/rpc/virnetsaslcontext.c @@ -28,7 +28,7 @@ #include "virterror_internal.h" #include "memory.h" #include "threads.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index f686a8f..6d3532a 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -28,7 +28,7 @@ #include <fcntl.h> #include "virnetserver.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "virterror_internal.h" #include "threads.h" diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index ed26719..9642ea5 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -29,7 +29,7 @@ #include "virnetserverclient.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "memory.h" #include "threads.h" diff --git a/src/rpc/virnetservermdns.c b/src/rpc/virnetservermdns.c index 166b4eb..c17b65d 100644 --- a/src/rpc/virnetservermdns.c +++ b/src/rpc/virnetservermdns.c @@ -44,7 +44,7 @@ #include "vireventpoll.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c index e4aa2da..5b96c34 100644 --- a/src/rpc/virnetserverprogram.c +++ b/src/rpc/virnetserverprogram.c @@ -28,7 +28,7 @@ #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "threads.h" diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 5a2eab3..aa8f4b9 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -44,7 +44,7 @@ #include "util.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "threads.h" #include "virprocess.h" diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index d890569..734acaa 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -28,7 +28,7 @@ #include "internal.h" #include "virbuffer.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "configmake.h" #include "threads.h" #include "util.h" diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 1d32327..2931003 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -33,7 +33,7 @@ #include "memory.h" #include "virterror_internal.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "threads.h" #include "configmake.h" diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index d9ba42b..4159358 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -32,7 +32,7 @@ #include "base64.h" #include "datatypes.h" #include "driver.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "secret_conf.h" #include "secret_driver.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 034eb04..f2aebc8 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -48,7 +48,7 @@ #include "virfile.h" #include "configmake.h" #include "vircommand.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_SECURITY #define SECURITY_APPARMOR_VOID_DOI "0" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 9f5d39d..9ff2665 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "pci.h" #include "virusb.h" #include "storage_file.h" diff --git a/src/security/security_driver.c b/src/security/security_driver.c index c7ff8a5..82d3ca9 100644 --- a/src/security/security_driver.c +++ b/src/security/security_driver.c @@ -24,7 +24,7 @@ #include <string.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "security_driver.h" #ifdef WITH_SECDRIVER_SELINUX diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 690e4da..67c8858 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -28,7 +28,7 @@ #include "security_dac.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index eb4f253..2a19781 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -36,7 +36,7 @@ #include "virterror_internal.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "pci.h" #include "virusb.h" #include "storage_file.h" diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 083028d..899caeb 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -54,7 +54,7 @@ #include "uuid.h" #include "storage_file.h" #include "storage_backend.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "stat-time.h" diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c index c6aa407..7e1d3ec 100644 --- a/src/storage/storage_backend_disk.c +++ b/src/storage/storage_backend_disk.c @@ -27,7 +27,7 @@ #include <stdio.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "storage_backend_disk.h" #include "util.h" #include "memory.h" diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index cdf93af..78b50f0 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -49,7 +49,7 @@ #include "memory.h" #include "xml.h" #include "virfile.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index c468b1b..46659af 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -39,7 +39,7 @@ #include "storage_backend_iscsi.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "vircommand.h" #include "virrandom.h" diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c index 53e6c61..f28c663 100644 --- a/src/storage/storage_backend_logical.c +++ b/src/storage/storage_backend_logical.c @@ -36,7 +36,7 @@ #include "storage_conf.h" #include "vircommand.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_backend_mpath.c b/src/storage/storage_backend_mpath.c index efcfb28..1ca120f 100644 --- a/src/storage/storage_backend_mpath.c +++ b/src/storage/storage_backend_mpath.c @@ -33,7 +33,7 @@ #include "storage_conf.h" #include "storage_backend.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index bc61cf7..4e58911 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -27,7 +27,7 @@ #include "storage_conf.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "base64.h" #include "uuid.h" #include "rados/librados.h" diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c index 6515e57..32713be 100644 --- a/src/storage/storage_backend_scsi.c +++ b/src/storage/storage_backend_scsi.c @@ -31,7 +31,7 @@ #include "virterror_internal.h" #include "storage_backend_scsi.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c index ecca7a8..05deeeb 100644 --- a/src/storage/storage_backend_sheepdog.c +++ b/src/storage/storage_backend_sheepdog.c @@ -32,7 +32,7 @@ #include "vircommand.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index c567fff..6076f6c 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -44,7 +44,7 @@ #include "storage_conf.h" #include "memory.h" #include "storage_backend.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "fdstream.h" #include "configmake.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 8e57370..dbaf14e 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -48,7 +48,7 @@ #include "node_device_conf.h" #include "xml.h" #include "threads.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "virtypedparam.h" #include "virrandom.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 51e5a7a..35b54c2 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -42,7 +42,7 @@ #include "util.h" #include "memory.h" #include "nodeinfo.h" -#include "logging.h" +#include "virlog.h" #include "domain_nwfilter.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 8dece66..90c9b66 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -56,7 +56,7 @@ #include "domain_conf.h" #include "domain_audit.h" #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "domain_nwfilter.h" #include "virfile.h" #include "fdstream.h" diff --git a/src/util/logging.c b/src/util/logging.c deleted file mode 100644 index 0df3549..0000000 --- a/src/util/logging.c +++ /dev/null @@ -1,1590 +0,0 @@ -/* - * logging.c: internal logging and debugging - * - * Copyright (C) 2008, 2010-2012 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#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> -#include <signal.h> -#include <execinfo.h> -#if HAVE_SYSLOG_H -# include <syslog.h> -#endif -#include <sys/socket.h> -#if HAVE_SYS_UN_H -# include <sys/un.h> -#endif - -#include "virterror_internal.h" -#include "logging.h" -#include "memory.h" -#include "util.h" -#include "virbuffer.h" -#include "threads.h" -#include "virfile.h" -#include "virtime.h" -#include "intprops.h" - -/* Journald output is only supported on Linux new enough to expose - * htole64. */ -#if HAVE_SYSLOG_H && defined(__linux__) && HAVE_DECL_HTOLE64 -# define USE_JOURNALD 1 -#endif - -#define VIR_FROM_THIS VIR_FROM_NONE - -VIR_ENUM_DECL(virLogSource) -VIR_ENUM_IMPL(virLogSource, VIR_LOG_FROM_LAST, - "file", - "error", - "audit", - "trace", - "library"); - -/* - * A logging buffer to keep some history over logs - */ - -static int virLogSize = 64 * 1024; -static char *virLogBuffer = NULL; -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; - virLogPriority priority; - unsigned int flags; -}; -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 { - bool logVersion; - void *data; - virLogOutputFunc f; - virLogCloseFunc c; - virLogPriority priority; - virLogDestination dest; - const char *name; -}; -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); -static void virLogOutputToFd(virLogSource src, - virLogPriority priority, - const char *filename, - int linenr, - const char *funcname, - const char *timestamp, - virLogMetadataPtr metadata, - unsigned int flags, - const char *rawstr, - const char *str, - void *data); - -/* - * Logs accesses must be serialized though a mutex - */ -virMutex virLogMutex; - -void -virLogLock(void) -{ - virMutexLock(&virLogMutex); -} - - -void -virLogUnlock(void) -{ - virMutexUnlock(&virLogMutex); -} - - -static const char * -virLogOutputString(virLogDestination ldest) -{ - switch (ldest) { - case VIR_LOG_TO_STDERR: - return "stderr"; - case VIR_LOG_TO_SYSLOG: - return "syslog"; - case VIR_LOG_TO_FILE: - return "file"; - case VIR_LOG_TO_JOURNALD: - return "journald"; - } - return "unknown"; -} - - -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 -virLogOnceInit(void) -{ - const char *pbm = NULL; - - if (virMutexInit(&virLogMutex) < 0) - return -1; - - virLogLock(); - if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) { - /* - * The debug buffer is not a critical component, allow startup - * even in case of failure to allocate it in case of a - * configuration mistake. - */ - virLogSize = 64 * 1024; - if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) { - pbm = "Failed to allocate debug buffer: deactivating debug log\n"; - virLogSize = 0; - } else { - pbm = "Failed to allocate debug buffer: reduced to 64 kB\n"; - } - } - virLogLen = 0; - virLogStart = 0; - virLogEnd = 0; - virLogDefaultPriority = VIR_LOG_DEFAULT; - virLogUnlock(); - if (pbm) - VIR_WARN("%s", pbm); - return 0; -} - -VIR_ONCE_GLOBAL_INIT(virLog) - - -/** - * virLogSetBufferSize: - * @size: size of the buffer in kilobytes or <= 0 to deactivate - * - * Dynamically set the size or deactivate the logging buffer used to keep - * a trace of all recent debug output. Note that the content of the buffer - * is lost if it gets reallocated. - * - * Return -1 in case of failure or 0 in case of success - */ -int -virLogSetBufferSize(int size) -{ - int ret = 0; - int oldsize; - char *oldLogBuffer; - const char *pbm = NULL; - - if (size < 0) - size = 0; - - if (virLogInitialize() < 0) - return -1; - - if (size * 1024 == virLogSize) - return ret; - - virLogLock(); - - oldsize = virLogSize; - oldLogBuffer = virLogBuffer; - - if (INT_MAX / 1024 <= size) { - pbm = "Requested log size of %d kB too large\n"; - ret = -1; - goto error; - } - - virLogSize = size * 1024; - if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) { - pbm = "Failed to allocate debug buffer of %d kB\n"; - virLogBuffer = oldLogBuffer; - virLogSize = oldsize; - ret = -1; - goto error; - } - VIR_FREE(oldLogBuffer); - virLogLen = 0; - virLogStart = 0; - virLogEnd = 0; - -error: - virLogUnlock(); - if (pbm) - VIR_ERROR(pbm, size); - return ret; -} - - -/** - * virLogReset: - * - * Reset the logging module to its default initial state - * - * Returns 0 if successful, and -1 in case or error - */ -int -virLogReset(void) -{ - if (virLogInitialize() < 0) - return -1; - - virLogLock(); - virLogResetFilters(); - virLogResetOutputs(); - virLogLen = 0; - virLogStart = 0; - virLogEnd = 0; - virLogDefaultPriority = VIR_LOG_DEFAULT; - virLogUnlock(); - return 0; -} - - -/* - * Store a string in the ring buffer - */ -static void -virLogStr(const char *str) -{ - int tmp; - int len; - - if ((str == NULL) || (virLogBuffer == NULL) || (virLogSize <= 0)) - return; - len = strlen(str); - if (len >= virLogSize) - return; - - /* - * copy the data and reset the end, we cycle over the end of the buffer - */ - if (virLogEnd + len >= virLogSize) { - tmp = virLogSize - virLogEnd; - memcpy(&virLogBuffer[virLogEnd], str, tmp); - memcpy(&virLogBuffer[0], &str[tmp], len - tmp); - virLogEnd = len - tmp; - } else { - memcpy(&virLogBuffer[virLogEnd], str, len); - virLogEnd += len; - } - virLogBuffer[virLogEnd] = 0; - /* - * Update the log length, and if full move the start index - */ - virLogLen += len; - if (virLogLen > virLogSize) { - tmp = virLogLen - virLogSize; - virLogLen = virLogSize; - virLogStart += tmp; - if (virLogStart >= virLogSize) - virLogStart -= virLogSize; - } -} - - -static void -virLogDumpAllFD(const char *msg, int len) -{ - int i, found = 0; - - if (len <= 0) - len = strlen(msg); - - for (i = 0; i < virLogNbOutputs;i++) { - if (virLogOutputs[i].f == virLogOutputToFd) { - int fd = (intptr_t) virLogOutputs[i].data; - - if (fd >= 0) { - ignore_value(safewrite(fd, msg, len)); - found = 1; - } - } - } - if (!found) - ignore_value(safewrite(STDERR_FILENO, msg, len)); -} - - -/** - * virLogEmergencyDumpAll: - * @signum: the signal number - * - * Emergency function called, possibly from a signal handler. - * It need to output the debug ring buffer through the log - * output which are safe to use from a signal handler. - * In case none is found it is emitted to standard error. - */ -void -virLogEmergencyDumpAll(int signum) -{ - int len; - int oldLogStart, oldLogLen; - - switch (signum) { -#ifdef SIGFPE - case SIGFPE: - virLogDumpAllFD("Caught signal Floating-point exception", -1); - break; -#endif -#ifdef SIGSEGV - case SIGSEGV: - virLogDumpAllFD("Caught Segmentation violation", -1); - break; -#endif -#ifdef SIGILL - case SIGILL: - virLogDumpAllFD("Caught illegal instruction", -1); - break; -#endif -#ifdef SIGABRT - case SIGABRT: - virLogDumpAllFD("Caught abort signal", -1); - break; -#endif -#ifdef SIGBUS - case SIGBUS: - virLogDumpAllFD("Caught bus error", -1); - break; -#endif -#ifdef SIGUSR2 - case SIGUSR2: - virLogDumpAllFD("Caught User-defined signal 2", -1); - break; -#endif - default: - virLogDumpAllFD("Caught unexpected signal", -1); - break; - } - if ((virLogBuffer == NULL) || (virLogSize <= 0)) { - virLogDumpAllFD(" internal log buffer deactivated\n", -1); - return; - } - - virLogDumpAllFD(" dumping internal log buffer:\n", -1); - virLogDumpAllFD("\n\n ====== start of log =====\n\n", -1); - - /* - * Since we can't lock the buffer safely from a signal handler - * we mark it as empty in case of concurrent access, and proceed - * with the data, at worse we will output something a bit weird - * if another thread start logging messages at the same time. - * Note that virLogStr() uses virLogEnd for the computations and - * writes to the buffer and only then updates virLogLen and virLogStart - * so it's best to reset it first. - */ - oldLogStart = virLogStart; - oldLogLen = virLogLen; - virLogEnd = 0; - virLogLen = 0; - virLogStart = 0; - - while (oldLogLen > 0) { - if (oldLogStart + oldLogLen < virLogSize) { - virLogBuffer[oldLogStart + oldLogLen] = 0; - virLogDumpAllFD(&virLogBuffer[oldLogStart], oldLogLen); - oldLogStart += oldLogLen; - oldLogLen = 0; - } else { - len = virLogSize - oldLogStart; - virLogBuffer[virLogSize] = 0; - virLogDumpAllFD(&virLogBuffer[oldLogStart], len); - oldLogLen -= len; - oldLogStart = 0; - } - } - virLogDumpAllFD("\n\n ====== end of log =====\n\n", -1); -} - - -/** - * 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(virLogPriority priority) -{ - if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) { - VIR_WARN("Ignoring invalid log level setting."); - return -1; - } - if (virLogInitialize() < 0) - return -1; - - 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 flags, see virLogFilterFlags enum - * - * 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, - virLogPriority priority, - unsigned int flags) -{ - int i; - char *mdup = NULL; - - virCheckFlags(VIR_LOG_STACK_TRACE, -1); - - 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 (mdup == 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; - virLogFilters[i].flags = flags; - 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, - unsigned int *flags) -{ - int ret = 0; - int i; - - virLogLock(); - for (i = 0;i < virLogNbFilters;i++) { - if (strstr(input, virLogFilters[i].match)) { - ret = virLogFilters[i].priority; - *flags = virLogFilters[i].flags; - 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].name); - } - VIR_FREE(virLogOutputs); - i = virLogNbOutputs; - virLogNbOutputs = 0; - return i; -} - - -/** - * virLogDefineOutput: - * @f: the function to call to output a message - * @c: 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 - * @dest: where to send output of this priority - * @name: optional name data associated with an output - * @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, - virLogPriority priority, - virLogDestination dest, - const char *name, - unsigned int flags) -{ - int ret = -1; - char *ndup = NULL; - - virCheckFlags(0, -1); - - if (f == NULL) - return -1; - - if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) { - if (name == NULL) - return -1; - ndup = strdup(name); - if (ndup == NULL) - return -1; - } - - virLogLock(); - if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) { - VIR_FREE(ndup); - goto cleanup; - } - ret = virLogNbOutputs++; - virLogOutputs[ret].logVersion = true; - virLogOutputs[ret].f = f; - virLogOutputs[ret].c = c; - virLogOutputs[ret].data = data; - virLogOutputs[ret].priority = priority; - virLogOutputs[ret].dest = dest; - virLogOutputs[ret].name = ndup; -cleanup: - virLogUnlock(); - return ret; -} - - -static int -virLogFormatString(char **msg, - int linenr, - const char *funcname, - virLogPriority priority, - const char *str) -{ - int ret; - - /* - * Be careful when changing the following log message formatting, we rely - * on it when stripping libvirt debug messages from qemu log files. So when - * changing this, you might also need to change the code there. - * virLogFormatString() function name is mentioned there so it's sufficient - * to just grep for it to find the right place. - */ - if ((funcname != NULL)) { - ret = virAsprintf(msg, "%d: %s : %s:%d : %s\n", - virThreadSelfID(), virLogPriorityString(priority), - funcname, linenr, str); - } else { - ret = virAsprintf(msg, "%d: %s : %s\n", - virThreadSelfID(), virLogPriorityString(priority), - str); - } - return ret; -} - - -static int -virLogVersionString(const char **rawmsg, - char **msg) -{ -#ifdef PACKAGER_VERSION -# ifdef PACKAGER -# define LOG_VERSION_STRING \ - "libvirt version: " VERSION ", package: " PACKAGER_VERSION " (" PACKAGER ")" -# else -# define LOG_VERSION_STRING \ - "libvirt version: " VERSION ", package: " PACKAGER_VERSION -# endif -#else -# define LOG_VERSION_STRING \ - "libvirt version: " VERSION -#endif - - *rawmsg = LOG_VERSION_STRING; - return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, LOG_VERSION_STRING); -} - - -/** - * virLogMessage: - * @source: where is that message coming from - * @priority: the priority level - * @filename: file where the message was emitted - * @linenr: line where the message was emitted - * @funcname: the function emitting the (debug) message - * @metadata: NULL or metadata array, terminated by an item with NULL key - * @fmt: the string format - * @...: the arguments - * - * Call the libvirt logger with some information. Based on the configuration - * the message may be stored, sent to output or just discarded - */ -void -virLogMessage(virLogSource source, - virLogPriority priority, - const char *filename, - int linenr, - const char *funcname, - virLogMetadataPtr metadata, - const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - virLogVMessage(source, priority, - filename, linenr, funcname, - metadata, fmt, ap); - va_end(ap); -} - - -/** - * virLogVMessage: - * @source: where is that message coming from - * @priority: the priority level - * @filename: file where the message was emitted - * @linenr: line where the message was emitted - * @funcname: the function emitting the (debug) message - * @metadata: NULL or metadata array, terminated by an item with NULL key - * @fmt: the string format - * @vargs: format args - * - * Call the libvirt logger with some information. Based on the configuration - * the message may be stored, sent to output or just discarded - */ -void -virLogVMessage(virLogSource source, - virLogPriority priority, - const char *filename, - int linenr, - const char *funcname, - virLogMetadataPtr metadata, - const char *fmt, - va_list vargs) -{ - static bool logVersionStderr = true; - char *str = NULL; - char *msg = NULL; - char timestamp[VIR_TIME_STRING_BUFLEN]; - int fprio, i, ret; - int saved_errno = errno; - int emit = 1; - unsigned int filterflags = 0; - - if (virLogInitialize() < 0) - return; - - if (fmt == NULL) - goto cleanup; - - /* - * check against list of specific logging patterns - */ - fprio = virLogFiltersCheck(filename, &filterflags); - if (fprio == 0) { - if (priority < virLogDefaultPriority) - emit = 0; - } else if (priority < fprio) { - emit = 0; - } - - if ((emit == 0) && ((virLogBuffer == NULL) || (virLogSize <= 0))) - goto cleanup; - - /* - * serialize the error message, add level and timestamp - */ - if (virVasprintf(&str, fmt, vargs) < 0) { - goto cleanup; - } - - ret = virLogFormatString(&msg, linenr, funcname, priority, str); - if (ret < 0) - goto cleanup; - - if (virTimeStringNowRaw(timestamp) < 0) - timestamp[0] = '\0'; - - /* - * Log based on defaults, first store in the history buffer, - * then if emit 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. - */ - virLogLock(); - virLogStr(timestamp); - virLogStr(msg); - virLogUnlock(); - if (emit == 0) - goto cleanup; - - virLogLock(); - for (i = 0; i < virLogNbOutputs; i++) { - if (priority >= virLogOutputs[i].priority) { - if (virLogOutputs[i].logVersion) { - const char *rawver; - char *ver = NULL; - if (virLogVersionString(&rawver, &ver) >= 0) - virLogOutputs[i].f(VIR_LOG_FROM_FILE, VIR_LOG_INFO, - __FILE__, __LINE__, __func__, - timestamp, NULL, 0, rawver, ver, - virLogOutputs[i].data); - VIR_FREE(ver); - virLogOutputs[i].logVersion = false; - } - virLogOutputs[i].f(source, priority, - filename, linenr, funcname, - timestamp, metadata, filterflags, - str, msg, virLogOutputs[i].data); - } - } - if ((virLogNbOutputs == 0) && (source != VIR_LOG_FROM_ERROR)) { - if (logVersionStderr) { - const char *rawver; - char *ver = NULL; - if (virLogVersionString(&rawver, &ver) >= 0) - virLogOutputToFd(VIR_LOG_FROM_FILE, VIR_LOG_INFO, - __FILE__, __LINE__, __func__, - timestamp, NULL, 0, rawver, ver, - (void *) STDERR_FILENO); - VIR_FREE(ver); - logVersionStderr = false; - } - virLogOutputToFd(source, priority, - filename, linenr, funcname, - timestamp, metadata, filterflags, - str, msg, (void *) STDERR_FILENO); - } - virLogUnlock(); - -cleanup: - VIR_FREE(str); - VIR_FREE(msg); - errno = saved_errno; -} - - -static void -virLogStackTraceToFd(int fd) -{ - void *array[100]; - int size; - static bool doneWarning = false; - const char *msg = "Stack trace not available on this platform\n"; - -#define STRIP_DEPTH 3 - size = backtrace(array, ARRAY_CARDINALITY(array)); - if (size) { - backtrace_symbols_fd(array + STRIP_DEPTH, size - STRIP_DEPTH, fd); - ignore_value(safewrite(fd, "\n", 1)); - } else if (!doneWarning) { - ignore_value(safewrite(fd, msg, strlen(msg))); - doneWarning = true; - } -#undef STRIP_DEPTH -} - -static void -virLogOutputToFd(virLogSource source ATTRIBUTE_UNUSED, - virLogPriority priority ATTRIBUTE_UNUSED, - const char *filename ATTRIBUTE_UNUSED, - int linenr ATTRIBUTE_UNUSED, - const char *funcname ATTRIBUTE_UNUSED, - const char *timestamp, - virLogMetadataPtr metadata ATTRIBUTE_UNUSED, - unsigned int flags, - const char *rawstr ATTRIBUTE_UNUSED, - const char *str, - void *data) -{ - int fd = (intptr_t) data; - char *msg; - - if (fd < 0) - return; - - if (virAsprintf(&msg, "%s: %s", timestamp, str) < 0) - return; - - ignore_value(safewrite(fd, msg, strlen(msg))); - VIR_FREE(msg); - - if (flags & VIR_LOG_STACK_TRACE) - virLogStackTraceToFd(fd); -} - - -static void -virLogCloseFd(void *data) -{ - int fd = (intptr_t) data; - - VIR_LOG_CLOSE(fd); -} - - -static int -virLogAddOutputToStderr(virLogPriority priority) -{ - if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority, - VIR_LOG_TO_STDERR, NULL, 0) < 0) - return -1; - return 0; -} - - -static int -virLogAddOutputToFile(virLogPriority priority, - const char *file) -{ - int fd; - - fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR); - if (fd < 0) - return -1; - if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd, - (void *)(intptr_t)fd, - priority, VIR_LOG_TO_FILE, file, 0) < 0) { - VIR_FORCE_CLOSE(fd); - return -1; - } - return 0; -} - - -#if HAVE_SYSLOG_H -static int -virLogPrioritySyslog(virLogPriority priority) -{ - switch (priority) { - case VIR_LOG_DEBUG: - return LOG_DEBUG; - case VIR_LOG_INFO: - return LOG_INFO; - case VIR_LOG_WARN: - return LOG_WARNING; - case VIR_LOG_ERROR: - return LOG_ERR; - default: - return LOG_ERR; - } -} - - -static void -virLogOutputToSyslog(virLogSource source ATTRIBUTE_UNUSED, - virLogPriority priority, - const char *filename ATTRIBUTE_UNUSED, - int linenr ATTRIBUTE_UNUSED, - const char *funcname ATTRIBUTE_UNUSED, - const char *timestamp ATTRIBUTE_UNUSED, - virLogMetadataPtr metadata ATTRIBUTE_UNUSED, - unsigned int flags, - const char *rawstr ATTRIBUTE_UNUSED, - const char *str, - void *data ATTRIBUTE_UNUSED) -{ - virCheckFlags(VIR_LOG_STACK_TRACE,); - - syslog(virLogPrioritySyslog(priority), "%s", str); -} - -static char *current_ident = NULL; - - -static void -virLogCloseSyslog(void *data ATTRIBUTE_UNUSED) -{ - closelog(); - VIR_FREE(current_ident); -} - - -static int -virLogAddOutputToSyslog(virLogPriority 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, VIR_LOG_TO_SYSLOG, ident, 0) < 0) { - closelog(); - VIR_FREE(current_ident); - return -1; - } - return 0; -} - - -# if USE_JOURNALD -# define IOVEC_SET(iov, data, size) \ - do { \ - struct iovec *_i = &(iov); \ - _i->iov_base = (void*)(data); \ - _i->iov_len = (size); \ - } while (0) - -# define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str)) - -/* Used for conversion of numbers to strings, and for length of binary data */ -# define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t))) - -struct journalState -{ - struct iovec *iov, *iov_end; - char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE]; -}; - -static void -journalAddString(struct journalState *state, const char *field, - const char *value) -{ - static const char newline = '\n', equals = '='; - - if (strchr(value, '\n') != NULL) { - uint64_t nstr; - - /* If 'str' contains a newline, then we must - * encode the string length, since we can't - * rely on the newline for the field separator - */ - if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end) - return; /* Silently drop */ - nstr = htole64(strlen(value)); - memcpy(state->bufs[0], &nstr, sizeof(nstr)); - - IOVEC_SET_STRING(state->iov[0], field); - IOVEC_SET(state->iov[1], &newline, sizeof(newline)); - IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr)); - state->bufs++; - state->iov += 3; - } else { - if (state->iov_end - state->iov < 4) - return; /* Silently drop */ - IOVEC_SET_STRING(state->iov[0], field); - IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals)); - state->iov += 2; - } - IOVEC_SET_STRING(state->iov[0], value); - IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline)); - state->iov += 2; -} - -static void -journalAddInt(struct journalState *state, const char *field, int value) -{ - static const char newline = '\n', equals = '='; - - char *num; - - if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end) - return; /* Silently drop */ - - num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value); - - IOVEC_SET_STRING(state->iov[0], field); - IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals)); - IOVEC_SET_STRING(state->iov[2], num); - IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline)); - state->bufs++; - state->iov += 4; -} - -static int journalfd = -1; - -static void -virLogOutputToJournald(virLogSource source, - virLogPriority priority, - const char *filename, - int linenr, - const char *funcname, - const char *timestamp ATTRIBUTE_UNUSED, - virLogMetadataPtr metadata ATTRIBUTE_UNUSED, - unsigned int flags, - const char *rawstr, - const char *str ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - virCheckFlags(VIR_LOG_STACK_TRACE,); - int buffd = -1; - struct msghdr mh; - struct sockaddr_un sa; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control; - struct cmsghdr *cmsg; - /* We use /dev/shm instead of /tmp here, since we want this to - * be a tmpfs, and one that is available from early boot on - * and where unprivileged users can create files. */ - char path[] = "/dev/shm/journal.XXXXXX"; - -# define NUM_FIELDS 6 - struct iovec iov[NUM_FIELDS * 5]; - char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE]; - struct journalState state; - - state.iov = iov; - state.iov_end = iov + ARRAY_CARDINALITY(iov); - state.bufs = iov_bufs; - state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs); - - journalAddString(&state ,"MESSAGE", rawstr); - journalAddInt(&state, "PRIORITY", priority); - journalAddString(&state, "LIBVIRT_SOURCE", - virLogSourceTypeToString(source)); - journalAddString(&state, "CODE_FILE", filename); - journalAddInt(&state, "CODE_LINE", linenr); - journalAddString(&state, "CODE_FUNC", funcname); - - memset(&sa, 0, sizeof(sa)); - sa.sun_family = AF_UNIX; - if (!virStrcpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path))) - return; - - memset(&mh, 0, sizeof(mh)); - mh.msg_name = &sa; - mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path); - mh.msg_iov = iov; - mh.msg_iovlen = state.iov - iov; - - if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0) - return; - - if (errno != EMSGSIZE && errno != ENOBUFS) - return; - - /* Message was too large, so dump to temporary file - * and pass an FD to the journal - */ - - /* NB: mkostemp is not declared async signal safe by - * POSIX, but this is Linux only code and the GLibc - * impl is safe enough, only using open() and inline - * asm to read a timestamp (falling back to gettimeofday - * on some arches - */ - if ((buffd = mkostemp(path, O_CLOEXEC|O_RDWR)) < 0) - return; - - if (unlink(path) < 0) - goto cleanup; - - if (writev(buffd, iov, state.iov - iov) < 0) - goto cleanup; - - mh.msg_iov = NULL; - mh.msg_iovlen = 0; - - memset(&control, 0, sizeof(control)); - mh.msg_control = &control; - mh.msg_controllen = sizeof(control); - - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &buffd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - sendmsg(journalfd, &mh, MSG_NOSIGNAL); - -cleanup: - VIR_LOG_CLOSE(buffd); -} - - -static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED) -{ - VIR_LOG_CLOSE(journalfd); -} - - -static int virLogAddOutputToJournald(int priority) -{ - if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) - return -1; - if (virSetInherit(journalfd, false) < 0) { - VIR_LOG_CLOSE(journalfd); - return -1; - } - if (virLogDefineOutput(virLogOutputToJournald, virLogCloseJournald, NULL, - priority, VIR_LOG_TO_JOURNALD, NULL, 0) < 0) { - return -1; - } - return 0; -} -# endif /* USE_JOURNALD */ -#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; - char *abspath; - virLogPriority prio; - int ret = -1; - int count = 0; - - if (cur == NULL) - return -1; - - VIR_DEBUG("outputs=%s", outputs); - - 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 (virFileAbsPath(name, &abspath) < 0) { - VIR_FREE(name); - return -1; /* skip warning here because setting was fine */ - } - if (virLogAddOutputToFile(prio, abspath) == 0) - count++; - VIR_FREE(name); - VIR_FREE(abspath); - } else if (STREQLEN(cur, "journald", 8)) { - cur += 8; -#if USE_JOURNALD - if (virLogAddOutputToJournald(prio) == 0) - count++; -#endif /* USE_JOURNALD */ - } else { - goto cleanup; - } - virSkipSpaces(&cur); - } - ret = count; -cleanup: - if (ret == -1) - VIR_WARN("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; - virLogPriority prio; - int ret = -1; - int count = 0; - - if (cur == NULL) - return -1; - - virSkipSpaces(&cur); - while (*cur != 0) { - unsigned int flags = 0; - prio= virParseNumber(&cur); - if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR)) - goto cleanup; - if (*cur != ':') - goto cleanup; - cur++; - if (*cur == '+') { - flags |= VIR_LOG_STACK_TRACE; - 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, flags) >= 0) - count++; - VIR_FREE(name); - virSkipSpaces(&cur); - } - ret = count; -cleanup: - if (ret == -1) - VIR_WARN("Ignoring invalid log filter setting."); - return ret; -} - - -/** - * virLogGetDefaultPriority: - * - * Returns the current logging priority level. - */ -virLogPriority -virLogGetDefaultPriority(void) -{ - return virLogDefaultPriority; -} - - -/** - * virLogGetFilters: - * - * Returns a string listing the current filters, in the format originally - * specified in the config file or environment. Caller must free the - * result. - */ -char * -virLogGetFilters(void) -{ - int i; - virBuffer filterbuf = VIR_BUFFER_INITIALIZER; - - virLogLock(); - for (i = 0; i < virLogNbFilters; i++) { - const char *sep = ":"; - if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE) - sep = ":+"; - virBufferAsprintf(&filterbuf, "%d%s%s ", - virLogFilters[i].priority, - sep, - virLogFilters[i].match); - } - virLogUnlock(); - - if (virBufferError(&filterbuf)) { - virBufferFreeAndReset(&filterbuf); - return NULL; - } - - return virBufferContentAndReset(&filterbuf); -} - - -/** - * virLogGetOutputs: - * - * Returns a string listing the current outputs, in the format originally - * specified in the config file or environment. Caller must free the - * result. - */ -char * -virLogGetOutputs(void) -{ - int i; - virBuffer outputbuf = VIR_BUFFER_INITIALIZER; - - virLogLock(); - for (i = 0; i < virLogNbOutputs; i++) { - virLogDestination dest = virLogOutputs[i].dest; - if (i) - virBufferAsprintf(&outputbuf, " "); - switch (dest) { - case VIR_LOG_TO_SYSLOG: - case VIR_LOG_TO_FILE: - virBufferAsprintf(&outputbuf, "%d:%s:%s", - virLogOutputs[i].priority, - virLogOutputString(dest), - virLogOutputs[i].name); - break; - default: - virBufferAsprintf(&outputbuf, "%d:%s", - virLogOutputs[i].priority, - virLogOutputString(dest)); - } - } - virLogUnlock(); - - if (virBufferError(&outputbuf)) { - virBufferFreeAndReset(&outputbuf); - return NULL; - } - - return virBufferContentAndReset(&outputbuf); -} - - -/** - * 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_WARN("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(debugEnv); - debugEnv = getenv("LIBVIRT_LOG_OUTPUTS"); - if (debugEnv && *debugEnv) - virLogParseOutputs(debugEnv); -} diff --git a/src/util/logging.h b/src/util/logging.h deleted file mode 100644 index 028b791..0000000 --- a/src/util/logging.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * logging.h: internal logging and debugging - * - * Copyright (C) 2006-2008, 2011-2012 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#ifndef __VIRTLOG_H_ -# define __VIRTLOG_H_ - -# include "internal.h" -# include "virbuffer.h" - -/* - * 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 - -typedef enum { - VIR_LOG_TO_STDERR = 1, - VIR_LOG_TO_SYSLOG, - VIR_LOG_TO_FILE, - VIR_LOG_TO_JOURNALD, -} virLogDestination; - -typedef enum { - VIR_LOG_FROM_FILE, - VIR_LOG_FROM_ERROR, - VIR_LOG_FROM_AUDIT, - VIR_LOG_FROM_TRACE, - VIR_LOG_FROM_LIBRARY, - - VIR_LOG_FROM_LAST, -} virLogSource; - -/* - * If configured with --enable-debug=yes then library calls - * are printed to stderr for debugging or to an appropriate channel - * defined at runtime from the libvirt daemon configuration file - */ -# ifdef ENABLE_DEBUG -# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \ - virLogMessage(src, VIR_LOG_DEBUG, filename, linenr, funcname, NULL, __VA_ARGS__) -# else -/** - * virLogEatParams: - * - * Do nothing but eat parameters. - */ -static inline void virLogEatParams(virLogSource unused, ...) -{ - /* Silence gcc */ - unused = unused; -} -# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \ - virLogEatParams(src, filename, linenr, funcname, __VA_ARGS__) -# endif /* !ENABLE_DEBUG */ - -# define VIR_INFO_INT(src, filename, linenr, funcname, ...) \ - virLogMessage(src, VIR_LOG_INFO, filename, linenr, funcname, NULL, __VA_ARGS__) -# define VIR_WARN_INT(src, filename, linenr, funcname, ...) \ - virLogMessage(src, VIR_LOG_WARN, filename, linenr, funcname, NULL, __VA_ARGS__) -# define VIR_ERROR_INT(src, filename, linenr, funcname, ...) \ - virLogMessage(src, VIR_LOG_ERROR, filename, linenr, funcname, NULL, __VA_ARGS__) - -# define VIR_DEBUG(...) \ - VIR_DEBUG_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) -# define VIR_INFO(...) \ - VIR_INFO_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) -# define VIR_WARN(...) \ - VIR_WARN_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) -# define VIR_ERROR(...) \ - VIR_ERROR_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) - - -struct _virLogMetadata { - const char *key; - const char *s; /* String value, or NULL to use "i" */ - int i; -}; - -typedef struct _virLogMetadata virLogMetadata; -typedef struct _virLogMetadata *virLogMetadataPtr; - -/** - * virLogOutputFunc: - * @src: the src for the message - * @priority: the priority for the message - * @filename: file where the message was emitted - * @linenr: line where the message was emitted - * @funcname: the function emitting the message - * @timestamp: zero terminated string with timestamp of the message - * @metadata: NULL or metadata array, terminated by an item with NULL key - * @flags: flags associated with the message - * @rawstr: the unformatted message to log, zero terminated - * @str: the message to log, preformatted and zero terminated - * @data: extra output logging data - * - * Callback function used to output messages - */ -typedef void (*virLogOutputFunc) (virLogSource src, - virLogPriority priority, - const char *filename, - int linenr, - const char *funcname, - const char *timestamp, - virLogMetadataPtr metadata, - unsigned int flags, - const char *rawstr, - const char *str, - void *data); - -/** - * virLogCloseFunc: - * @data: extra output logging data - * - * Callback function used to close a log output - */ -typedef void (*virLogCloseFunc) (void *data); - -typedef enum { - VIR_LOG_STACK_TRACE = (1 << 0), -} virLogFlags; - -extern int virLogGetNbFilters(void); -extern int virLogGetNbOutputs(void); -extern char *virLogGetFilters(void); -extern char *virLogGetOutputs(void); -extern virLogPriority virLogGetDefaultPriority(void); -extern int virLogSetDefaultPriority(virLogPriority priority); -extern void virLogSetFromEnv(void); -extern int virLogDefineFilter(const char *match, - virLogPriority priority, - unsigned int flags); -extern int virLogDefineOutput(virLogOutputFunc f, - virLogCloseFunc c, - void *data, - virLogPriority priority, - virLogDestination dest, - const char *name, - unsigned int flags); - -/* - * Internal logging API - */ - -extern void virLogLock(void); -extern void virLogUnlock(void); -extern int virLogReset(void); -extern int virLogParseDefaultPriority(const char *priority); -extern int virLogParseFilters(const char *filters); -extern int virLogParseOutputs(const char *output); -extern void virLogMessage(virLogSource src, - virLogPriority priority, - const char *filename, - int linenr, - const char *funcname, - virLogMetadataPtr metadata, - const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(7, 8); -extern void virLogVMessage(virLogSource src, - virLogPriority priority, - const char *filename, - int linenr, - const char *funcname, - virLogMetadataPtr metadata, - const char *fmt, - va_list vargs) ATTRIBUTE_FMT_PRINTF(7, 0); -extern int virLogSetBufferSize(int size); -extern void virLogEmergencyDumpAll(int signum); -#endif diff --git a/src/util/memory.c b/src/util/memory.c index b224f30..186d3b6 100644 --- a/src/util/memory.c +++ b/src/util/memory.c @@ -24,7 +24,7 @@ #include <stdlib.h> #include "memory.h" -#include "logging.h" +#include "virlog.h" #if TEST_OOM static int testMallocNext = 0; diff --git a/src/util/pci.c b/src/util/pci.c index bf46fca..7adce75 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -34,7 +34,7 @@ #include <unistd.h> #include <stdlib.h> -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "vircommand.h" #include "virterror_internal.h" diff --git a/src/util/storage_file.c b/src/util/storage_file.c index eebf59a..6c3390b 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -37,7 +37,7 @@ #include "dirname.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "c-ctype.h" #include "vircommand.h" diff --git a/src/util/sysinfo.c b/src/util/sysinfo.c index e21cbfd..5690f95 100644 --- a/src/util/sysinfo.c +++ b/src/util/sysinfo.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "sysinfo.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "vircommand.h" diff --git a/src/util/util.c b/src/util/util.c index f8ba7b4..f941dfd 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -76,7 +76,7 @@ #include "c-ctype.h" #include "dirname.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virbuffer.h" #include "util.h" #include "storage_file.h" diff --git a/src/util/uuid.c b/src/util/uuid.c index 5c3b32c..6efc7be 100644 --- a/src/util/uuid.c +++ b/src/util/uuid.c @@ -37,7 +37,7 @@ #include "internal.h" #include "util.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "virfile.h" #include "virrandom.h" diff --git a/src/util/viraudit.c b/src/util/viraudit.c index 9bdc5ed..c4e0129 100644 --- a/src/util/viraudit.c +++ b/src/util/viraudit.c @@ -28,7 +28,7 @@ #include <unistd.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "viraudit.h" #include "util.h" #include "virfile.h" diff --git a/src/util/virauth.c b/src/util/virauth.c index 6d9935d..a1bad6a 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -27,7 +27,7 @@ #include "virauth.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "virterror_internal.h" #include "configmake.h" diff --git a/src/util/virauthconfig.c b/src/util/virauthconfig.c index 49a4466..46ba040 100644 --- a/src/util/virauthconfig.c +++ b/src/util/virauthconfig.c @@ -27,7 +27,7 @@ #include "virkeyfile.h" #include "memory.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index e9fc67f..82e6613 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -41,7 +41,7 @@ #include "util.h" #include "memory.h" #include "vircgroup.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "virhash.h" #include "virhashcode.h" diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 3046658..7bed04e 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -37,7 +37,7 @@ #include "memory.h" #include "virterror_internal.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" diff --git a/src/util/virconf.c b/src/util/virconf.c index 221a1eb..c12a0bb 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -35,7 +35,7 @@ #include "virconf.h" #include "util.h" #include "c-ctype.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "virfile.h" diff --git a/src/util/virdbus.c b/src/util/virdbus.c index 2a96778..b6c6642 100644 --- a/src/util/virdbus.c +++ b/src/util/virdbus.c @@ -24,7 +24,7 @@ #include "virdbus.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "threads.h" #define VIR_FROM_THIS VIR_FROM_DBUS diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c index 4a32f49..7bb42fc 100644 --- a/src/util/virdnsmasq.c +++ b/src/util/virdnsmasq.c @@ -45,7 +45,7 @@ #include "vircommand.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_NETWORK diff --git a/src/util/virebtables.c b/src/util/virebtables.c index 8474b2a..8333c38 100644 --- a/src/util/virebtables.c +++ b/src/util/virebtables.c @@ -44,7 +44,7 @@ #include "vircommand.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "threads.h" #if HAVE_FIREWALLD diff --git a/src/util/virevent.c b/src/util/virevent.c index 7d11f85..573b4ac 100644 --- a/src/util/virevent.c +++ b/src/util/virevent.c @@ -25,7 +25,7 @@ #include "virevent.h" #include "vireventpoll.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include <stdlib.h> diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index 9fd196d..0256d83 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -32,7 +32,7 @@ #include <fcntl.h> #include "threads.h" -#include "logging.h" +#include "virlog.h" #include "vireventpoll.h" #include "memory.h" #include "util.h" diff --git a/src/util/virfile.c b/src/util/virfile.c index d77b726..30294a2 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -41,7 +41,7 @@ #include "configmake.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virhash.c b/src/util/virhash.c index 1576dd3..077abca 100644 --- a/src/util/virhash.c +++ b/src/util/virhash.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "virhash.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virhashcode.h" #include "virrandom.h" diff --git a/src/util/virhooks.c b/src/util/virhooks.c index 4a732ff..2e8ecf2 100644 --- a/src/util/virhooks.c +++ b/src/util/virhooks.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virhooks.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "virfile.h" #include "configmake.h" diff --git a/src/util/viriptables.c b/src/util/viriptables.c index 8831920..ee3e9a0 100644 --- a/src/util/viriptables.c +++ b/src/util/viriptables.c @@ -42,7 +42,7 @@ #include "vircommand.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "threads.h" #if HAVE_FIREWALLD diff --git a/src/util/virjson.c b/src/util/virjson.c index a07dd5c..18a28ba 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -26,7 +26,7 @@ #include "virjson.h" #include "memory.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #if HAVE_YAJL diff --git a/src/util/virkeyfile.c b/src/util/virkeyfile.c index 3c2ce26..b43b92d 100644 --- a/src/util/virkeyfile.c +++ b/src/util/virkeyfile.c @@ -26,7 +26,7 @@ #include <stdio.h> #include "c-ctype.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "util.h" #include "virhash.h" diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c index 99b6182..b652294 100644 --- a/src/util/virlockspace.c +++ b/src/util/virlockspace.c @@ -22,7 +22,7 @@ #include <config.h> #include "virlockspace.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "virterror_internal.h" #include "util.h" diff --git a/src/util/virlog.c b/src/util/virlog.c new file mode 100644 index 0000000..d179de2 --- /dev/null +++ b/src/util/virlog.c @@ -0,0 +1,1590 @@ +/* + * logging.c: internal logging and debugging + * + * Copyright (C) 2008, 2010-2012 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#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> +#include <signal.h> +#include <execinfo.h> +#if HAVE_SYSLOG_H +# include <syslog.h> +#endif +#include <sys/socket.h> +#if HAVE_SYS_UN_H +# include <sys/un.h> +#endif + +#include "virterror_internal.h" +#include "virlog.h" +#include "memory.h" +#include "util.h" +#include "virbuffer.h" +#include "threads.h" +#include "virfile.h" +#include "virtime.h" +#include "intprops.h" + +/* Journald output is only supported on Linux new enough to expose + * htole64. */ +#if HAVE_SYSLOG_H && defined(__linux__) && HAVE_DECL_HTOLE64 +# define USE_JOURNALD 1 +#endif + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_ENUM_DECL(virLogSource) +VIR_ENUM_IMPL(virLogSource, VIR_LOG_FROM_LAST, + "file", + "error", + "audit", + "trace", + "library"); + +/* + * A logging buffer to keep some history over logs + */ + +static int virLogSize = 64 * 1024; +static char *virLogBuffer = NULL; +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; + virLogPriority priority; + unsigned int flags; +}; +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 { + bool logVersion; + void *data; + virLogOutputFunc f; + virLogCloseFunc c; + virLogPriority priority; + virLogDestination dest; + const char *name; +}; +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); +static void virLogOutputToFd(virLogSource src, + virLogPriority priority, + const char *filename, + int linenr, + const char *funcname, + const char *timestamp, + virLogMetadataPtr metadata, + unsigned int flags, + const char *rawstr, + const char *str, + void *data); + +/* + * Logs accesses must be serialized though a mutex + */ +virMutex virLogMutex; + +void +virLogLock(void) +{ + virMutexLock(&virLogMutex); +} + + +void +virLogUnlock(void) +{ + virMutexUnlock(&virLogMutex); +} + + +static const char * +virLogOutputString(virLogDestination ldest) +{ + switch (ldest) { + case VIR_LOG_TO_STDERR: + return "stderr"; + case VIR_LOG_TO_SYSLOG: + return "syslog"; + case VIR_LOG_TO_FILE: + return "file"; + case VIR_LOG_TO_JOURNALD: + return "journald"; + } + return "unknown"; +} + + +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 +virLogOnceInit(void) +{ + const char *pbm = NULL; + + if (virMutexInit(&virLogMutex) < 0) + return -1; + + virLogLock(); + if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) { + /* + * The debug buffer is not a critical component, allow startup + * even in case of failure to allocate it in case of a + * configuration mistake. + */ + virLogSize = 64 * 1024; + if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) { + pbm = "Failed to allocate debug buffer: deactivating debug log\n"; + virLogSize = 0; + } else { + pbm = "Failed to allocate debug buffer: reduced to 64 kB\n"; + } + } + virLogLen = 0; + virLogStart = 0; + virLogEnd = 0; + virLogDefaultPriority = VIR_LOG_DEFAULT; + virLogUnlock(); + if (pbm) + VIR_WARN("%s", pbm); + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virLog) + + +/** + * virLogSetBufferSize: + * @size: size of the buffer in kilobytes or <= 0 to deactivate + * + * Dynamically set the size or deactivate the logging buffer used to keep + * a trace of all recent debug output. Note that the content of the buffer + * is lost if it gets reallocated. + * + * Return -1 in case of failure or 0 in case of success + */ +int +virLogSetBufferSize(int size) +{ + int ret = 0; + int oldsize; + char *oldLogBuffer; + const char *pbm = NULL; + + if (size < 0) + size = 0; + + if (virLogInitialize() < 0) + return -1; + + if (size * 1024 == virLogSize) + return ret; + + virLogLock(); + + oldsize = virLogSize; + oldLogBuffer = virLogBuffer; + + if (INT_MAX / 1024 <= size) { + pbm = "Requested log size of %d kB too large\n"; + ret = -1; + goto error; + } + + virLogSize = size * 1024; + if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) { + pbm = "Failed to allocate debug buffer of %d kB\n"; + virLogBuffer = oldLogBuffer; + virLogSize = oldsize; + ret = -1; + goto error; + } + VIR_FREE(oldLogBuffer); + virLogLen = 0; + virLogStart = 0; + virLogEnd = 0; + +error: + virLogUnlock(); + if (pbm) + VIR_ERROR(pbm, size); + return ret; +} + + +/** + * virLogReset: + * + * Reset the logging module to its default initial state + * + * Returns 0 if successful, and -1 in case or error + */ +int +virLogReset(void) +{ + if (virLogInitialize() < 0) + return -1; + + virLogLock(); + virLogResetFilters(); + virLogResetOutputs(); + virLogLen = 0; + virLogStart = 0; + virLogEnd = 0; + virLogDefaultPriority = VIR_LOG_DEFAULT; + virLogUnlock(); + return 0; +} + + +/* + * Store a string in the ring buffer + */ +static void +virLogStr(const char *str) +{ + int tmp; + int len; + + if ((str == NULL) || (virLogBuffer == NULL) || (virLogSize <= 0)) + return; + len = strlen(str); + if (len >= virLogSize) + return; + + /* + * copy the data and reset the end, we cycle over the end of the buffer + */ + if (virLogEnd + len >= virLogSize) { + tmp = virLogSize - virLogEnd; + memcpy(&virLogBuffer[virLogEnd], str, tmp); + memcpy(&virLogBuffer[0], &str[tmp], len - tmp); + virLogEnd = len - tmp; + } else { + memcpy(&virLogBuffer[virLogEnd], str, len); + virLogEnd += len; + } + virLogBuffer[virLogEnd] = 0; + /* + * Update the log length, and if full move the start index + */ + virLogLen += len; + if (virLogLen > virLogSize) { + tmp = virLogLen - virLogSize; + virLogLen = virLogSize; + virLogStart += tmp; + if (virLogStart >= virLogSize) + virLogStart -= virLogSize; + } +} + + +static void +virLogDumpAllFD(const char *msg, int len) +{ + int i, found = 0; + + if (len <= 0) + len = strlen(msg); + + for (i = 0; i < virLogNbOutputs;i++) { + if (virLogOutputs[i].f == virLogOutputToFd) { + int fd = (intptr_t) virLogOutputs[i].data; + + if (fd >= 0) { + ignore_value(safewrite(fd, msg, len)); + found = 1; + } + } + } + if (!found) + ignore_value(safewrite(STDERR_FILENO, msg, len)); +} + + +/** + * virLogEmergencyDumpAll: + * @signum: the signal number + * + * Emergency function called, possibly from a signal handler. + * It need to output the debug ring buffer through the log + * output which are safe to use from a signal handler. + * In case none is found it is emitted to standard error. + */ +void +virLogEmergencyDumpAll(int signum) +{ + int len; + int oldLogStart, oldLogLen; + + switch (signum) { +#ifdef SIGFPE + case SIGFPE: + virLogDumpAllFD("Caught signal Floating-point exception", -1); + break; +#endif +#ifdef SIGSEGV + case SIGSEGV: + virLogDumpAllFD("Caught Segmentation violation", -1); + break; +#endif +#ifdef SIGILL + case SIGILL: + virLogDumpAllFD("Caught illegal instruction", -1); + break; +#endif +#ifdef SIGABRT + case SIGABRT: + virLogDumpAllFD("Caught abort signal", -1); + break; +#endif +#ifdef SIGBUS + case SIGBUS: + virLogDumpAllFD("Caught bus error", -1); + break; +#endif +#ifdef SIGUSR2 + case SIGUSR2: + virLogDumpAllFD("Caught User-defined signal 2", -1); + break; +#endif + default: + virLogDumpAllFD("Caught unexpected signal", -1); + break; + } + if ((virLogBuffer == NULL) || (virLogSize <= 0)) { + virLogDumpAllFD(" internal log buffer deactivated\n", -1); + return; + } + + virLogDumpAllFD(" dumping internal log buffer:\n", -1); + virLogDumpAllFD("\n\n ====== start of log =====\n\n", -1); + + /* + * Since we can't lock the buffer safely from a signal handler + * we mark it as empty in case of concurrent access, and proceed + * with the data, at worse we will output something a bit weird + * if another thread start logging messages at the same time. + * Note that virLogStr() uses virLogEnd for the computations and + * writes to the buffer and only then updates virLogLen and virLogStart + * so it's best to reset it first. + */ + oldLogStart = virLogStart; + oldLogLen = virLogLen; + virLogEnd = 0; + virLogLen = 0; + virLogStart = 0; + + while (oldLogLen > 0) { + if (oldLogStart + oldLogLen < virLogSize) { + virLogBuffer[oldLogStart + oldLogLen] = 0; + virLogDumpAllFD(&virLogBuffer[oldLogStart], oldLogLen); + oldLogStart += oldLogLen; + oldLogLen = 0; + } else { + len = virLogSize - oldLogStart; + virLogBuffer[virLogSize] = 0; + virLogDumpAllFD(&virLogBuffer[oldLogStart], len); + oldLogLen -= len; + oldLogStart = 0; + } + } + virLogDumpAllFD("\n\n ====== end of log =====\n\n", -1); +} + + +/** + * 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(virLogPriority priority) +{ + if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) { + VIR_WARN("Ignoring invalid log level setting."); + return -1; + } + if (virLogInitialize() < 0) + return -1; + + 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 flags, see virLogFilterFlags enum + * + * 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, + virLogPriority priority, + unsigned int flags) +{ + int i; + char *mdup = NULL; + + virCheckFlags(VIR_LOG_STACK_TRACE, -1); + + 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 (mdup == 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; + virLogFilters[i].flags = flags; + 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, + unsigned int *flags) +{ + int ret = 0; + int i; + + virLogLock(); + for (i = 0;i < virLogNbFilters;i++) { + if (strstr(input, virLogFilters[i].match)) { + ret = virLogFilters[i].priority; + *flags = virLogFilters[i].flags; + 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].name); + } + VIR_FREE(virLogOutputs); + i = virLogNbOutputs; + virLogNbOutputs = 0; + return i; +} + + +/** + * virLogDefineOutput: + * @f: the function to call to output a message + * @c: 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 + * @dest: where to send output of this priority + * @name: optional name data associated with an output + * @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, + virLogPriority priority, + virLogDestination dest, + const char *name, + unsigned int flags) +{ + int ret = -1; + char *ndup = NULL; + + virCheckFlags(0, -1); + + if (f == NULL) + return -1; + + if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) { + if (name == NULL) + return -1; + ndup = strdup(name); + if (ndup == NULL) + return -1; + } + + virLogLock(); + if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) { + VIR_FREE(ndup); + goto cleanup; + } + ret = virLogNbOutputs++; + virLogOutputs[ret].logVersion = true; + virLogOutputs[ret].f = f; + virLogOutputs[ret].c = c; + virLogOutputs[ret].data = data; + virLogOutputs[ret].priority = priority; + virLogOutputs[ret].dest = dest; + virLogOutputs[ret].name = ndup; +cleanup: + virLogUnlock(); + return ret; +} + + +static int +virLogFormatString(char **msg, + int linenr, + const char *funcname, + virLogPriority priority, + const char *str) +{ + int ret; + + /* + * Be careful when changing the following log message formatting, we rely + * on it when stripping libvirt debug messages from qemu log files. So when + * changing this, you might also need to change the code there. + * virLogFormatString() function name is mentioned there so it's sufficient + * to just grep for it to find the right place. + */ + if ((funcname != NULL)) { + ret = virAsprintf(msg, "%d: %s : %s:%d : %s\n", + virThreadSelfID(), virLogPriorityString(priority), + funcname, linenr, str); + } else { + ret = virAsprintf(msg, "%d: %s : %s\n", + virThreadSelfID(), virLogPriorityString(priority), + str); + } + return ret; +} + + +static int +virLogVersionString(const char **rawmsg, + char **msg) +{ +#ifdef PACKAGER_VERSION +# ifdef PACKAGER +# define LOG_VERSION_STRING \ + "libvirt version: " VERSION ", package: " PACKAGER_VERSION " (" PACKAGER ")" +# else +# define LOG_VERSION_STRING \ + "libvirt version: " VERSION ", package: " PACKAGER_VERSION +# endif +#else +# define LOG_VERSION_STRING \ + "libvirt version: " VERSION +#endif + + *rawmsg = LOG_VERSION_STRING; + return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, LOG_VERSION_STRING); +} + + +/** + * virLogMessage: + * @source: where is that message coming from + * @priority: the priority level + * @filename: file where the message was emitted + * @linenr: line where the message was emitted + * @funcname: the function emitting the (debug) message + * @metadata: NULL or metadata array, terminated by an item with NULL key + * @fmt: the string format + * @...: the arguments + * + * Call the libvirt logger with some information. Based on the configuration + * the message may be stored, sent to output or just discarded + */ +void +virLogMessage(virLogSource source, + virLogPriority priority, + const char *filename, + int linenr, + const char *funcname, + virLogMetadataPtr metadata, + const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + virLogVMessage(source, priority, + filename, linenr, funcname, + metadata, fmt, ap); + va_end(ap); +} + + +/** + * virLogVMessage: + * @source: where is that message coming from + * @priority: the priority level + * @filename: file where the message was emitted + * @linenr: line where the message was emitted + * @funcname: the function emitting the (debug) message + * @metadata: NULL or metadata array, terminated by an item with NULL key + * @fmt: the string format + * @vargs: format args + * + * Call the libvirt logger with some information. Based on the configuration + * the message may be stored, sent to output or just discarded + */ +void +virLogVMessage(virLogSource source, + virLogPriority priority, + const char *filename, + int linenr, + const char *funcname, + virLogMetadataPtr metadata, + const char *fmt, + va_list vargs) +{ + static bool logVersionStderr = true; + char *str = NULL; + char *msg = NULL; + char timestamp[VIR_TIME_STRING_BUFLEN]; + int fprio, i, ret; + int saved_errno = errno; + int emit = 1; + unsigned int filterflags = 0; + + if (virLogInitialize() < 0) + return; + + if (fmt == NULL) + goto cleanup; + + /* + * check against list of specific logging patterns + */ + fprio = virLogFiltersCheck(filename, &filterflags); + if (fprio == 0) { + if (priority < virLogDefaultPriority) + emit = 0; + } else if (priority < fprio) { + emit = 0; + } + + if ((emit == 0) && ((virLogBuffer == NULL) || (virLogSize <= 0))) + goto cleanup; + + /* + * serialize the error message, add level and timestamp + */ + if (virVasprintf(&str, fmt, vargs) < 0) { + goto cleanup; + } + + ret = virLogFormatString(&msg, linenr, funcname, priority, str); + if (ret < 0) + goto cleanup; + + if (virTimeStringNowRaw(timestamp) < 0) + timestamp[0] = '\0'; + + /* + * Log based on defaults, first store in the history buffer, + * then if emit 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. + */ + virLogLock(); + virLogStr(timestamp); + virLogStr(msg); + virLogUnlock(); + if (emit == 0) + goto cleanup; + + virLogLock(); + for (i = 0; i < virLogNbOutputs; i++) { + if (priority >= virLogOutputs[i].priority) { + if (virLogOutputs[i].logVersion) { + const char *rawver; + char *ver = NULL; + if (virLogVersionString(&rawver, &ver) >= 0) + virLogOutputs[i].f(VIR_LOG_FROM_FILE, VIR_LOG_INFO, + __FILE__, __LINE__, __func__, + timestamp, NULL, 0, rawver, ver, + virLogOutputs[i].data); + VIR_FREE(ver); + virLogOutputs[i].logVersion = false; + } + virLogOutputs[i].f(source, priority, + filename, linenr, funcname, + timestamp, metadata, filterflags, + str, msg, virLogOutputs[i].data); + } + } + if ((virLogNbOutputs == 0) && (source != VIR_LOG_FROM_ERROR)) { + if (logVersionStderr) { + const char *rawver; + char *ver = NULL; + if (virLogVersionString(&rawver, &ver) >= 0) + virLogOutputToFd(VIR_LOG_FROM_FILE, VIR_LOG_INFO, + __FILE__, __LINE__, __func__, + timestamp, NULL, 0, rawver, ver, + (void *) STDERR_FILENO); + VIR_FREE(ver); + logVersionStderr = false; + } + virLogOutputToFd(source, priority, + filename, linenr, funcname, + timestamp, metadata, filterflags, + str, msg, (void *) STDERR_FILENO); + } + virLogUnlock(); + +cleanup: + VIR_FREE(str); + VIR_FREE(msg); + errno = saved_errno; +} + + +static void +virLogStackTraceToFd(int fd) +{ + void *array[100]; + int size; + static bool doneWarning = false; + const char *msg = "Stack trace not available on this platform\n"; + +#define STRIP_DEPTH 3 + size = backtrace(array, ARRAY_CARDINALITY(array)); + if (size) { + backtrace_symbols_fd(array + STRIP_DEPTH, size - STRIP_DEPTH, fd); + ignore_value(safewrite(fd, "\n", 1)); + } else if (!doneWarning) { + ignore_value(safewrite(fd, msg, strlen(msg))); + doneWarning = true; + } +#undef STRIP_DEPTH +} + +static void +virLogOutputToFd(virLogSource source ATTRIBUTE_UNUSED, + virLogPriority priority ATTRIBUTE_UNUSED, + const char *filename ATTRIBUTE_UNUSED, + int linenr ATTRIBUTE_UNUSED, + const char *funcname ATTRIBUTE_UNUSED, + const char *timestamp, + virLogMetadataPtr metadata ATTRIBUTE_UNUSED, + unsigned int flags, + const char *rawstr ATTRIBUTE_UNUSED, + const char *str, + void *data) +{ + int fd = (intptr_t) data; + char *msg; + + if (fd < 0) + return; + + if (virAsprintf(&msg, "%s: %s", timestamp, str) < 0) + return; + + ignore_value(safewrite(fd, msg, strlen(msg))); + VIR_FREE(msg); + + if (flags & VIR_LOG_STACK_TRACE) + virLogStackTraceToFd(fd); +} + + +static void +virLogCloseFd(void *data) +{ + int fd = (intptr_t) data; + + VIR_LOG_CLOSE(fd); +} + + +static int +virLogAddOutputToStderr(virLogPriority priority) +{ + if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority, + VIR_LOG_TO_STDERR, NULL, 0) < 0) + return -1; + return 0; +} + + +static int +virLogAddOutputToFile(virLogPriority priority, + const char *file) +{ + int fd; + + fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd < 0) + return -1; + if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd, + (void *)(intptr_t)fd, + priority, VIR_LOG_TO_FILE, file, 0) < 0) { + VIR_FORCE_CLOSE(fd); + return -1; + } + return 0; +} + + +#if HAVE_SYSLOG_H +static int +virLogPrioritySyslog(virLogPriority priority) +{ + switch (priority) { + case VIR_LOG_DEBUG: + return LOG_DEBUG; + case VIR_LOG_INFO: + return LOG_INFO; + case VIR_LOG_WARN: + return LOG_WARNING; + case VIR_LOG_ERROR: + return LOG_ERR; + default: + return LOG_ERR; + } +} + + +static void +virLogOutputToSyslog(virLogSource source ATTRIBUTE_UNUSED, + virLogPriority priority, + const char *filename ATTRIBUTE_UNUSED, + int linenr ATTRIBUTE_UNUSED, + const char *funcname ATTRIBUTE_UNUSED, + const char *timestamp ATTRIBUTE_UNUSED, + virLogMetadataPtr metadata ATTRIBUTE_UNUSED, + unsigned int flags, + const char *rawstr ATTRIBUTE_UNUSED, + const char *str, + void *data ATTRIBUTE_UNUSED) +{ + virCheckFlags(VIR_LOG_STACK_TRACE,); + + syslog(virLogPrioritySyslog(priority), "%s", str); +} + +static char *current_ident = NULL; + + +static void +virLogCloseSyslog(void *data ATTRIBUTE_UNUSED) +{ + closelog(); + VIR_FREE(current_ident); +} + + +static int +virLogAddOutputToSyslog(virLogPriority 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, VIR_LOG_TO_SYSLOG, ident, 0) < 0) { + closelog(); + VIR_FREE(current_ident); + return -1; + } + return 0; +} + + +# if USE_JOURNALD +# define IOVEC_SET(iov, data, size) \ + do { \ + struct iovec *_i = &(iov); \ + _i->iov_base = (void*)(data); \ + _i->iov_len = (size); \ + } while (0) + +# define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str)) + +/* Used for conversion of numbers to strings, and for length of binary data */ +# define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t))) + +struct journalState +{ + struct iovec *iov, *iov_end; + char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE]; +}; + +static void +journalAddString(struct journalState *state, const char *field, + const char *value) +{ + static const char newline = '\n', equals = '='; + + if (strchr(value, '\n') != NULL) { + uint64_t nstr; + + /* If 'str' contains a newline, then we must + * encode the string length, since we can't + * rely on the newline for the field separator + */ + if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end) + return; /* Silently drop */ + nstr = htole64(strlen(value)); + memcpy(state->bufs[0], &nstr, sizeof(nstr)); + + IOVEC_SET_STRING(state->iov[0], field); + IOVEC_SET(state->iov[1], &newline, sizeof(newline)); + IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr)); + state->bufs++; + state->iov += 3; + } else { + if (state->iov_end - state->iov < 4) + return; /* Silently drop */ + IOVEC_SET_STRING(state->iov[0], field); + IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals)); + state->iov += 2; + } + IOVEC_SET_STRING(state->iov[0], value); + IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline)); + state->iov += 2; +} + +static void +journalAddInt(struct journalState *state, const char *field, int value) +{ + static const char newline = '\n', equals = '='; + + char *num; + + if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end) + return; /* Silently drop */ + + num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value); + + IOVEC_SET_STRING(state->iov[0], field); + IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals)); + IOVEC_SET_STRING(state->iov[2], num); + IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline)); + state->bufs++; + state->iov += 4; +} + +static int journalfd = -1; + +static void +virLogOutputToJournald(virLogSource source, + virLogPriority priority, + const char *filename, + int linenr, + const char *funcname, + const char *timestamp ATTRIBUTE_UNUSED, + virLogMetadataPtr metadata ATTRIBUTE_UNUSED, + unsigned int flags, + const char *rawstr, + const char *str ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + virCheckFlags(VIR_LOG_STACK_TRACE,); + int buffd = -1; + struct msghdr mh; + struct sockaddr_un sa; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control; + struct cmsghdr *cmsg; + /* We use /dev/shm instead of /tmp here, since we want this to + * be a tmpfs, and one that is available from early boot on + * and where unprivileged users can create files. */ + char path[] = "/dev/shm/journal.XXXXXX"; + +# define NUM_FIELDS 6 + struct iovec iov[NUM_FIELDS * 5]; + char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE]; + struct journalState state; + + state.iov = iov; + state.iov_end = iov + ARRAY_CARDINALITY(iov); + state.bufs = iov_bufs; + state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs); + + journalAddString(&state ,"MESSAGE", rawstr); + journalAddInt(&state, "PRIORITY", priority); + journalAddString(&state, "LIBVIRT_SOURCE", + virLogSourceTypeToString(source)); + journalAddString(&state, "CODE_FILE", filename); + journalAddInt(&state, "CODE_LINE", linenr); + journalAddString(&state, "CODE_FUNC", funcname); + + memset(&sa, 0, sizeof(sa)); + sa.sun_family = AF_UNIX; + if (!virStrcpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path))) + return; + + memset(&mh, 0, sizeof(mh)); + mh.msg_name = &sa; + mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path); + mh.msg_iov = iov; + mh.msg_iovlen = state.iov - iov; + + if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0) + return; + + if (errno != EMSGSIZE && errno != ENOBUFS) + return; + + /* Message was too large, so dump to temporary file + * and pass an FD to the journal + */ + + /* NB: mkostemp is not declared async signal safe by + * POSIX, but this is Linux only code and the GLibc + * impl is safe enough, only using open() and inline + * asm to read a timestamp (falling back to gettimeofday + * on some arches + */ + if ((buffd = mkostemp(path, O_CLOEXEC|O_RDWR)) < 0) + return; + + if (unlink(path) < 0) + goto cleanup; + + if (writev(buffd, iov, state.iov - iov) < 0) + goto cleanup; + + mh.msg_iov = NULL; + mh.msg_iovlen = 0; + + memset(&control, 0, sizeof(control)); + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &buffd, sizeof(int)); + + mh.msg_controllen = cmsg->cmsg_len; + + sendmsg(journalfd, &mh, MSG_NOSIGNAL); + +cleanup: + VIR_LOG_CLOSE(buffd); +} + + +static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED) +{ + VIR_LOG_CLOSE(journalfd); +} + + +static int virLogAddOutputToJournald(int priority) +{ + if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) + return -1; + if (virSetInherit(journalfd, false) < 0) { + VIR_LOG_CLOSE(journalfd); + return -1; + } + if (virLogDefineOutput(virLogOutputToJournald, virLogCloseJournald, NULL, + priority, VIR_LOG_TO_JOURNALD, NULL, 0) < 0) { + return -1; + } + return 0; +} +# endif /* USE_JOURNALD */ +#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; + char *abspath; + virLogPriority prio; + int ret = -1; + int count = 0; + + if (cur == NULL) + return -1; + + VIR_DEBUG("outputs=%s", outputs); + + 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 (virFileAbsPath(name, &abspath) < 0) { + VIR_FREE(name); + return -1; /* skip warning here because setting was fine */ + } + if (virLogAddOutputToFile(prio, abspath) == 0) + count++; + VIR_FREE(name); + VIR_FREE(abspath); + } else if (STREQLEN(cur, "journald", 8)) { + cur += 8; +#if USE_JOURNALD + if (virLogAddOutputToJournald(prio) == 0) + count++; +#endif /* USE_JOURNALD */ + } else { + goto cleanup; + } + virSkipSpaces(&cur); + } + ret = count; +cleanup: + if (ret == -1) + VIR_WARN("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; + virLogPriority prio; + int ret = -1; + int count = 0; + + if (cur == NULL) + return -1; + + virSkipSpaces(&cur); + while (*cur != 0) { + unsigned int flags = 0; + prio= virParseNumber(&cur); + if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR)) + goto cleanup; + if (*cur != ':') + goto cleanup; + cur++; + if (*cur == '+') { + flags |= VIR_LOG_STACK_TRACE; + 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, flags) >= 0) + count++; + VIR_FREE(name); + virSkipSpaces(&cur); + } + ret = count; +cleanup: + if (ret == -1) + VIR_WARN("Ignoring invalid log filter setting."); + return ret; +} + + +/** + * virLogGetDefaultPriority: + * + * Returns the current logging priority level. + */ +virLogPriority +virLogGetDefaultPriority(void) +{ + return virLogDefaultPriority; +} + + +/** + * virLogGetFilters: + * + * Returns a string listing the current filters, in the format originally + * specified in the config file or environment. Caller must free the + * result. + */ +char * +virLogGetFilters(void) +{ + int i; + virBuffer filterbuf = VIR_BUFFER_INITIALIZER; + + virLogLock(); + for (i = 0; i < virLogNbFilters; i++) { + const char *sep = ":"; + if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE) + sep = ":+"; + virBufferAsprintf(&filterbuf, "%d%s%s ", + virLogFilters[i].priority, + sep, + virLogFilters[i].match); + } + virLogUnlock(); + + if (virBufferError(&filterbuf)) { + virBufferFreeAndReset(&filterbuf); + return NULL; + } + + return virBufferContentAndReset(&filterbuf); +} + + +/** + * virLogGetOutputs: + * + * Returns a string listing the current outputs, in the format originally + * specified in the config file or environment. Caller must free the + * result. + */ +char * +virLogGetOutputs(void) +{ + int i; + virBuffer outputbuf = VIR_BUFFER_INITIALIZER; + + virLogLock(); + for (i = 0; i < virLogNbOutputs; i++) { + virLogDestination dest = virLogOutputs[i].dest; + if (i) + virBufferAsprintf(&outputbuf, " "); + switch (dest) { + case VIR_LOG_TO_SYSLOG: + case VIR_LOG_TO_FILE: + virBufferAsprintf(&outputbuf, "%d:%s:%s", + virLogOutputs[i].priority, + virLogOutputString(dest), + virLogOutputs[i].name); + break; + default: + virBufferAsprintf(&outputbuf, "%d:%s", + virLogOutputs[i].priority, + virLogOutputString(dest)); + } + } + virLogUnlock(); + + if (virBufferError(&outputbuf)) { + virBufferFreeAndReset(&outputbuf); + return NULL; + } + + return virBufferContentAndReset(&outputbuf); +} + + +/** + * 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_WARN("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(debugEnv); + debugEnv = getenv("LIBVIRT_LOG_OUTPUTS"); + if (debugEnv && *debugEnv) + virLogParseOutputs(debugEnv); +} diff --git a/src/util/virlog.h b/src/util/virlog.h new file mode 100644 index 0000000..028b791 --- /dev/null +++ b/src/util/virlog.h @@ -0,0 +1,191 @@ +/* + * logging.h: internal logging and debugging + * + * Copyright (C) 2006-2008, 2011-2012 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __VIRTLOG_H_ +# define __VIRTLOG_H_ + +# include "internal.h" +# include "virbuffer.h" + +/* + * 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 + +typedef enum { + VIR_LOG_TO_STDERR = 1, + VIR_LOG_TO_SYSLOG, + VIR_LOG_TO_FILE, + VIR_LOG_TO_JOURNALD, +} virLogDestination; + +typedef enum { + VIR_LOG_FROM_FILE, + VIR_LOG_FROM_ERROR, + VIR_LOG_FROM_AUDIT, + VIR_LOG_FROM_TRACE, + VIR_LOG_FROM_LIBRARY, + + VIR_LOG_FROM_LAST, +} virLogSource; + +/* + * If configured with --enable-debug=yes then library calls + * are printed to stderr for debugging or to an appropriate channel + * defined at runtime from the libvirt daemon configuration file + */ +# ifdef ENABLE_DEBUG +# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \ + virLogMessage(src, VIR_LOG_DEBUG, filename, linenr, funcname, NULL, __VA_ARGS__) +# else +/** + * virLogEatParams: + * + * Do nothing but eat parameters. + */ +static inline void virLogEatParams(virLogSource unused, ...) +{ + /* Silence gcc */ + unused = unused; +} +# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \ + virLogEatParams(src, filename, linenr, funcname, __VA_ARGS__) +# endif /* !ENABLE_DEBUG */ + +# define VIR_INFO_INT(src, filename, linenr, funcname, ...) \ + virLogMessage(src, VIR_LOG_INFO, filename, linenr, funcname, NULL, __VA_ARGS__) +# define VIR_WARN_INT(src, filename, linenr, funcname, ...) \ + virLogMessage(src, VIR_LOG_WARN, filename, linenr, funcname, NULL, __VA_ARGS__) +# define VIR_ERROR_INT(src, filename, linenr, funcname, ...) \ + virLogMessage(src, VIR_LOG_ERROR, filename, linenr, funcname, NULL, __VA_ARGS__) + +# define VIR_DEBUG(...) \ + VIR_DEBUG_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) +# define VIR_INFO(...) \ + VIR_INFO_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) +# define VIR_WARN(...) \ + VIR_WARN_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) +# define VIR_ERROR(...) \ + VIR_ERROR_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__) + + +struct _virLogMetadata { + const char *key; + const char *s; /* String value, or NULL to use "i" */ + int i; +}; + +typedef struct _virLogMetadata virLogMetadata; +typedef struct _virLogMetadata *virLogMetadataPtr; + +/** + * virLogOutputFunc: + * @src: the src for the message + * @priority: the priority for the message + * @filename: file where the message was emitted + * @linenr: line where the message was emitted + * @funcname: the function emitting the message + * @timestamp: zero terminated string with timestamp of the message + * @metadata: NULL or metadata array, terminated by an item with NULL key + * @flags: flags associated with the message + * @rawstr: the unformatted message to log, zero terminated + * @str: the message to log, preformatted and zero terminated + * @data: extra output logging data + * + * Callback function used to output messages + */ +typedef void (*virLogOutputFunc) (virLogSource src, + virLogPriority priority, + const char *filename, + int linenr, + const char *funcname, + const char *timestamp, + virLogMetadataPtr metadata, + unsigned int flags, + const char *rawstr, + const char *str, + void *data); + +/** + * virLogCloseFunc: + * @data: extra output logging data + * + * Callback function used to close a log output + */ +typedef void (*virLogCloseFunc) (void *data); + +typedef enum { + VIR_LOG_STACK_TRACE = (1 << 0), +} virLogFlags; + +extern int virLogGetNbFilters(void); +extern int virLogGetNbOutputs(void); +extern char *virLogGetFilters(void); +extern char *virLogGetOutputs(void); +extern virLogPriority virLogGetDefaultPriority(void); +extern int virLogSetDefaultPriority(virLogPriority priority); +extern void virLogSetFromEnv(void); +extern int virLogDefineFilter(const char *match, + virLogPriority priority, + unsigned int flags); +extern int virLogDefineOutput(virLogOutputFunc f, + virLogCloseFunc c, + void *data, + virLogPriority priority, + virLogDestination dest, + const char *name, + unsigned int flags); + +/* + * Internal logging API + */ + +extern void virLogLock(void); +extern void virLogUnlock(void); +extern int virLogReset(void); +extern int virLogParseDefaultPriority(const char *priority); +extern int virLogParseFilters(const char *filters); +extern int virLogParseOutputs(const char *output); +extern void virLogMessage(virLogSource src, + virLogPriority priority, + const char *filename, + int linenr, + const char *funcname, + virLogMetadataPtr metadata, + const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(7, 8); +extern void virLogVMessage(virLogSource src, + virLogPriority priority, + const char *filename, + int linenr, + const char *funcname, + virLogMetadataPtr metadata, + const char *fmt, + va_list vargs) ATTRIBUTE_FMT_PRINTF(7, 0); +extern int virLogSetBufferSize(int size); +extern void virLogEmergencyDumpAll(int signum); +#endif diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index e98a2ca..a1d1c12 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -29,7 +29,7 @@ #include "vircommand.h" #include "memory.h" #include "pci.h" -#include "logging.h" +#include "virlog.h" #include <sys/ioctl.h> #include <net/if.h> diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 657c484..8d2574c 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -57,7 +57,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST, # endif # include "memory.h" -# include "logging.h" +# include "virlog.h" # include "uuid.h" # include "virfile.h" # include "virnetlink.h" diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 0eadd6c..644e9a4 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -31,7 +31,7 @@ #include "virfile.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include <sys/ioctl.h> diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c index 3261337..630b7c9 100644 --- a/src/util/virnetdevveth.c +++ b/src/util/virnetdevveth.c @@ -27,7 +27,7 @@ #include "virnetdevveth.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "vircommand.h" #include "virterror_internal.h" diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index ac7aa5f..834b9b9 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -53,7 +53,7 @@ VIR_ENUM_IMPL(virNetDevVPortProfileOp, VIR_NETDEV_VPORT_PROFILE_OP_LAST, # include "virnetlink.h" # include "virfile.h" -# include "logging.h" +# include "virlog.h" # include "virnetdev.h" # define MICROSEC_PER_SEC (1000 * 1000) diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 8a8bfae..830e9b9 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -36,7 +36,7 @@ #include <sys/socket.h> #include "virnetlink.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "threads.h" #include "virmacaddr.h" diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c index a34ca6a..e37a2d6 100644 --- a/src/util/virnodesuspend.c +++ b/src/util/virnodesuspend.c @@ -27,7 +27,7 @@ #include "datatypes.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virobject.c b/src/util/virobject.c index 101507f..aa80cab 100644 --- a/src/util/virobject.c +++ b/src/util/virobject.c @@ -26,7 +26,7 @@ #include "memory.h" #include "viratomic.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virpidfile.c b/src/util/virpidfile.c index 90a79c5..6ec9760 100644 --- a/src/util/virpidfile.c +++ b/src/util/virpidfile.c @@ -32,7 +32,7 @@ #include "memory.h" #include "util.h" #include "intprops.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "c-ctype.h" #include "areadlink.h" diff --git a/src/util/virprocess.c b/src/util/virprocess.c index f8a8a49..3c0ed8a 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -29,7 +29,7 @@ #include "virprocess.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virrandom.c b/src/util/virrandom.c index 002f655..c24bf3b 100644 --- a/src/util/virrandom.c +++ b/src/util/virrandom.c @@ -31,7 +31,7 @@ #include "count-one-bits.h" #include "util.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virterror.c b/src/util/virterror.c index 1142c40..6e3301b 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -29,7 +29,7 @@ #include "virterror_internal.h" #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "threads.h" #include "util.h" diff --git a/src/util/virusb.c b/src/util/virusb.c index b9c81ed..ebc1af5 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -32,7 +32,7 @@ #include <unistd.h> #include "virusb.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" #include "util.h" #include "virterror_internal.h" diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index 9ddc89c..3194b7c 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -32,7 +32,7 @@ #include "internal.h" #include "memory.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "vbox_MSCOMGlue.h" diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 63470ae..5f70283 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -39,7 +39,7 @@ #include "internal.h" #include "memory.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_VBOX diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index 56726ed..cd29e19 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -34,7 +34,7 @@ #include "internal.h" #include "datatypes.h" -#include "logging.h" +#include "virlog.h" #include "vbox_driver.h" #include "vbox_glue.h" #include "virterror_internal.h" diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index e0f9b6f..847af35 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -52,7 +52,7 @@ #include "uuid.h" #include "memory.h" #include "nodeinfo.h" -#include "logging.h" +#include "virlog.h" #include "vbox_driver.h" #include "configmake.h" #include "virfile.h" diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 0d34453..e74e9ed 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -29,7 +29,7 @@ #include "virterror_internal.h" #include "virconf.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "vmx.h" #include "viruri.h" diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index d9174b6..c281c00 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -40,7 +40,7 @@ #include <xen/dom0_ops.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "xen_driver.h" diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 1aa2b73..b094313 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -64,7 +64,7 @@ #include <xen/sched.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "driver.h" #include "util.h" diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index bcafdd0..073663f 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -36,7 +36,7 @@ #include "domain_conf.h" #include "xen_inotify.h" #include "xend_internal.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "virfile.h" diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 9407e95..0364f84 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -30,7 +30,7 @@ #include <errno.h> #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "datatypes.h" #include "xend_internal.h" #include "driver.h" diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 2cd4b95..fc7b581 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -47,7 +47,7 @@ #include "uuid.h" #include "util.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "count-one-bits.h" #define VIR_FROM_THIS VIR_FROM_XENXM diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index 8a0af62..4cc82d8 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -45,7 +45,7 @@ #include "datatypes.h" #include "driver.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "uuid.h" #include "xen_driver.h" #include "xs_internal.h" diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index dbdb22d..6f51100 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -33,7 +33,7 @@ #include "uuid.h" #include "memory.h" #include "virbuffer.h" -#include "logging.h" +#include "virlog.h" #include "viruri.h" #include "xenapi_driver_private.h" #include "xenapi_utils.h" diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index ed0c9e1..2aa384d 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -32,7 +32,7 @@ #include "memory.h" #include "verify.h" #include "uuid.h" -#include "logging.h" +#include "virlog.h" #include "count-one-bits.h" #include "xenxs_private.h" #include "xen_sxpr.h" diff --git a/tests/eventtest.c b/tests/eventtest.c index bc8d443..cd36a2d 100644 --- a/tests/eventtest.c +++ b/tests/eventtest.c @@ -29,7 +29,7 @@ #include "testutils.h" #include "internal.h" #include "threads.h" -#include "logging.h" +#include "virlog.h" #include "util.h" #include "vireventpoll.h" diff --git a/tests/libvirtdconftest.c b/tests/libvirtdconftest.c index c2b02a6..0365ade 100644 --- a/tests/libvirtdconftest.c +++ b/tests/libvirtdconftest.c @@ -27,7 +27,7 @@ #include "util.h" #include "c-ctype.h" #include "virterror_internal.h" -#include "logging.h" +#include "virlog.h" #include "virconf.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index b55d867..e4194de 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -31,7 +31,7 @@ #include "rpc/virnetsocket.h" #include "memory.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/tests/securityselinuxtest.c b/tests/securityselinuxtest.c index 8bcf3a1..c021480 100644 --- a/tests/securityselinuxtest.c +++ b/tests/securityselinuxtest.c @@ -32,7 +32,7 @@ #include "testutils.h" #include "memory.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #include "virterror_internal.h" #include "security/security_manager.h" diff --git a/tests/sockettest.c b/tests/sockettest.c index 2f85307..c6a175f 100644 --- a/tests/sockettest.c +++ b/tests/sockettest.c @@ -27,7 +27,7 @@ #include "virsocketaddr.h" #include "testutils.h" -#include "logging.h" +#include "virlog.h" #include "memory.h" static void testQuietError(void *userData ATTRIBUTE_UNUSED, diff --git a/tests/testutils.c b/tests/testutils.c index 1315cb5..96e24d4 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -44,7 +44,7 @@ #include "threads.h" #include "virterror_internal.h" #include "virbuffer.h" -#include "logging.h" +#include "virlog.h" #include "vircommand.h" #include "virrandom.h" #include "dirname.h" diff --git a/tests/virauthconfigtest.c b/tests/virauthconfigtest.c index 4d37af6..74cc187 100644 --- a/tests/virauthconfigtest.c +++ b/tests/virauthconfigtest.c @@ -27,7 +27,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virauthconfig.h" diff --git a/tests/virdrivermoduletest.c b/tests/virdrivermoduletest.c index 53a772e..440ee8e 100644 --- a/tests/virdrivermoduletest.c +++ b/tests/virdrivermoduletest.c @@ -24,7 +24,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "driver.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/tests/virhashtest.c b/tests/virhashtest.c index 721e877..7de16d0 100644 --- a/tests/virhashtest.c +++ b/tests/virhashtest.c @@ -11,7 +11,7 @@ #include "testutils.h" #include "memory.h" #include "util.h" -#include "logging.h" +#include "virlog.h" #define testError(...) \ diff --git a/tests/virkeyfiletest.c b/tests/virkeyfiletest.c index 3667c8c..c6aca86 100644 --- a/tests/virkeyfiletest.c +++ b/tests/virkeyfiletest.c @@ -27,7 +27,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virkeyfile.h" diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c index ee58f95..c95f5d8 100644 --- a/tests/virlockspacetest.c +++ b/tests/virlockspacetest.c @@ -28,7 +28,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virlockspace.h" diff --git a/tests/virnetmessagetest.c b/tests/virnetmessagetest.c index eff8ea7..c20f5e6 100644 --- a/tests/virnetmessagetest.c +++ b/tests/virnetmessagetest.c @@ -27,7 +27,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "rpc/virnetmessage.h" diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index e31f19a..ba281e9 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -31,7 +31,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "rpc/virnetsocket.h" diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c index d421feb..0236659 100644 --- a/tests/virnettlscontexttest.c +++ b/tests/virnettlscontexttest.c @@ -30,7 +30,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virfile.h" #include "vircommand.h" #include "virsocketaddr.h" diff --git a/tests/virstringtest.c b/tests/virstringtest.c index 7e726c6..27e490f 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -26,7 +26,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virstring.h" diff --git a/tests/virtimetest.c b/tests/virtimetest.c index dca4efb..c8e9a2e 100644 --- a/tests/virtimetest.c +++ b/tests/virtimetest.c @@ -27,7 +27,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "virtime.h" diff --git a/tests/viruritest.c b/tests/viruritest.c index 430bcb6..46964b3 100644 --- a/tests/viruritest.c +++ b/tests/viruritest.c @@ -27,7 +27,7 @@ #include "util.h" #include "virterror_internal.h" #include "memory.h" -#include "logging.h" +#include "virlog.h" #include "viruri.h" diff --git a/tools/console.c b/tools/console.c index 40de8eb..dbdaab7 100644 --- a/tools/console.c +++ b/tools/console.c @@ -38,7 +38,7 @@ # include "internal.h" # include "console.h" -# include "logging.h" +# include "virlog.h" # include "util.h" # include "virfile.h" # include "memory.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- cfg.mk | 6 +- daemon/libvirtd-config.c | 2 +- daemon/libvirtd.c | 2 +- daemon/remote.c | 2 +- daemon/stream.c | 2 +- python/libvirt-override.c | 2 +- python/typewrappers.c | 2 +- src/Makefile.am | 2 +- src/conf/capabilities.c | 2 +- src/conf/cpu_conf.c | 2 +- src/conf/device_conf.c | 2 +- src/conf/domain_audit.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_event.c | 2 +- src/conf/interface_conf.c | 2 +- src/conf/netdev_bandwidth_conf.c | 2 +- src/conf/netdev_vlan_conf.c | 2 +- src/conf/netdev_vport_profile_conf.c | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 4 +- src/conf/nwfilter_conf.c | 2 +- src/conf/nwfilter_params.c | 2 +- src/conf/secret_conf.c | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/conf/virconsole.c | 2 +- src/cpu/cpu.c | 2 +- src/cpu/cpu_arm.c | 2 +- src/cpu/cpu_generic.c | 2 +- src/cpu/cpu_map.c | 2 +- src/cpu/cpu_powerpc.c | 2 +- src/cpu/cpu_s390.c | 2 +- src/cpu/cpu_x86.c | 2 +- src/datatypes.c | 2 +- src/driver.c | 2 +- src/esx/esx_device_monitor.c | 2 +- src/esx/esx_driver.c | 2 +- src/esx/esx_interface_driver.c | 2 +- src/esx/esx_network_driver.c | 2 +- src/esx/esx_nwfilter_driver.c | 2 +- src/esx/esx_secret_driver.c | 2 +- src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/esx/esx_storage_driver.c | 2 +- src/esx/esx_util.c | 2 +- src/esx/esx_vi.c | 2 +- src/esx/esx_vi_methods.c | 2 +- src/esx/esx_vi_types.c | 2 +- src/fdstream.c | 2 +- src/hyperv/hyperv_device_monitor.c | 2 +- src/hyperv/hyperv_driver.c | 2 +- src/hyperv/hyperv_interface_driver.c | 2 +- src/hyperv/hyperv_network_driver.c | 2 +- src/hyperv/hyperv_nwfilter_driver.c | 2 +- src/hyperv/hyperv_secret_driver.c | 2 +- src/hyperv/hyperv_storage_driver.c | 2 +- src/hyperv/hyperv_util.c | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/interface/interface_backend_netcf.c | 2 +- src/interface/interface_backend_udev.c | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/locking/domain_lock.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_daemon_config.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_nop.c | 2 +- src/locking/lock_driver_sanlock.c | 2 +- src/locking/lock_manager.c | 2 +- src/locking/sanlock_helper.c | 2 +- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_controller.c | 2 +- src/lxc/lxc_domain.c | 2 +- src/lxc/lxc_driver.c | 2 +- src/lxc/lxc_fuse.h | 2 +- src/lxc/lxc_monitor.c | 2 +- src/lxc/lxc_process.c | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_driver.c | 2 +- src/node_device/node_device_hal.c | 2 +- src/node_device/node_device_linux_sysfs.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/nodeinfo.c | 2 +- src/nwfilter/nwfilter_dhcpsnoop.c | 2 +- src/nwfilter/nwfilter_driver.c | 2 +- src/nwfilter/nwfilter_ebiptables_driver.c | 2 +- src/nwfilter/nwfilter_gentech_driver.c | 2 +- src/nwfilter/nwfilter_learnipaddr.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/openvz/openvz_util.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_network.c | 2 +- src/parallels/parallels_storage.c | 2 +- src/parallels/parallels_utils.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_agent.c | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_cgroup.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_domain.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_text.c | 2 +- src/qemu/qemu_process.c | 2 +- src/remote/remote_driver.c | 2 +- src/rpc/virkeepalive.c | 2 +- src/rpc/virnetclient.c | 2 +- src/rpc/virnetclientprogram.c | 2 +- src/rpc/virnetclientstream.c | 2 +- src/rpc/virnetmessage.c | 2 +- src/rpc/virnetsaslcontext.c | 2 +- src/rpc/virnetserver.c | 2 +- src/rpc/virnetserverclient.c | 2 +- src/rpc/virnetservermdns.c | 2 +- src/rpc/virnetserverprogram.c | 2 +- src/rpc/virnetserverservice.c | 2 +- src/rpc/virnetsocket.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/rpc/virnettlscontext.c | 2 +- src/secret/secret_driver.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_manager.c | 2 +- src/security/security_selinux.c | 2 +- src/security/security_stack.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_disk.c | 2 +- src/storage/storage_backend_fs.c | 2 +- src/storage/storage_backend_iscsi.c | 2 +- src/storage/storage_backend_logical.c | 2 +- src/storage/storage_backend_mpath.c | 2 +- src/storage/storage_backend_rbd.c | 2 +- src/storage/storage_backend_scsi.c | 2 +- src/storage/storage_backend_sheepdog.c | 2 +- src/storage/storage_driver.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/iohelper.c | 2 +- src/util/memory.c | 422 ------------------------------ src/util/memory.h | 380 --------------------------- src/util/pci.c | 2 +- src/util/sexpr.c | 2 +- src/util/stats_linux.c | 2 +- src/util/storage_file.c | 2 +- src/util/sysinfo.c | 2 +- src/util/threadpool.c | 2 +- src/util/threads-pthread.c | 2 +- src/util/threads-win32.c | 2 +- src/util/util.c | 2 +- src/util/uuid.c | 2 +- src/util/viralloc.c | 422 ++++++++++++++++++++++++++++++ src/util/viralloc.h | 380 +++++++++++++++++++++++++++ src/util/viraudit.c | 2 +- src/util/virauth.c | 2 +- src/util/virauthconfig.c | 2 +- src/util/virbitmap.c | 2 +- src/util/virbuffer.c | 2 +- src/util/vircgroup.c | 2 +- src/util/vircommand.c | 2 +- src/util/virconf.c | 2 +- src/util/virdbus.c | 2 +- src/util/virdnsmasq.c | 2 +- src/util/virebtables.c | 2 +- src/util/vireventpoll.c | 2 +- src/util/virfile.c | 2 +- src/util/virhash.c | 2 +- src/util/virhooks.c | 2 +- src/util/virinitctl.c | 2 +- src/util/viriptables.c | 2 +- src/util/virjson.c | 2 +- src/util/virkeyfile.c | 2 +- src/util/virlockspace.c | 2 +- src/util/virlog.c | 2 +- src/util/virnetdev.c | 2 +- src/util/virnetdevbandwidth.c | 2 +- src/util/virnetdevbridge.c | 2 +- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevopenvswitch.c | 2 +- src/util/virnetdevtap.c | 2 +- src/util/virnetdevveth.c | 2 +- src/util/virnetdevvlan.c | 2 +- src/util/virnetdevvportprofile.c | 2 +- src/util/virnetlink.c | 2 +- src/util/virnodesuspend.c | 2 +- src/util/virobject.c | 2 +- src/util/virpidfile.c | 2 +- src/util/virprocess.c | 2 +- src/util/virstring.c | 2 +- src/util/virterror.c | 2 +- src/util/virtime.c | 2 +- src/util/virtypedparam.c | 2 +- src/util/viruri.c | 2 +- src/util/virusb.c | 2 +- src/util/xml.c | 2 +- src/vbox/vbox_MSCOMGlue.c | 2 +- src/vbox/vbox_XPCOMCGlue.c | 2 +- src/vbox/vbox_tmpl.c | 2 +- src/vmware/vmware_conf.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 2 +- src/xen/block_stats.c | 2 +- src/xen/xen_driver.c | 2 +- src/xen/xen_hypervisor.c | 2 +- src/xen/xen_inotify.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xm_internal.c | 2 +- src/xen/xs_internal.c | 2 +- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 2 +- src/xenxs/xen_sxpr.c | 2 +- src/xenxs/xen_xm.c | 2 +- tests/commandhelper.c | 2 +- tests/commandtest.c | 2 +- tests/conftest.c | 2 +- tests/cputest.c | 2 +- tests/esxutilstest.c | 2 +- tests/networkxml2conftest.c | 2 +- tests/openvzutilstest.c | 2 +- tests/qemuhelptest.c | 2 +- tests/qemumonitortest.c | 2 +- tests/qemumonitortestutils.c | 2 +- tests/qemuxml2argvtest.c | 2 +- tests/securityselinuxtest.c | 2 +- tests/sockettest.c | 2 +- tests/testutils.c | 2 +- tests/testutils.h | 2 +- tests/testutilslxc.c | 2 +- tests/testutilsqemu.c | 2 +- tests/utiltest.c | 2 +- tests/virauthconfigtest.c | 2 +- tests/virbuftest.c | 2 +- tests/virdrivermoduletest.c | 2 +- tests/virhashtest.c | 2 +- tests/virkeyfiletest.c | 2 +- tests/virlockspacetest.c | 2 +- tests/virnetmessagetest.c | 2 +- tests/virnetsockettest.c | 2 +- tests/virnettlscontexttest.c | 2 +- tests/virstringtest.c | 2 +- tests/virtimetest.c | 2 +- tests/viruritest.c | 2 +- tests/vmx2xmltest.c | 2 +- tests/xmconfigtest.c | 2 +- tests/xml2vmxtest.c | 2 +- tools/console.c | 2 +- tools/virsh-domain-monitor.c | 2 +- tools/virsh-domain.c | 2 +- tools/virsh-host.c | 2 +- tools/virsh-interface.c | 2 +- tools/virsh-network.c | 2 +- tools/virsh-nodedev.c | 2 +- tools/virsh-nwfilter.c | 2 +- tools/virsh-pool.c | 2 +- tools/virsh-secret.c | 2 +- tools/virsh-snapshot.c | 2 +- tools/virsh-volume.c | 2 +- tools/virsh.c | 2 +- tools/virt-host-validate-common.c | 2 +- 270 files changed, 1071 insertions(+), 1071 deletions(-) delete mode 100644 src/util/memory.c delete mode 100644 src/util/memory.h create mode 100644 src/util/viralloc.c create mode 100644 src/util/viralloc.h diff --git a/cfg.mk b/cfg.mk index 9fbf799..e23f1c5 100644 --- a/cfg.mk +++ b/cfg.mk @@ -321,7 +321,7 @@ sc_prohibit_internal_functions: # Avoid raw malloc and free, except in documentation comments. sc_prohibit_raw_allocation: @prohibit='^.[^*].*\<((m|c|re)alloc|free) *\([^)]' \ - halt='use VIR_ macros from memory.h instead of malloc/free' \ + halt='use VIR_ macros from viralloc.h instead of malloc/free' \ $(_sc_search_regexp) # Avoid functions that can lead to double-close bugs. @@ -785,7 +785,7 @@ exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/util\.c$$ exclude_file_name_regexp--sc_prohibit_internal_functions = \ - ^src/(util/(memory|util|virfile)\.[hc]|esx/esx_vi\.c)$$ + ^src/(util/(viralloc|util|virfile)\.[hc]|esx/esx_vi\.c)$$ exclude_file_name_regexp--sc_prohibit_newline_at_end_of_diagnostic = \ ^src/rpc/gendispatch\.pl$$ @@ -794,7 +794,7 @@ exclude_file_name_regexp--sc_prohibit_nonreentrant = \ ^((po|tests)/|docs/.*py|run.in$$) exclude_file_name_regexp--sc_prohibit_raw_allocation = \ - ^(src/util/memory\.[ch]|examples/.*)$$ + ^(src/util/viralloc\.[ch]|examples/.*)$$ exclude_file_name_regexp--sc_prohibit_readlink = \ ^src/(util/util|lxc/lxc_container)\.c$$ diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index f61f08d..b979a23 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -25,7 +25,7 @@ #include "libvirtd-config.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "rpc/virnetserver.h" diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index fbf23d8..903f8c2 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -46,7 +46,7 @@ #include "util.h" #include "uuid.h" #include "remote_driver.h" -#include "memory.h" +#include "viralloc.h" #include "virconf.h" #include "virnetlink.h" #include "virnetserver.h" diff --git a/daemon/remote.c b/daemon/remote.c index 58ceb39..eb75281 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -33,7 +33,7 @@ #include "libvirtd.h" #include "libvirt_internal.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "util.h" #include "stream.h" diff --git a/daemon/stream.c b/daemon/stream.c index d63e009..f208139 100644 --- a/daemon/stream.c +++ b/daemon/stream.c @@ -25,7 +25,7 @@ #include "stream.h" #include "remote.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virnetserverclient.h" #include "virterror_internal.h" diff --git a/python/libvirt-override.c b/python/libvirt-override.c index eda8a11..644f34d 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -24,7 +24,7 @@ #include "libvirt/virterror.h" #include "typewrappers.h" #include "libvirt.h" -#include "memory.h" +#include "viralloc.h" #include "virtypedparam.h" #include "ignore-value.h" #include "util.h" diff --git a/python/typewrappers.c b/python/typewrappers.c index d633603..9ba8790 100644 --- a/python/typewrappers.c +++ b/python/typewrappers.c @@ -16,7 +16,7 @@ #include "typewrappers.h" -#include "memory.h" +#include "viralloc.h" #ifndef Py_CAPSULE_H typedef void(*PyCapsule_Destructor)(void *, void *); diff --git a/src/Makefile.am b/src/Makefile.am index 93da171..64f117d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/memory.c util/memory.h \ util/pci.c util/pci.h \ util/processinfo.c util/processinfo.h \ util/sexpr.c util/sexpr.h \ @@ -66,6 +65,7 @@ UTIL_SOURCES = \ util/threadpool.c util/threadpool.h \ util/uuid.c util/uuid.h \ util/util.c util/util.h \ + util/viralloc.c util/viralloc.h \ util/viratomic.h util/viratomic.c \ util/viraudit.c util/viraudit.h \ util/virauth.c util/virauth.h \ diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 3b8fef1..9ac18e2 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -27,7 +27,7 @@ #include "capabilities.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "uuid.h" #include "cpu_conf.h" diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 190b088..23941c5 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -24,7 +24,7 @@ #include <config.h> #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virbuffer.h" #include "cpu_conf.h" diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index daf57bc..c3ca2d6 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -23,7 +23,7 @@ #include <config.h> #include "virterror_internal.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "xml.h" #include "uuid.h" #include "util.h" diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index 5fca6a6..c275f71 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -30,7 +30,7 @@ #include "viraudit.h" #include "uuid.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" /* Return nn:mm in hex for block and character devices, and NULL * for other file types, stat failure, or allocation failure. */ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c48adf5..f80f5f1 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -34,7 +34,7 @@ #include "datatypes.h" #include "domain_conf.h" #include "snapshot_conf.h" -#include "memory.h" +#include "viralloc.h" #include "verify.h" #include "xml.h" #include "uuid.h" diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index f1e247b..d523808 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -26,7 +26,7 @@ #include "domain_event.h" #include "virlog.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index 738ef33..046a8a1 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -27,7 +27,7 @@ #include "interface_conf.h" -#include "memory.h" +#include "viralloc.h" #include "xml.h" #include "uuid.h" #include "util.h" diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c index 15840b9..35f067c 100644 --- a/src/conf/netdev_bandwidth_conf.c +++ b/src/conf/netdev_bandwidth_conf.c @@ -25,7 +25,7 @@ #include "netdev_bandwidth_conf.h" #include "virterror_internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "domain_conf.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/conf/netdev_vlan_conf.c b/src/conf/netdev_vlan_conf.c index 6a0511a..8cee025 100644 --- a/src/conf/netdev_vlan_conf.c +++ b/src/conf/netdev_vlan_conf.c @@ -23,7 +23,7 @@ #include "netdev_vlan_conf.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/conf/netdev_vport_profile_conf.c b/src/conf/netdev_vport_profile_conf.c index 94992e3..a9a38d7 100644 --- a/src/conf/netdev_vport_profile_conf.c +++ b/src/conf/netdev_vport_profile_conf.c @@ -24,7 +24,7 @@ #include "netdev_vport_profile_conf.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 42cb87e..1932851 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -37,7 +37,7 @@ #include "netdev_vport_profile_conf.h" #include "netdev_bandwidth_conf.h" #include "netdev_vlan_conf.h" -#include "memory.h" +#include "viralloc.h" #include "xml.h" #include "uuid.h" #include "util.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 50fcf0b..85de50f 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -28,10 +28,10 @@ #include "virterror_internal.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "node_device_conf.h" -#include "memory.h" +#include "viralloc.h" #include "xml.h" #include "util.h" #include "virbuffer.h" diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c index 46580e9..09a9d1c 100644 --- a/src/conf/nwfilter_conf.c +++ b/src/conf/nwfilter_conf.c @@ -39,7 +39,7 @@ #include "internal.h" #include "uuid.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" #include "nwfilter_params.h" diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c index f8cf980..1429952 100644 --- a/src/conf/nwfilter_params.c +++ b/src/conf/nwfilter_params.c @@ -25,7 +25,7 @@ #include "internal.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" #include "nwfilter_params.h" diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index 24d7aa0..5188c7a 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -26,7 +26,7 @@ #include "virbuffer.h" #include "datatypes.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "secret_conf.h" #include "virterror_internal.h" #include "util.h" diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 6361810..9c16a88 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -35,7 +35,7 @@ #include "datatypes.h" #include "domain_conf.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "netdev_bandwidth_conf.h" #include "netdev_vport_profile_conf.h" #include "nwfilter_conf.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index b81c08c..0e00588 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -42,7 +42,7 @@ #include "uuid.h" #include "virbuffer.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 0c2bded..8d3ceac 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -28,7 +28,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "storage_conf.h" #include "storage_encryption_conf.h" #include "util.h" diff --git a/src/conf/virconsole.c b/src/conf/virconsole.c index 92179cc..757573d 100644 --- a/src/conf/virconsole.c +++ b/src/conf/virconsole.c @@ -32,7 +32,7 @@ #include "fdstream.h" #include "internal.h" #include "threads.h" -#include "memory.h" +#include "viralloc.h" #include "virpidfile.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 17a06f3..2222a91 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -24,7 +24,7 @@ #include <config.h> #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "xml.h" #include "cpu.h" #include "cpu_x86.h" diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c index 2d005df..75dee30 100644 --- a/src/cpu/cpu_arm.c +++ b/src/cpu/cpu_arm.c @@ -23,7 +23,7 @@ #include <config.h> -#include "memory.h" +#include "viralloc.h" #include "cpu.h" #define VIR_FROM_THIS VIR_FROM_CPU diff --git a/src/cpu/cpu_generic.c b/src/cpu/cpu_generic.c index 3a6ed6c..4415ce1 100644 --- a/src/cpu/cpu_generic.c +++ b/src/cpu/cpu_generic.c @@ -24,7 +24,7 @@ #include <config.h> -#include "memory.h" +#include "viralloc.h" #include "virhash.h" #include "cpu.h" #include "cpu_generic.h" diff --git a/src/cpu/cpu_map.c b/src/cpu/cpu_map.c index 8c4cfee..015be2e 100644 --- a/src/cpu/cpu_map.c +++ b/src/cpu/cpu_map.c @@ -23,7 +23,7 @@ #include <config.h> -#include "memory.h" +#include "viralloc.h" #include "cpu.h" #include "cpu_map.h" #include "configmake.h" diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index c59bd1b..6b6c325 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -27,7 +27,7 @@ #include <stdint.h> #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "cpu.h" diff --git a/src/cpu/cpu_s390.c b/src/cpu/cpu_s390.c index 137c15f..a0f06f1 100644 --- a/src/cpu/cpu_s390.c +++ b/src/cpu/cpu_s390.c @@ -23,7 +23,7 @@ #include <config.h> -#include "memory.h" +#include "viralloc.h" #include "cpu.h" diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index bea48a1..93ee111 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -26,7 +26,7 @@ #include <stdint.h> #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "cpu.h" #include "cpu_map.h" diff --git a/src/datatypes.c b/src/datatypes.c index 73a2fd0..0907c7d 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -25,7 +25,7 @@ #include "datatypes.h" #include "virterror_internal.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "util.h" diff --git a/src/driver.c b/src/driver.c index 4ef6fd2..23dc329 100644 --- a/src/driver.c +++ b/src/driver.c @@ -25,7 +25,7 @@ #include <unistd.h> #include "driver.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "util.h" #include "configmake.h" diff --git a/src/esx/esx_device_monitor.c b/src/esx/esx_device_monitor.c index 0ad95f5..854fc38 100644 --- a/src/esx/esx_device_monitor.c +++ b/src/esx/esx_device_monitor.c @@ -26,7 +26,7 @@ #include "internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "esx_private.h" diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index a69d149..0fe9a67 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -29,7 +29,7 @@ #include "snapshot_conf.h" #include "virauth.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "vmx.h" diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 4760264..fea67ab 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "interface_conf.h" diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index 3e25aa2..fec7e72 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -27,7 +27,7 @@ #include "md5.h" #include "internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "network_conf.h" diff --git a/src/esx/esx_nwfilter_driver.c b/src/esx/esx_nwfilter_driver.c index f5e710d..7a05a5a 100644 --- a/src/esx/esx_nwfilter_driver.c +++ b/src/esx/esx_nwfilter_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "esx_private.h" diff --git a/src/esx/esx_secret_driver.c b/src/esx/esx_secret_driver.c index 2a98644..2969b19 100644 --- a/src/esx/esx_secret_driver.c +++ b/src/esx/esx_secret_driver.c @@ -25,7 +25,7 @@ #include "internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "esx_private.h" diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 5d4eb3c..9d481d2 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -29,7 +29,7 @@ #include "internal.h" #include "md5.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "storage_conf.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index c8bba9e..bca637b 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -32,7 +32,7 @@ #include "internal.h" #include "md5.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "storage_conf.h" diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index e6c09aa..1324469 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -26,7 +26,7 @@ #include <config.h> #include "uuid.h" -#include "memory.h" +#include "viralloc.h" #include "storage_conf.h" #include "esx_private.h" #include "esx_storage_driver.h" diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index 6e27fe4..bcda9df 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -29,7 +29,7 @@ #include "internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "vmx.h" diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 76192df..37b6e0f 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -27,7 +27,7 @@ #include <libxml/xpathInternals.h> #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "util.h" #include "uuid.h" diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c index a3870ee..7ffca559 100644 --- a/src/esx/esx_vi_methods.c +++ b/src/esx/esx_vi_methods.c @@ -24,7 +24,7 @@ #include <config.h> #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "esx_vi_methods.h" diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index d0a2c6c..b93223d 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -29,7 +29,7 @@ #include "virbuffer.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "util.h" #include "esx_vi.h" diff --git a/src/fdstream.c b/src/fdstream.c index fdbd7a2..39e92b8 100644 --- a/src/fdstream.c +++ b/src/fdstream.c @@ -36,7 +36,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "configmake.h" diff --git a/src/hyperv/hyperv_device_monitor.c b/src/hyperv/hyperv_device_monitor.c index 1fa98b2..d6edb76 100644 --- a/src/hyperv/hyperv_device_monitor.c +++ b/src/hyperv/hyperv_device_monitor.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_device_monitor.h" diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 95b0cd9..749c7f0 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -28,7 +28,7 @@ #include "domain_conf.h" #include "virauth.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_driver.h" diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c index 6a3c2cb..43c7dd7 100644 --- a/src/hyperv/hyperv_interface_driver.c +++ b/src/hyperv/hyperv_interface_driver.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_interface_driver.h" diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index 2f9fcab..06b051b 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_network_driver.h" diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c index c490522..7452b7a 100644 --- a/src/hyperv/hyperv_nwfilter_driver.c +++ b/src/hyperv/hyperv_nwfilter_driver.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_nwfilter_driver.h" diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c index 3d58b01..04a6ada 100644 --- a/src/hyperv/hyperv_secret_driver.c +++ b/src/hyperv/hyperv_secret_driver.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_secret_driver.h" diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c index 7fbc14d..b2817a2 100644 --- a/src/hyperv/hyperv_storage_driver.c +++ b/src/hyperv/hyperv_storage_driver.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_storage_driver.h" diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c index 1ef6dae..016d415 100644 --- a/src/hyperv/hyperv_util.c +++ b/src/hyperv/hyperv_util.c @@ -25,7 +25,7 @@ #include "internal.h" #include "datatypes.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "hyperv_private.h" diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 069ebe6..69e7283 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -28,7 +28,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "uuid.h" #include "virbuffer.h" diff --git a/src/interface/interface_backend_netcf.c b/src/interface/interface_backend_netcf.c index 1f42920..74a749b 100644 --- a/src/interface/interface_backend_netcf.c +++ b/src/interface/interface_backend_netcf.c @@ -29,7 +29,7 @@ #include "datatypes.h" #include "interface_driver.h" #include "interface_conf.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_INTERFACE diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index 9233e87..248b02e 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -27,7 +27,7 @@ #include "datatypes.h" #include "interface_driver.h" #include "interface_conf.h" -#include "memory.h" +#include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_INTERFACE diff --git a/src/libvirt.c b/src/libvirt.c index d078304..ed7dcae 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -51,7 +51,7 @@ #include "driver.h" #include "uuid.h" -#include "memory.h" +#include "viralloc.h" #include "configmake.h" #include "intprops.h" #include "virconf.h" diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index 460d15f..ac55cf3 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -37,7 +37,7 @@ #include "datatypes.h" #include "virfile.h" #include "virstring.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "capabilities.h" #include "libxl_driver.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index ced7cfa..af74ebc 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -37,7 +37,7 @@ #include "virconf.h" #include "datatypes.h" #include "virfile.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "vircommand.h" #include "libxl.h" diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c index 00861cf..0ae9750 100644 --- a/src/locking/domain_lock.c +++ b/src/locking/domain_lock.c @@ -22,7 +22,7 @@ #include <config.h> #include "domain_lock.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index 3c2a50c..3d90c57 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -39,7 +39,7 @@ #include "virprocess.h" #include "virterror_internal.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "virconf.h" #include "rpc/virnetserver.h" #include "virrandom.h" diff --git a/src/locking/lock_daemon_config.c b/src/locking/lock_daemon_config.c index 9557b8c..e370dd4 100644 --- a/src/locking/lock_daemon_config.c +++ b/src/locking/lock_daemon_config.c @@ -25,7 +25,7 @@ #include "lock_daemon_config.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "rpc/virnetserver.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index d5d721d..cee530d 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -23,7 +23,7 @@ #include "lock_driver.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "util.h" diff --git a/src/locking/lock_driver_nop.c b/src/locking/lock_driver_nop.c index 745a0bf..cf0f49a 100644 --- a/src/locking/lock_driver_nop.c +++ b/src/locking/lock_driver_nop.c @@ -22,7 +22,7 @@ #include <config.h> #include "lock_driver_nop.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index 1e8df26..e520444 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -39,7 +39,7 @@ #include "lock_driver.h" #include "virlog.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "md5.h" diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c index f038d4e..f938b04 100644 --- a/src/locking/lock_manager.c +++ b/src/locking/lock_manager.c @@ -26,7 +26,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #if HAVE_DLFCN_H diff --git a/src/locking/sanlock_helper.c b/src/locking/sanlock_helper.c index ad69312..3e400b7 100644 --- a/src/locking/sanlock_helper.c +++ b/src/locking/sanlock_helper.c @@ -6,7 +6,7 @@ #include "configmake.h" #include "internal.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "domain_conf.h" diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index b8c4308..5d1f7ff 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -26,7 +26,7 @@ #include "virfile.h" #include "virterror_internal.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "vircgroup.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index ca36965..043630a 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -32,7 +32,7 @@ #include "nodeinfo.h" #include "virterror_internal.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "configmake.h" diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 4aae28e..f3c6e19 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -57,7 +57,7 @@ #include "virlog.h" #include "lxc_container.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virnetdevveth.h" #include "uuid.h" #include "virfile.h" diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 78f10ab..8a83e71 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -63,7 +63,7 @@ #include "lxc_fuse.h" #include "virnetdev.h" #include "virnetdevveth.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "virpidfile.h" diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 77a64dd..fab1506 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -23,7 +23,7 @@ #include "lxc_domain.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 0ab2cb9..35e8ac9 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -43,7 +43,7 @@ #include "lxc_domain.h" #include "lxc_driver.h" #include "lxc_process.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virnetdevbridge.h" #include "virnetdevveth.h" diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h index a888122..9878017 100644 --- a/src/lxc/lxc_fuse.h +++ b/src/lxc/lxc_fuse.h @@ -33,7 +33,7 @@ # include "lxc_conf.h" # include "util.h" -# include "memory.h" +# include "viralloc.h" struct virLXCMeminfo { unsigned long long memtotal; diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c index 9eb587d..90637eb 100644 --- a/src/lxc/lxc_monitor.c +++ b/src/lxc/lxc_monitor.c @@ -25,7 +25,7 @@ #include "lxc_protocol.h" #include "lxc_monitor_dispatch.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 02ed226..af14f6a 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -38,7 +38,7 @@ #include "virtime.h" #include "domain_nwfilter.h" #include "network/bridge_driver.h" -#include "memory.h" +#include "viralloc.h" #include "domain_audit.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 2a59b84..52b36a1 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -54,7 +54,7 @@ #include "virpidfile.h" #include "util.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "viriptables.h" #include "virlog.h" diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 48360e3..d914816 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "node_device_conf.h" #include "node_device_hal.h" diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 59ba5c3..6f89f16 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "driver.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "pci.h" #include "virlog.h" diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index fbe0da5..be5d3ed 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -29,7 +29,7 @@ #include "node_device_driver.h" #include "node_device_hal.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index fef00ad..81a11d7 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -33,7 +33,7 @@ #include "driver.h" #include "datatypes.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "util.h" #include "virbuffer.h" diff --git a/src/nodeinfo.c b/src/nodeinfo.c index 0019c2b..b14e63b 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -39,7 +39,7 @@ #endif #include "c-ctype.h" -#include "memory.h" +#include "viralloc.h" #include "nodeinfo.h" #include "physmem.h" #include "util.h" diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c index 68aa233..a798e95 100644 --- a/src/nwfilter/nwfilter_dhcpsnoop.c +++ b/src/nwfilter/nwfilter_dhcpsnoop.c @@ -54,7 +54,7 @@ #include <netinet/udp.h> #include <net/if.h> -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "datatypes.h" #include "virterror_internal.h" diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c index 7fde656..4b1188d 100644 --- a/src/nwfilter/nwfilter_driver.c +++ b/src/nwfilter/nwfilter_driver.c @@ -34,7 +34,7 @@ #include "virterror_internal.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "domain_conf.h" #include "domain_nwfilter.h" #include "nwfilter_conf.h" diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index 23a43d2..092ae5a 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -31,7 +31,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" #include "domain_conf.h" diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c index 6be4a93..2b4cc8e 100644 --- a/src/nwfilter/nwfilter_gentech_driver.c +++ b/src/nwfilter/nwfilter_gentech_driver.c @@ -26,7 +26,7 @@ #include "internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "domain_conf.h" #include "virterror_internal.h" diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c index 110eae8..8c4bbcf 100644 --- a/src/nwfilter/nwfilter_learnipaddr.c +++ b/src/nwfilter/nwfilter_learnipaddr.c @@ -42,7 +42,7 @@ #include "intprops.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "datatypes.h" #include "virnetdev.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index c9189ef..6e0f6eb 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -48,7 +48,7 @@ #include "openvz_util.h" #include "uuid.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "nodeinfo.h" #include "virfile.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 101fa32..f6327fd 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -53,7 +53,7 @@ #include "util.h" #include "openvz_conf.h" #include "nodeinfo.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #include "virtypedparam.h" #include "virlog.h" diff --git a/src/openvz/openvz_util.c b/src/openvz/openvz_util.c index 4163e19..51b22c9 100644 --- a/src/openvz/openvz_util.c +++ b/src/openvz/openvz_util.c @@ -28,7 +28,7 @@ #include "virterror_internal.h" #include "vircommand.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "openvz_conf.h" #include "openvz_util.h" diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 4e6f903..2d3dc4a 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -43,7 +43,7 @@ #include "datatypes.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virlog.h" #include "vircommand.h" diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index 40706aa..4729f18 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -23,7 +23,7 @@ #include <config.h> #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "md5.h" diff --git a/src/parallels/parallels_storage.c b/src/parallels/parallels_storage.c index 90fa104..f546d28 100644 --- a/src/parallels/parallels_storage.c +++ b/src/parallels/parallels_storage.c @@ -31,7 +31,7 @@ #include <libgen.h> #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "configmake.h" #include "storage_file.h" #include "virterror_internal.h" diff --git a/src/parallels/parallels_utils.c b/src/parallels/parallels_utils.c index b032882..9e317b1 100644 --- a/src/parallels/parallels_utils.c +++ b/src/parallels/parallels_utils.c @@ -26,7 +26,7 @@ #include "vircommand.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virjson.h" #include "parallels_utils.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 0ac2771..ad56686 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -48,7 +48,7 @@ #include "util.h" #include "datatypes.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "driver.h" #include "libvirt/libvirt.h" diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 421e43f..ec1e300 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -34,7 +34,7 @@ #include "qemu_agent.h" #include "qemu_command.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" #include "virjson.h" diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 5853180..46f8540 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -24,7 +24,7 @@ #include <config.h> #include "qemu_capabilities.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" #include "util.h" diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 8d9ccf9..b47fb78 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -28,7 +28,7 @@ #include "qemu_process.h" #include "vircgroup.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "util.h" #include "domain_audit.h" diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8a35982..8a57cb5 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -28,7 +28,7 @@ #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" #include "cpu/cpu.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" #include "util.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 598fad7..d6bc1fc 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -44,7 +44,7 @@ #include "virbuffer.h" #include "virconf.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "datatypes.h" #include "xml.h" #include "nodeinfo.h" diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index e6eaa58..8dcadbc 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -27,7 +27,7 @@ #include "qemu_command.h" #include "qemu_capabilities.h" #include "qemu_migration.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" #include "c-ctype.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 25e5738..65254b6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -67,7 +67,7 @@ #include "nodeinfo.h" #include "stats_linux.h" #include "capabilities.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "domain_conf.h" #include "domain_audit.h" diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 3854520..754f8d0 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -26,7 +26,7 @@ #include "qemu_hostdev.h" #include "virlog.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "pci.h" #include "virusb.h" #include "virnetdev.h" diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 7edd125..c432a32 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -35,7 +35,7 @@ #include "virlog.h" #include "datatypes.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "pci.h" #include "virfile.h" #include "qemu_cgroup.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index cabbe1a..3e9ff03 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -38,7 +38,7 @@ #include "domain_audit.h" #include "virlog.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "datatypes.h" diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 920453d..5ca1f89 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -32,7 +32,7 @@ #include "qemu_monitor_text.h" #include "qemu_monitor_json.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" #include "virprocess.h" diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index e14134b..0137291 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -35,7 +35,7 @@ #include "qemu_monitor_json.h" #include "qemu_command.h" #include "qemu_capabilities.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "driver.h" #include "datatypes.h" diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 28690b1..82e9108 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -34,7 +34,7 @@ #include "qemu_command.h" #include "c-ctype.h" #include "c-strcasestr.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "driver.h" #include "datatypes.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index a77b248..b20734d 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -53,7 +53,7 @@ #include "datatypes.h" #include "virlog.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virhooks.h" #include "virfile.h" #include "virpidfile.h" diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 1e9151a..2edf6e6 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -38,7 +38,7 @@ #include "remote_driver.h" #include "remote_protocol.h" #include "qemu_protocol.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index 8fc1cba..91af315 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -22,7 +22,7 @@ #include <config.h> -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "virfile.h" #include "virlog.h" diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 7370ae0..b4fe4d9 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -30,7 +30,7 @@ #include "virnetclient.h" #include "virnetsocket.h" #include "virkeepalive.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "virfile.h" #include "virlog.h" diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c index dec3943..7396971 100644 --- a/src/rpc/virnetclientprogram.c +++ b/src/rpc/virnetclientprogram.c @@ -28,7 +28,7 @@ #include "virnetclient.h" #include "virnetprotocol.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "util.h" diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c index 26dc292..4877b0c 100644 --- a/src/rpc/virnetclientstream.c +++ b/src/rpc/virnetclientstream.c @@ -24,7 +24,7 @@ #include "virnetclientstream.h" #include "virnetclient.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "threads.h" diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c index 16d8e61..f273811 100644 --- a/src/rpc/virnetmessage.c +++ b/src/rpc/virnetmessage.c @@ -24,7 +24,7 @@ #include <unistd.h> #include "virnetmessage.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c index e880127..adc4f1e 100644 --- a/src/rpc/virnetsaslcontext.c +++ b/src/rpc/virnetsaslcontext.c @@ -26,7 +26,7 @@ #include "virnetmessage.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "virlog.h" diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 6d3532a..67cd4b5 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -29,7 +29,7 @@ #include "virnetserver.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "threads.h" #include "threadpool.h" diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 9642ea5..7f028b8 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -31,7 +31,7 @@ #include "virlog.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "virkeepalive.h" diff --git a/src/rpc/virnetservermdns.c b/src/rpc/virnetservermdns.c index c17b65d..daef2b4 100644 --- a/src/rpc/virnetservermdns.c +++ b/src/rpc/virnetservermdns.c @@ -42,7 +42,7 @@ #include "virnetservermdns.h" #include "vireventpoll.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c index 5b96c34..287282e 100644 --- a/src/rpc/virnetserverprogram.c +++ b/src/rpc/virnetserverprogram.c @@ -26,7 +26,7 @@ #include "virnetserverprogram.h" #include "virnetserverclient.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c index a9362ad..92b5cef 100644 --- a/src/rpc/virnetserverservice.c +++ b/src/rpc/virnetserverservice.c @@ -25,7 +25,7 @@ #include "virnetserverservice.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "threads.h" diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index aa8f4b9..8c62a2a 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -42,7 +42,7 @@ #include "c-ctype.h" #include "virnetsocket.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index 734acaa..8a7d5f9 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -27,7 +27,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "configmake.h" #include "threads.h" diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 2931003..d9354e0 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -30,7 +30,7 @@ #include "virnettlscontext.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "util.h" #include "virlog.h" diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 4159358..fb2024b 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -33,7 +33,7 @@ #include "datatypes.h" #include "driver.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "secret_conf.h" #include "secret_driver.h" #include "threads.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index f2aebc8..b65384e 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -39,7 +39,7 @@ #include "security_apparmor.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" #include "uuid.h" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 9ff2665..bdb29c7 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -26,7 +26,7 @@ #include "security_dac.h" #include "virterror_internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "pci.h" #include "virusb.h" diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 67c8858..2da6244 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -27,7 +27,7 @@ #include "security_stack.h" #include "security_dac.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 2a19781..3a1548d 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -35,7 +35,7 @@ #include "security_selinux.h" #include "virterror_internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "pci.h" #include "virusb.h" diff --git a/src/security/security_stack.c b/src/security/security_stack.c index c2ccbd0..390bd3b 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -23,7 +23,7 @@ #include "security_stack.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index d92b3d4..c9c222a 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -42,7 +42,7 @@ #include "internal.h" #include "virbuffer.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "vircommand.h" #include "security_driver.h" diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 899caeb..cdc5bda 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -48,7 +48,7 @@ #include "datatypes.h" #include "virterror_internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "internal.h" #include "secret_conf.h" #include "uuid.h" diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c index 7e1d3ec..8759b3a 100644 --- a/src/storage/storage_backend_disk.c +++ b/src/storage/storage_backend_disk.c @@ -30,7 +30,7 @@ #include "virlog.h" #include "storage_backend_disk.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "vircommand.h" #include "configmake.h" diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 78b50f0..f7b4656 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -46,7 +46,7 @@ #include "storage_conf.h" #include "storage_file.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "xml.h" #include "virfile.h" #include "virlog.h" diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index 46659af..ecb8f8e 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -38,7 +38,7 @@ #include "storage_backend_scsi.h" #include "storage_backend_iscsi.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c index f28c663..83b517c 100644 --- a/src/storage/storage_backend_logical.c +++ b/src/storage/storage_backend_logical.c @@ -35,7 +35,7 @@ #include "storage_backend_logical.h" #include "storage_conf.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/src/storage/storage_backend_mpath.c b/src/storage/storage_backend_mpath.c index 1ca120f..0e5d032 100644 --- a/src/storage/storage_backend_mpath.c +++ b/src/storage/storage_backend_mpath.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "storage_conf.h" #include "storage_backend.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index 4e58911..e1f07ab 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -26,7 +26,7 @@ #include "storage_backend_rbd.h" #include "storage_conf.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "base64.h" #include "uuid.h" diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c index 32713be..1db8fdd 100644 --- a/src/storage/storage_backend_scsi.c +++ b/src/storage/storage_backend_scsi.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "storage_backend_scsi.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c index 05deeeb..d3b9d87 100644 --- a/src/storage/storage_backend_sheepdog.c +++ b/src/storage/storage_backend_sheepdog.c @@ -31,7 +31,7 @@ #include "storage_conf.h" #include "vircommand.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index 6076f6c..aebf8bb 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -42,7 +42,7 @@ #include "util.h" #include "storage_driver.h" #include "storage_conf.h" -#include "memory.h" +#include "viralloc.h" #include "storage_backend.h" #include "virlog.h" #include "virfile.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index dbaf14e..3abd289 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -39,7 +39,7 @@ #include "util.h" #include "uuid.h" #include "capabilities.h" -#include "memory.h" +#include "viralloc.h" #include "network_conf.h" #include "interface_conf.h" #include "domain_conf.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 35b54c2..6da311b 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -40,7 +40,7 @@ #include "virbuffer.h" #include "virconf.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "nodeinfo.h" #include "virlog.h" #include "domain_nwfilter.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 90c9b66..cece114 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -51,7 +51,7 @@ #include "nodeinfo.h" #include "stats_linux.h" #include "capabilities.h" -#include "memory.h" +#include "viralloc.h" #include "uuid.h" #include "domain_conf.h" #include "domain_audit.h" diff --git a/src/util/iohelper.c b/src/util/iohelper.c index a9c8b4c..1b16d5c 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -36,7 +36,7 @@ #include "util.h" #include "threads.h" #include "virfile.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "configmake.h" #include "virrandom.h" diff --git a/src/util/memory.c b/src/util/memory.c deleted file mode 100644 index 186d3b6..0000000 --- a/src/util/memory.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * memory.c: safer memory allocation - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <config.h> -#include <stdlib.h> - -#include "memory.h" -#include "virlog.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. Any newly allocated memory in 'ptrptr' is uninitialized. - * - * 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; -} - -/** - * virExpandN: - * @ptrptr: pointer to pointer for address of allocated memory - * @size: number of bytes per element - * @countptr: pointer to number of elements in array - * @add: number of elements to add - * - * Resize the block of memory in 'ptrptr' to be an array of - * '*countptr' + 'add' elements, each 'size' bytes in length. - * Update 'ptrptr' and 'countptr' with the details of the newly - * allocated memory. On failure, 'ptrptr' and 'countptr' are not - * changed. Any newly allocated memory in 'ptrptr' is zero-filled. - * - * Returns -1 on failure to allocate, zero on success - */ -int virExpandN(void *ptrptr, size_t size, size_t *countptr, size_t add) -{ - int ret; - - if (*countptr + add < *countptr) { - errno = ENOMEM; - return -1; - } - ret = virReallocN(ptrptr, size, *countptr + add); - if (ret == 0) { - memset(*(char **)ptrptr + (size * *countptr), 0, size * add); - *countptr += add; - } - return ret; -} - -/** - * virResizeN: - * @ptrptr: pointer to pointer for address of allocated memory - * @size: number of bytes per element - * @allocptr: pointer to number of elements allocated in array - * @count: number of elements currently used in array - * @add: minimum number of additional elements to support in array - * - * If 'count' + 'add' is larger than '*allocptr', then resize the - * block of memory in 'ptrptr' to be an array of at least 'count' + - * 'add' elements, each 'size' bytes in length. Update 'ptrptr' and - * 'allocptr' with the details of the newly allocated memory. On - * failure, 'ptrptr' and 'allocptr' are not changed. Any newly - * allocated memory in 'ptrptr' is zero-filled. - * - * Returns -1 on failure to allocate, zero on success - */ -int virResizeN(void *ptrptr, size_t size, size_t *allocptr, size_t count, - size_t add) -{ - size_t delta; - - if (count + add < count) { - errno = ENOMEM; - return -1; - } - if (count + add <= *allocptr) - return 0; - - delta = count + add - *allocptr; - if (delta < *allocptr / 2) - delta = *allocptr / 2; - return virExpandN(ptrptr, size, allocptr, delta); -} - -/** - * virShrinkN: - * @ptrptr: pointer to pointer for address of allocated memory - * @size: number of bytes per element - * @countptr: pointer to number of elements in array - * @toremove: number of elements to remove - * - * Resize the block of memory in 'ptrptr' to be an array of - * '*countptr' - 'toremove' elements, each 'size' bytes in length. - * Update 'ptrptr' and 'countptr' with the details of the newly - * allocated memory. If 'toremove' is larger than 'countptr', free - * the entire array. - */ -void virShrinkN(void *ptrptr, size_t size, size_t *countptr, size_t toremove) -{ - if (toremove < *countptr) - ignore_value(virReallocN(ptrptr, size, *countptr -= toremove)); - else { - virFree(ptrptr); - *countptr = 0; - } -} - -/** - * virInsertElementsN: - * @ptrptr: pointer to hold address of allocated memory - * @size: the size of one element in bytes - * @at: index within array where new elements should be added - * @countptr: variable tracking number of elements currently allocated - * @add: number of elements to add - * @newelems: pointer to array of one or more new elements to move into - * place (the originals will be zeroed out if successful - * and if clearOriginal is true) - * @clearOriginal: false if the new item in the array should be copied - * from the original, and the original left intact. - * true if the original should be 0'd out on success. - * @inPlace: false if we should expand the allocated memory before - * moving, true if we should assume someone else *has - * already* done that. - * - * Re-allocate an array of *countptr elements, each sizeof(*ptrptr) bytes - * long, to be *countptr+add elements long, then appropriately move - * the elements starting at ptrptr[at] up by add elements, copy the - * items from newelems into ptrptr[at], then store the address of - * allocated memory in *ptrptr and the new size in *countptr. If - * newelems is NULL, the new elements at ptrptr[at] are instead filled - * with zero. - * - * Returns -1 on failure, 0 on success - */ -int -virInsertElementsN(void *ptrptr, size_t size, size_t at, - size_t *countptr, - size_t add, void *newelems, - bool clearOriginal, bool inPlace) -{ - if (at > *countptr) { - VIR_WARN("out of bounds index - count %zu at %zu add %zu", - *countptr, at, add); - return -1; - } - - if (inPlace) { - *countptr += add; - } else if (virExpandN(ptrptr, size, countptr, add) < 0) { - return -1; - } - - /* memory was successfully re-allocated. Move up all elements from - * ptrptr[at] to the end (if we're not "inserting" at the end - * already), memcpy in the new elements, and clear the elements - * from their original location. Remember that *countptr has - * already been updated with new element count! - */ - if (at < *countptr - add) { - memmove(*(char**)ptrptr + (size * (at + add)), - *(char**)ptrptr + (size * at), - size * (*countptr - add - at)); - } - - if (newelems) { - memcpy(*(char**)ptrptr + (size * at), newelems, size * add); - if (clearOriginal) - memset((char*)newelems, 0, size * add); - } else if (inPlace || (at < *countptr - add)) { - /* NB: if inPlace, assume memory at the end wasn't initialized */ - memset(*(char**)ptrptr + (size * at), 0, size * add); - } - - return 0; -} - -/** - * virDeleteElementsN: - * @ptrptr: pointer to hold address of allocated memory - * @size: the size of one element in bytes - * @at: index within array where new elements should be deleted - * @countptr: variable tracking number of elements currently allocated - * @remove: number of elements to remove - * @inPlace: false if we should shrink the allocated memory when done, - * true if we should assume someone else will do that. - * - * Re-allocate an array of *countptr elements, each sizeof(*ptrptr) - * bytes long, to be *countptr-remove elements long, then store the - * address of allocated memory in *ptrptr and the new size in *countptr. - * If *countptr <= remove, the entire array is freed. - * - * Returns -1 on failure, 0 on success - */ -int -virDeleteElementsN(void *ptrptr, size_t size, size_t at, - size_t *countptr, size_t remove, - bool inPlace) -{ - if (at + remove > *countptr) { - VIR_WARN("out of bounds index - count %zu at %zu remove %zu", - *countptr, at, remove); - return -1; - } - - /* First move down the elements at the end that won't be deleted, - * then realloc. We assume that the items being deleted have - * already been cleared. - */ - memmove(*(char**)ptrptr + (size * at), - *(char**)ptrptr + (size * (at + remove)), - size * (*countptr - remove - at)); - if (inPlace) - *countptr -= remove; - else - virShrinkN(ptrptr, size, countptr, remove); - return 0; -} - -/** - * Vir_Alloc_Var: - * @ptrptr: pointer to hold address of allocated memory - * @struct_size: size of initial struct - * @element_size: size of array elements - * @count: number of array elements to allocate - * - * Allocate struct_size bytes plus an array of 'count' elements, each - * of size element_size. This sort of allocation is useful for - * receiving the data of certain ioctls and other APIs which return a - * struct in which the last element is an array of undefined length. - * The caller of this type of API is expected to know the length of - * the array that will be returned and allocate a suitable buffer to - * contain the returned data. C99 refers to these variable length - * objects as structs containing flexible array members. - * - * Returns -1 on failure, 0 on success - */ -int virAllocVar(void *ptrptr, size_t struct_size, size_t element_size, size_t count) -{ - size_t alloc_size = 0; - -#if TEST_OOM - if (virAllocTestFail()) - return -1; -#endif - - if (VIR_ALLOC_VAR_OVERSIZED(struct_size, count, element_size)) { - errno = ENOMEM; - return -1; - } - - alloc_size = struct_size + (element_size * count); - *(void **)ptrptr = calloc(1, alloc_size); - if (*(void **)ptrptr == NULL) - return -1; - 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) -{ - int save_errno = errno; - - free(*(void**)ptrptr); - *(void**)ptrptr = NULL; - errno = save_errno; -} diff --git a/src/util/memory.h b/src/util/memory.h deleted file mode 100644 index 8398105..0000000 --- a/src/util/memory.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * memory.c: safer memory allocation - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * 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, see - * <http://www.gnu.org/licenses/>. - * - */ - - -#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 - ATTRIBUTE_NONNULL(1); -int virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK - ATTRIBUTE_NONNULL(1); -int virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK - ATTRIBUTE_NONNULL(1); -int virExpandN(void *ptrptr, size_t size, size_t *count, size_t add) - ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); -int virResizeN(void *ptrptr, size_t size, size_t *alloc, size_t count, - size_t desired) - ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); -void virShrinkN(void *ptrptr, size_t size, size_t *count, size_t toremove) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); -int virInsertElementsN(void *ptrptr, size_t size, size_t at, size_t *countptr, - size_t add, void *newelem, - bool clearOriginal, bool inPlace) - ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); -int virDeleteElementsN(void *ptrptr, size_t size, size_t at, size_t *countptr, - size_t remove, bool inPlace) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); -int virAllocVar(void *ptrptr, - size_t struct_size, - size_t element_size, - size_t count) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1); -void virFree(void *ptrptr) ATTRIBUTE_NONNULL(1); - -/** - * 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'. If 'ptr' grew, the added memory is uninitialized. - * - * Returns -1 on failure, 0 on success - */ -# define VIR_REALLOC_N(ptr, count) virReallocN(&(ptr), sizeof(*(ptr)), (count)) - -/** - * VIR_EXPAND_N: - * @ptr: pointer to hold address of allocated memory - * @count: variable tracking number of elements currently allocated - * @add: number of elements to add - * - * Re-allocate an array of 'count' elements, each sizeof(*ptr) - * bytes long, to be 'count' + 'add' elements long, then store the - * address of allocated memory in 'ptr' and the new size in 'count'. - * The new elements are filled with zero. - * - * Returns -1 on failure, 0 on success - */ -# define VIR_EXPAND_N(ptr, count, add) \ - virExpandN(&(ptr), sizeof(*(ptr)), &(count), add) - -/** - * VIR_RESIZE_N: - * @ptr: pointer to hold address of allocated memory - * @alloc: variable tracking number of elements currently allocated - * @count: number of elements currently in use - * @add: minimum number of elements to additionally support - * - * Blindly using VIR_EXPAND_N(array, alloc, 1) in a loop scales - * quadratically, because every iteration must copy contents from - * all prior iterations. But amortized linear scaling can be achieved - * by tracking allocation size separately from the number of used - * elements, and growing geometrically only as needed. - * - * If 'count' + 'add' is larger than 'alloc', then geometrically reallocate - * the array of 'alloc' elements, each sizeof(*ptr) bytes long, and store - * the address of allocated memory in 'ptr' and the new size in 'alloc'. - * The new elements are filled with zero. - * - * Returns -1 on failure, 0 on success - */ -# define VIR_RESIZE_N(ptr, alloc, count, add) \ - virResizeN(&(ptr), sizeof(*(ptr)), &(alloc), count, add) - -/** - * VIR_SHRINK_N: - * @ptr: pointer to hold address of allocated memory - * @count: variable tracking number of elements currently allocated - * @remove: number of elements to remove - * - * Re-allocate an array of 'count' elements, each sizeof(*ptr) - * bytes long, to be 'count' - 'remove' elements long, then store the - * address of allocated memory in 'ptr' and the new size in 'count'. - * If 'count' <= 'remove', the entire array is freed. - * - * No return value. - */ -# define VIR_SHRINK_N(ptr, count, remove) \ - virShrinkN(&(ptr), sizeof(*(ptr)), &(count), remove) - -/* - * VIR_TYPEMATCH: - * - * The following macro seems a bit cryptic, so it needs a thorough - * explanation. Its purpose is to check for assignment compatibility - * and identical size between two values without creating any side - * effects (by doing something silly like actually assigning one to - * the other). Note that it takes advantage of the C89-guaranteed - * property of sizeof() - it cannot have any side effects, so anything - * that happens inside sizeof() will not have any effect at runtime. - * - * VIR_TYPEMATCH evaluates to "1" if the two passed values are both - * assignment-compatible and the same size, and otherwise generates a - * compile-time error. It determines the result by performing the - * following three operations: - * - * * sizeof(*(a) = *(b)) assures that *a and *b are - * assignment-compatible (they may still have a different size - * though! e.g. longVar = intVar) (If not, there is a compile-time - * error. If so, the result of that subexpression is sizeof(*(a)), - * i.e. one element of the array) - * - * * sizeof(*(a) = *(b)) == sizeof(*(b)) checks if *a and *b are also - * of the same size (so that, e.g. you don't accidentally copy an - * int plus the random bytes following it into an array of long). It - * evaluates to 1 if they are the same, and 0 otherwise. - * - * * sizeof(char[2 * (result of previous step) - 1]) evaluates to 1 - * if the previous step was successful (char [(2*1) - 1] i.e. - * char[1]), or generates a compile error if it wasn't successful - * (char[2*0 -1] i.e. char[-1], which isn't valid in C). - * - * So VIR_TYPECHECK(a, b) will either abort the compile with an error, - * or evaluate to "1", and in the meantime check that we've actually - * added the correct &'s and/or *'s to the arguments. (Whew!) -*/ -# define VIR_TYPEMATCH(a, b) \ - sizeof(char[2 * (sizeof(*(a) = *(b)) == sizeof(*(b))) - 1]) - -/** - * VIR_INSERT_ELEMENT: - * @ptr: pointer to array of objects (*not* ptr to ptr) - * @at: index within array where new elements should be added - * @count: variable tracking number of elements currently allocated - * @newelem: the new element to move into place (*not* a pointer to - * the element, but the element itself). - * (the original will be zeroed out if successful) - * - * Re-allocate an array of 'count' elements, each sizeof(*ptr) bytes - * long, to be 'count' + 1 elements long, then appropriately move - * the elements starting at ptr[at] up by 1 element, copy the - * item 'newelem' into ptr[at], then store the address of - * allocated memory in 'ptr' and the new size in 'count'. - * - * VIR_INSERT_ELEMENT_COPY is identical, but doesn't clear out the - * original element to 0 on success, so there are two copies of the - * element. This is useful if the "element" is actually just a - * pointer to the real data, and you want to maintain a reference to - * it for use after the insert is completed; but if the "element" is - * an object that points to other allocated memory, having multiple - * copies can cause problems (e.g. double free). - * - * VIR_INSERT_ELEMENT_*INPLACE are identical, but assume any necessary - * memory re-allocation has already been done. - * - * VIR_INSERT_ELEMENT_* all need to send "1" as the "add" argument to - * virInsertElementsN (which has the currently-unused capability of - * inserting multiple items at once). We use this to our advantage by - * replacing it with VIR_TYPECHECK(ptr, &newelem) so that we can be - * assured ptr and &newelem are of compatible types. - * - * Returns -1 on failure, 0 on success - * - * - */ -# define VIR_INSERT_ELEMENT(ptr, at, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, false) -# define VIR_INSERT_ELEMENT_COPY(ptr, at, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, false) -# define VIR_INSERT_ELEMENT_INPLACE(ptr, at, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, true) -# define VIR_INSERT_ELEMENT_COPY_INPLACE(ptr, at, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, true) - -/** - * VIR_APPEND_ELEMENT: - * @ptr: pointer to array of objects (*not* ptr to ptr) - * @count: variable tracking number of elements currently allocated - * @newelem: the new element to move into place (*not* a pointer to - * the element, but the element itself). - * (the original will be zeroed out if successful) - * - * Re-allocate an array of 'count' elements, each sizeof(*ptr) bytes - * long, to be 'count' + 1 elements long, then copy the item from - * 'newelem' into ptr[count+1], and store the address of allocated - * memory in 'ptr' and the new size in 'count'. If 'newelem' is NULL, - * the new element at ptr[at] is instead filled with zero. - * - * VIR_APPEND_ELEMENT_COPY is identical, but doesn't clear out the - * original element to 0 on success, so there are two copies of the - * element. This is useful if the "element" is actually just a - * pointer to the real data, and you want to maintain a reference to - * it for use after the append is completed; but if the "element" is - * an object that points to other allocated memory, having multiple - * copies can cause problems (e.g. double free). - * - * VIR_APPEND_ELEMENT_*INPLACE are identical, but assume any - * necessary memory re-allocation has already been done. - * - * VIR_APPEND_ELEMENT_* all need to send "1" as the "add" argument to - * virInsertElementsN (which has the currently-unused capability of - * inserting multiple items at once). We use this to our advantage by - * replacing it with VIR_TYPECHECK(ptr, &newelem) so that we can be - * assured ptr and &newelem are of compatible types. - * - * Returns -1 on failure, 0 on success - * - * - */ -# define VIR_APPEND_ELEMENT(ptr, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, false) -# define VIR_APPEND_ELEMENT_COPY(ptr, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, false) -# define VIR_APPEND_ELEMENT_INPLACE(ptr, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, true) -# define VIR_APPEND_ELEMENT_COPY_INPLACE(ptr, count, newelem) \ - virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ - VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, true) - -/** - * VIR_DELETE_ELEMENT: - * @ptr: pointer to array of objects (*not* ptr to ptr) - * @at: index within array where new elements should be deleted - * @count: variable tracking number of elements currently allocated - * - * Re-allocate an array of 'count' elements, each sizeof(*ptr) - * bytes long, to be 'count' - 1 elements long, then store the - * address of allocated memory in 'ptr' and the new size in 'count'. - * If 'count' <= 1, the entire array is freed. - * - * VIR_DELETE_ELEMENT_INPLACE is identical, but assumes any - * necessary memory re-allocation will be done later. - * - * Returns -1 on failure, 0 on success - */ -# define VIR_DELETE_ELEMENT(ptr, at, count) \ - virDeleteElementsN(&(ptr), sizeof(*(ptr)), at, &(count), 1, false) -# define VIR_DELETE_ELEMENT_INPLACE(ptr, at, count) \ - virDeleteElementsN(&(ptr), sizeof(*(ptr)), at, &(count), 1, true) - -/* - * VIR_ALLOC_VAR_OVERSIZED: - * @M: size of base structure - * @N: number of array elements in trailing array - * @S: size of trailing array elements - * - * Check to make sure that the requested allocation will not cause - * arithmetic overflow in the allocation size. The check is - * essentially the same as that in gnulib's xalloc_oversized. - */ -# define VIR_ALLOC_VAR_OVERSIZED(M, N, S) ((((size_t)-1) - (M)) / (S) < (N)) - -/** - * VIR_ALLOC_VAR: - * @ptr: pointer to hold address of allocated memory - * @type: element type of trailing array - * @count: number of array elements to allocate - * - * Allocate sizeof(*ptr) bytes plus an array of 'count' elements, each - * sizeof('type'). This sort of allocation is useful for receiving - * the data of certain ioctls and other APIs which return a struct in - * which the last element is an array of undefined length. The caller - * of this type of API is expected to know the length of the array - * that will be returned and allocate a suitable buffer to contain the - * returned data. C99 refers to these variable length objects as - * structs containing flexible array members. - - * Returns -1 on failure, 0 on success - */ -# define VIR_ALLOC_VAR(ptr, type, count) \ - virAllocVar(&(ptr), sizeof(*(ptr)), sizeof(type), (count)) - -/** - * VIR_FREE: - * @ptr: pointer holding address to be freed - * - * Free the memory stored in 'ptr' and update to point - * to NULL. - */ -/* The ternary ensures that ptr is a pointer and not an integer type, - * while evaluating ptr only once. For now, we intentionally cast - * away const, since a number of callers safely pass const char *. - */ -# define VIR_FREE(ptr) virFree((void *) (1 ? (const void *) &(ptr) : (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 index 7adce75..e4009fa 100644 --- a/src/util/pci.c +++ b/src/util/pci.c @@ -35,7 +35,7 @@ #include <stdlib.h> #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "vircommand.h" #include "virterror_internal.h" #include "virfile.h" diff --git a/src/util/sexpr.c b/src/util/sexpr.c index f72b7d7..ae0cc18 100644 --- a/src/util/sexpr.c +++ b/src/util/sexpr.c @@ -20,7 +20,7 @@ #include "virterror_internal.h" #include "sexpr.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_SEXPR diff --git a/src/util/stats_linux.c b/src/util/stats_linux.c index 2dfc30d..67ef82e 100644 --- a/src/util/stats_linux.c +++ b/src/util/stats_linux.c @@ -36,7 +36,7 @@ # include "datatypes.h" # include "util.h" # include "stats_linux.h" -# include "memory.h" +# include "viralloc.h" # include "virfile.h" # define VIR_FROM_THIS VIR_FROM_STATS_LINUX diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 6c3390b..a020bb2 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -35,7 +35,7 @@ # include <sys/statfs.h> #endif #include "dirname.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" diff --git a/src/util/sysinfo.c b/src/util/sysinfo.c index 5690f95..667e6a2 100644 --- a/src/util/sysinfo.c +++ b/src/util/sysinfo.c @@ -34,7 +34,7 @@ #include "sysinfo.h" #include "util.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "vircommand.h" #define VIR_FROM_THIS VIR_FROM_SYSINFO diff --git a/src/util/threadpool.c b/src/util/threadpool.c index ffbbe72..9d3d5d2 100644 --- a/src/util/threadpool.c +++ b/src/util/threadpool.c @@ -26,7 +26,7 @@ #include <config.h> #include "threadpool.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "virterror_internal.h" diff --git a/src/util/threads-pthread.c b/src/util/threads-pthread.c index 44e8bc0..37d8902 100644 --- a/src/util/threads-pthread.c +++ b/src/util/threads-pthread.c @@ -27,7 +27,7 @@ # include <sys/syscall.h> #endif -#include "memory.h" +#include "viralloc.h" /* Nothing special required for pthreads */ diff --git a/src/util/threads-win32.c b/src/util/threads-win32.c index 142aa4f..c9f16c1 100644 --- a/src/util/threads-win32.c +++ b/src/util/threads-win32.c @@ -23,7 +23,7 @@ #include <process.h> -#include "memory.h" +#include "viralloc.h" struct virThreadLocalData { DWORD key; diff --git a/src/util/util.c b/src/util/util.c index f941dfd..c070d94 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -80,7 +80,7 @@ #include "virbuffer.h" #include "util.h" #include "storage_file.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "verify.h" #include "virfile.h" diff --git a/src/util/uuid.c b/src/util/uuid.c index 6efc7be..5232ba9 100644 --- a/src/util/uuid.c +++ b/src/util/uuid.c @@ -38,7 +38,7 @@ #include "util.h" #include "virterror_internal.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #include "virrandom.h" diff --git a/src/util/viralloc.c b/src/util/viralloc.c new file mode 100644 index 0000000..628145f --- /dev/null +++ b/src/util/viralloc.c @@ -0,0 +1,422 @@ +/* + * memory.c: safer memory allocation + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> +#include <stdlib.h> + +#include "viralloc.h" +#include "virlog.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. Any newly allocated memory in 'ptrptr' is uninitialized. + * + * 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; +} + +/** + * virExpandN: + * @ptrptr: pointer to pointer for address of allocated memory + * @size: number of bytes per element + * @countptr: pointer to number of elements in array + * @add: number of elements to add + * + * Resize the block of memory in 'ptrptr' to be an array of + * '*countptr' + 'add' elements, each 'size' bytes in length. + * Update 'ptrptr' and 'countptr' with the details of the newly + * allocated memory. On failure, 'ptrptr' and 'countptr' are not + * changed. Any newly allocated memory in 'ptrptr' is zero-filled. + * + * Returns -1 on failure to allocate, zero on success + */ +int virExpandN(void *ptrptr, size_t size, size_t *countptr, size_t add) +{ + int ret; + + if (*countptr + add < *countptr) { + errno = ENOMEM; + return -1; + } + ret = virReallocN(ptrptr, size, *countptr + add); + if (ret == 0) { + memset(*(char **)ptrptr + (size * *countptr), 0, size * add); + *countptr += add; + } + return ret; +} + +/** + * virResizeN: + * @ptrptr: pointer to pointer for address of allocated memory + * @size: number of bytes per element + * @allocptr: pointer to number of elements allocated in array + * @count: number of elements currently used in array + * @add: minimum number of additional elements to support in array + * + * If 'count' + 'add' is larger than '*allocptr', then resize the + * block of memory in 'ptrptr' to be an array of at least 'count' + + * 'add' elements, each 'size' bytes in length. Update 'ptrptr' and + * 'allocptr' with the details of the newly allocated memory. On + * failure, 'ptrptr' and 'allocptr' are not changed. Any newly + * allocated memory in 'ptrptr' is zero-filled. + * + * Returns -1 on failure to allocate, zero on success + */ +int virResizeN(void *ptrptr, size_t size, size_t *allocptr, size_t count, + size_t add) +{ + size_t delta; + + if (count + add < count) { + errno = ENOMEM; + return -1; + } + if (count + add <= *allocptr) + return 0; + + delta = count + add - *allocptr; + if (delta < *allocptr / 2) + delta = *allocptr / 2; + return virExpandN(ptrptr, size, allocptr, delta); +} + +/** + * virShrinkN: + * @ptrptr: pointer to pointer for address of allocated memory + * @size: number of bytes per element + * @countptr: pointer to number of elements in array + * @toremove: number of elements to remove + * + * Resize the block of memory in 'ptrptr' to be an array of + * '*countptr' - 'toremove' elements, each 'size' bytes in length. + * Update 'ptrptr' and 'countptr' with the details of the newly + * allocated memory. If 'toremove' is larger than 'countptr', free + * the entire array. + */ +void virShrinkN(void *ptrptr, size_t size, size_t *countptr, size_t toremove) +{ + if (toremove < *countptr) + ignore_value(virReallocN(ptrptr, size, *countptr -= toremove)); + else { + virFree(ptrptr); + *countptr = 0; + } +} + +/** + * virInsertElementsN: + * @ptrptr: pointer to hold address of allocated memory + * @size: the size of one element in bytes + * @at: index within array where new elements should be added + * @countptr: variable tracking number of elements currently allocated + * @add: number of elements to add + * @newelems: pointer to array of one or more new elements to move into + * place (the originals will be zeroed out if successful + * and if clearOriginal is true) + * @clearOriginal: false if the new item in the array should be copied + * from the original, and the original left intact. + * true if the original should be 0'd out on success. + * @inPlace: false if we should expand the allocated memory before + * moving, true if we should assume someone else *has + * already* done that. + * + * Re-allocate an array of *countptr elements, each sizeof(*ptrptr) bytes + * long, to be *countptr+add elements long, then appropriately move + * the elements starting at ptrptr[at] up by add elements, copy the + * items from newelems into ptrptr[at], then store the address of + * allocated memory in *ptrptr and the new size in *countptr. If + * newelems is NULL, the new elements at ptrptr[at] are instead filled + * with zero. + * + * Returns -1 on failure, 0 on success + */ +int +virInsertElementsN(void *ptrptr, size_t size, size_t at, + size_t *countptr, + size_t add, void *newelems, + bool clearOriginal, bool inPlace) +{ + if (at > *countptr) { + VIR_WARN("out of bounds index - count %zu at %zu add %zu", + *countptr, at, add); + return -1; + } + + if (inPlace) { + *countptr += add; + } else if (virExpandN(ptrptr, size, countptr, add) < 0) { + return -1; + } + + /* memory was successfully re-allocated. Move up all elements from + * ptrptr[at] to the end (if we're not "inserting" at the end + * already), memcpy in the new elements, and clear the elements + * from their original location. Remember that *countptr has + * already been updated with new element count! + */ + if (at < *countptr - add) { + memmove(*(char**)ptrptr + (size * (at + add)), + *(char**)ptrptr + (size * at), + size * (*countptr - add - at)); + } + + if (newelems) { + memcpy(*(char**)ptrptr + (size * at), newelems, size * add); + if (clearOriginal) + memset((char*)newelems, 0, size * add); + } else if (inPlace || (at < *countptr - add)) { + /* NB: if inPlace, assume memory at the end wasn't initialized */ + memset(*(char**)ptrptr + (size * at), 0, size * add); + } + + return 0; +} + +/** + * virDeleteElementsN: + * @ptrptr: pointer to hold address of allocated memory + * @size: the size of one element in bytes + * @at: index within array where new elements should be deleted + * @countptr: variable tracking number of elements currently allocated + * @remove: number of elements to remove + * @inPlace: false if we should shrink the allocated memory when done, + * true if we should assume someone else will do that. + * + * Re-allocate an array of *countptr elements, each sizeof(*ptrptr) + * bytes long, to be *countptr-remove elements long, then store the + * address of allocated memory in *ptrptr and the new size in *countptr. + * If *countptr <= remove, the entire array is freed. + * + * Returns -1 on failure, 0 on success + */ +int +virDeleteElementsN(void *ptrptr, size_t size, size_t at, + size_t *countptr, size_t remove, + bool inPlace) +{ + if (at + remove > *countptr) { + VIR_WARN("out of bounds index - count %zu at %zu remove %zu", + *countptr, at, remove); + return -1; + } + + /* First move down the elements at the end that won't be deleted, + * then realloc. We assume that the items being deleted have + * already been cleared. + */ + memmove(*(char**)ptrptr + (size * at), + *(char**)ptrptr + (size * (at + remove)), + size * (*countptr - remove - at)); + if (inPlace) + *countptr -= remove; + else + virShrinkN(ptrptr, size, countptr, remove); + return 0; +} + +/** + * Vir_Alloc_Var: + * @ptrptr: pointer to hold address of allocated memory + * @struct_size: size of initial struct + * @element_size: size of array elements + * @count: number of array elements to allocate + * + * Allocate struct_size bytes plus an array of 'count' elements, each + * of size element_size. This sort of allocation is useful for + * receiving the data of certain ioctls and other APIs which return a + * struct in which the last element is an array of undefined length. + * The caller of this type of API is expected to know the length of + * the array that will be returned and allocate a suitable buffer to + * contain the returned data. C99 refers to these variable length + * objects as structs containing flexible array members. + * + * Returns -1 on failure, 0 on success + */ +int virAllocVar(void *ptrptr, size_t struct_size, size_t element_size, size_t count) +{ + size_t alloc_size = 0; + +#if TEST_OOM + if (virAllocTestFail()) + return -1; +#endif + + if (VIR_ALLOC_VAR_OVERSIZED(struct_size, count, element_size)) { + errno = ENOMEM; + return -1; + } + + alloc_size = struct_size + (element_size * count); + *(void **)ptrptr = calloc(1, alloc_size); + if (*(void **)ptrptr == NULL) + return -1; + 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) +{ + int save_errno = errno; + + free(*(void**)ptrptr); + *(void**)ptrptr = NULL; + errno = save_errno; +} diff --git a/src/util/viralloc.h b/src/util/viralloc.h new file mode 100644 index 0000000..8398105 --- /dev/null +++ b/src/util/viralloc.h @@ -0,0 +1,380 @@ +/* + * memory.c: safer memory allocation + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * 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, see + * <http://www.gnu.org/licenses/>. + * + */ + + +#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 + ATTRIBUTE_NONNULL(1); +int virAllocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK + ATTRIBUTE_NONNULL(1); +int virReallocN(void *ptrptr, size_t size, size_t count) ATTRIBUTE_RETURN_CHECK + ATTRIBUTE_NONNULL(1); +int virExpandN(void *ptrptr, size_t size, size_t *count, size_t add) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); +int virResizeN(void *ptrptr, size_t size, size_t *alloc, size_t count, + size_t desired) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); +void virShrinkN(void *ptrptr, size_t size, size_t *count, size_t toremove) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); +int virInsertElementsN(void *ptrptr, size_t size, size_t at, size_t *countptr, + size_t add, void *newelem, + bool clearOriginal, bool inPlace) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); +int virDeleteElementsN(void *ptrptr, size_t size, size_t at, size_t *countptr, + size_t remove, bool inPlace) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); +int virAllocVar(void *ptrptr, + size_t struct_size, + size_t element_size, + size_t count) ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1); +void virFree(void *ptrptr) ATTRIBUTE_NONNULL(1); + +/** + * 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'. If 'ptr' grew, the added memory is uninitialized. + * + * Returns -1 on failure, 0 on success + */ +# define VIR_REALLOC_N(ptr, count) virReallocN(&(ptr), sizeof(*(ptr)), (count)) + +/** + * VIR_EXPAND_N: + * @ptr: pointer to hold address of allocated memory + * @count: variable tracking number of elements currently allocated + * @add: number of elements to add + * + * Re-allocate an array of 'count' elements, each sizeof(*ptr) + * bytes long, to be 'count' + 'add' elements long, then store the + * address of allocated memory in 'ptr' and the new size in 'count'. + * The new elements are filled with zero. + * + * Returns -1 on failure, 0 on success + */ +# define VIR_EXPAND_N(ptr, count, add) \ + virExpandN(&(ptr), sizeof(*(ptr)), &(count), add) + +/** + * VIR_RESIZE_N: + * @ptr: pointer to hold address of allocated memory + * @alloc: variable tracking number of elements currently allocated + * @count: number of elements currently in use + * @add: minimum number of elements to additionally support + * + * Blindly using VIR_EXPAND_N(array, alloc, 1) in a loop scales + * quadratically, because every iteration must copy contents from + * all prior iterations. But amortized linear scaling can be achieved + * by tracking allocation size separately from the number of used + * elements, and growing geometrically only as needed. + * + * If 'count' + 'add' is larger than 'alloc', then geometrically reallocate + * the array of 'alloc' elements, each sizeof(*ptr) bytes long, and store + * the address of allocated memory in 'ptr' and the new size in 'alloc'. + * The new elements are filled with zero. + * + * Returns -1 on failure, 0 on success + */ +# define VIR_RESIZE_N(ptr, alloc, count, add) \ + virResizeN(&(ptr), sizeof(*(ptr)), &(alloc), count, add) + +/** + * VIR_SHRINK_N: + * @ptr: pointer to hold address of allocated memory + * @count: variable tracking number of elements currently allocated + * @remove: number of elements to remove + * + * Re-allocate an array of 'count' elements, each sizeof(*ptr) + * bytes long, to be 'count' - 'remove' elements long, then store the + * address of allocated memory in 'ptr' and the new size in 'count'. + * If 'count' <= 'remove', the entire array is freed. + * + * No return value. + */ +# define VIR_SHRINK_N(ptr, count, remove) \ + virShrinkN(&(ptr), sizeof(*(ptr)), &(count), remove) + +/* + * VIR_TYPEMATCH: + * + * The following macro seems a bit cryptic, so it needs a thorough + * explanation. Its purpose is to check for assignment compatibility + * and identical size between two values without creating any side + * effects (by doing something silly like actually assigning one to + * the other). Note that it takes advantage of the C89-guaranteed + * property of sizeof() - it cannot have any side effects, so anything + * that happens inside sizeof() will not have any effect at runtime. + * + * VIR_TYPEMATCH evaluates to "1" if the two passed values are both + * assignment-compatible and the same size, and otherwise generates a + * compile-time error. It determines the result by performing the + * following three operations: + * + * * sizeof(*(a) = *(b)) assures that *a and *b are + * assignment-compatible (they may still have a different size + * though! e.g. longVar = intVar) (If not, there is a compile-time + * error. If so, the result of that subexpression is sizeof(*(a)), + * i.e. one element of the array) + * + * * sizeof(*(a) = *(b)) == sizeof(*(b)) checks if *a and *b are also + * of the same size (so that, e.g. you don't accidentally copy an + * int plus the random bytes following it into an array of long). It + * evaluates to 1 if they are the same, and 0 otherwise. + * + * * sizeof(char[2 * (result of previous step) - 1]) evaluates to 1 + * if the previous step was successful (char [(2*1) - 1] i.e. + * char[1]), or generates a compile error if it wasn't successful + * (char[2*0 -1] i.e. char[-1], which isn't valid in C). + * + * So VIR_TYPECHECK(a, b) will either abort the compile with an error, + * or evaluate to "1", and in the meantime check that we've actually + * added the correct &'s and/or *'s to the arguments. (Whew!) +*/ +# define VIR_TYPEMATCH(a, b) \ + sizeof(char[2 * (sizeof(*(a) = *(b)) == sizeof(*(b))) - 1]) + +/** + * VIR_INSERT_ELEMENT: + * @ptr: pointer to array of objects (*not* ptr to ptr) + * @at: index within array where new elements should be added + * @count: variable tracking number of elements currently allocated + * @newelem: the new element to move into place (*not* a pointer to + * the element, but the element itself). + * (the original will be zeroed out if successful) + * + * Re-allocate an array of 'count' elements, each sizeof(*ptr) bytes + * long, to be 'count' + 1 elements long, then appropriately move + * the elements starting at ptr[at] up by 1 element, copy the + * item 'newelem' into ptr[at], then store the address of + * allocated memory in 'ptr' and the new size in 'count'. + * + * VIR_INSERT_ELEMENT_COPY is identical, but doesn't clear out the + * original element to 0 on success, so there are two copies of the + * element. This is useful if the "element" is actually just a + * pointer to the real data, and you want to maintain a reference to + * it for use after the insert is completed; but if the "element" is + * an object that points to other allocated memory, having multiple + * copies can cause problems (e.g. double free). + * + * VIR_INSERT_ELEMENT_*INPLACE are identical, but assume any necessary + * memory re-allocation has already been done. + * + * VIR_INSERT_ELEMENT_* all need to send "1" as the "add" argument to + * virInsertElementsN (which has the currently-unused capability of + * inserting multiple items at once). We use this to our advantage by + * replacing it with VIR_TYPECHECK(ptr, &newelem) so that we can be + * assured ptr and &newelem are of compatible types. + * + * Returns -1 on failure, 0 on success + * + * + */ +# define VIR_INSERT_ELEMENT(ptr, at, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, false) +# define VIR_INSERT_ELEMENT_COPY(ptr, at, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, false) +# define VIR_INSERT_ELEMENT_INPLACE(ptr, at, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, true) +# define VIR_INSERT_ELEMENT_COPY_INPLACE(ptr, at, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), at, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, true) + +/** + * VIR_APPEND_ELEMENT: + * @ptr: pointer to array of objects (*not* ptr to ptr) + * @count: variable tracking number of elements currently allocated + * @newelem: the new element to move into place (*not* a pointer to + * the element, but the element itself). + * (the original will be zeroed out if successful) + * + * Re-allocate an array of 'count' elements, each sizeof(*ptr) bytes + * long, to be 'count' + 1 elements long, then copy the item from + * 'newelem' into ptr[count+1], and store the address of allocated + * memory in 'ptr' and the new size in 'count'. If 'newelem' is NULL, + * the new element at ptr[at] is instead filled with zero. + * + * VIR_APPEND_ELEMENT_COPY is identical, but doesn't clear out the + * original element to 0 on success, so there are two copies of the + * element. This is useful if the "element" is actually just a + * pointer to the real data, and you want to maintain a reference to + * it for use after the append is completed; but if the "element" is + * an object that points to other allocated memory, having multiple + * copies can cause problems (e.g. double free). + * + * VIR_APPEND_ELEMENT_*INPLACE are identical, but assume any + * necessary memory re-allocation has already been done. + * + * VIR_APPEND_ELEMENT_* all need to send "1" as the "add" argument to + * virInsertElementsN (which has the currently-unused capability of + * inserting multiple items at once). We use this to our advantage by + * replacing it with VIR_TYPECHECK(ptr, &newelem) so that we can be + * assured ptr and &newelem are of compatible types. + * + * Returns -1 on failure, 0 on success + * + * + */ +# define VIR_APPEND_ELEMENT(ptr, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, false) +# define VIR_APPEND_ELEMENT_COPY(ptr, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, false) +# define VIR_APPEND_ELEMENT_INPLACE(ptr, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), true, true) +# define VIR_APPEND_ELEMENT_COPY_INPLACE(ptr, count, newelem) \ + virInsertElementsN(&(ptr), sizeof(*(ptr)), count, &(count), \ + VIR_TYPEMATCH(ptr, &(newelem)), &(newelem), false, true) + +/** + * VIR_DELETE_ELEMENT: + * @ptr: pointer to array of objects (*not* ptr to ptr) + * @at: index within array where new elements should be deleted + * @count: variable tracking number of elements currently allocated + * + * Re-allocate an array of 'count' elements, each sizeof(*ptr) + * bytes long, to be 'count' - 1 elements long, then store the + * address of allocated memory in 'ptr' and the new size in 'count'. + * If 'count' <= 1, the entire array is freed. + * + * VIR_DELETE_ELEMENT_INPLACE is identical, but assumes any + * necessary memory re-allocation will be done later. + * + * Returns -1 on failure, 0 on success + */ +# define VIR_DELETE_ELEMENT(ptr, at, count) \ + virDeleteElementsN(&(ptr), sizeof(*(ptr)), at, &(count), 1, false) +# define VIR_DELETE_ELEMENT_INPLACE(ptr, at, count) \ + virDeleteElementsN(&(ptr), sizeof(*(ptr)), at, &(count), 1, true) + +/* + * VIR_ALLOC_VAR_OVERSIZED: + * @M: size of base structure + * @N: number of array elements in trailing array + * @S: size of trailing array elements + * + * Check to make sure that the requested allocation will not cause + * arithmetic overflow in the allocation size. The check is + * essentially the same as that in gnulib's xalloc_oversized. + */ +# define VIR_ALLOC_VAR_OVERSIZED(M, N, S) ((((size_t)-1) - (M)) / (S) < (N)) + +/** + * VIR_ALLOC_VAR: + * @ptr: pointer to hold address of allocated memory + * @type: element type of trailing array + * @count: number of array elements to allocate + * + * Allocate sizeof(*ptr) bytes plus an array of 'count' elements, each + * sizeof('type'). This sort of allocation is useful for receiving + * the data of certain ioctls and other APIs which return a struct in + * which the last element is an array of undefined length. The caller + * of this type of API is expected to know the length of the array + * that will be returned and allocate a suitable buffer to contain the + * returned data. C99 refers to these variable length objects as + * structs containing flexible array members. + + * Returns -1 on failure, 0 on success + */ +# define VIR_ALLOC_VAR(ptr, type, count) \ + virAllocVar(&(ptr), sizeof(*(ptr)), sizeof(type), (count)) + +/** + * VIR_FREE: + * @ptr: pointer holding address to be freed + * + * Free the memory stored in 'ptr' and update to point + * to NULL. + */ +/* The ternary ensures that ptr is a pointer and not an integer type, + * while evaluating ptr only once. For now, we intentionally cast + * away const, since a number of callers safely pass const char *. + */ +# define VIR_FREE(ptr) virFree((void *) (1 ? (const void *) &(ptr) : (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/viraudit.c b/src/util/viraudit.c index c4e0129..a807b76 100644 --- a/src/util/viraudit.c +++ b/src/util/viraudit.c @@ -32,7 +32,7 @@ #include "viraudit.h" #include "util.h" #include "virfile.h" -#include "memory.h" +#include "viralloc.h" /* Provide the macros in case the header file is old. FIXME: should be removed. */ diff --git a/src/util/virauth.c b/src/util/virauth.c index a1bad6a..c4c5676 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -26,7 +26,7 @@ #include "virauth.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "datatypes.h" #include "virterror_internal.h" diff --git a/src/util/virauthconfig.c b/src/util/virauthconfig.c index 46ba040..a0f0be5 100644 --- a/src/util/virauthconfig.c +++ b/src/util/virauthconfig.c @@ -25,7 +25,7 @@ #include "virauthconfig.h" #include "virkeyfile.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index 41b74d4..cb9606b 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -31,7 +31,7 @@ #include <sys/types.h> #include "virbitmap.h" -#include "memory.h" +#include "viralloc.h" #include "virbuffer.h" #include "util.h" #include "c-ctype.h" diff --git a/src/util/virbuffer.c b/src/util/virbuffer.c index e4409c6..6fcb7d6 100644 --- a/src/util/virbuffer.c +++ b/src/util/virbuffer.c @@ -31,7 +31,7 @@ #define __VIR_BUFFER_C__ #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" /* If adding more fields, ensure to edit buf.h to match diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index 82e6613..5c628cc 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -39,7 +39,7 @@ #include "internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "vircgroup.h" #include "virlog.h" #include "virfile.h" diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 7bed04e..6e17a8d 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -34,7 +34,7 @@ #endif #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "util.h" #include "virlog.h" diff --git a/src/util/virconf.c b/src/util/virconf.c index c12a0bb..2f6d60e 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -36,7 +36,7 @@ #include "util.h" #include "c-ctype.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_CONF diff --git a/src/util/virdbus.c b/src/util/virdbus.c index b6c6642..34c46b2 100644 --- a/src/util/virdbus.c +++ b/src/util/virdbus.c @@ -22,7 +22,7 @@ #include <config.h> #include "virdbus.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "threads.h" diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c index 7bb42fc..918610a 100644 --- a/src/util/virdnsmasq.c +++ b/src/util/virdnsmasq.c @@ -43,7 +43,7 @@ #include "virdnsmasq.h" #include "util.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" diff --git a/src/util/virebtables.c b/src/util/virebtables.c index 8333c38..1beb085 100644 --- a/src/util/virebtables.c +++ b/src/util/virebtables.c @@ -42,7 +42,7 @@ #include "internal.h" #include "virebtables.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "threads.h" diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index 0256d83..cf4dc41 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -34,7 +34,7 @@ #include "threads.h" #include "virlog.h" #include "vireventpoll.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "virterror_internal.h" diff --git a/src/util/virfile.c b/src/util/virfile.c index 30294a2..f20ce64 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -39,7 +39,7 @@ #include "vircommand.h" #include "configmake.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/util/virhash.c b/src/util/virhash.c index 077abca..a1234c4 100644 --- a/src/util/virhash.c +++ b/src/util/virhash.c @@ -26,7 +26,7 @@ #include "virterror_internal.h" #include "virhash.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virhashcode.h" #include "virrandom.h" diff --git a/src/util/virhooks.c b/src/util/virhooks.c index 2e8ecf2..ad3a371 100644 --- a/src/util/virhooks.c +++ b/src/util/virhooks.c @@ -34,7 +34,7 @@ #include "virhooks.h" #include "util.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #include "configmake.h" #include "vircommand.h" diff --git a/src/util/virinitctl.c b/src/util/virinitctl.c index e8949af..91a948f 100644 --- a/src/util/virinitctl.c +++ b/src/util/virinitctl.c @@ -30,7 +30,7 @@ #include "virinitctl.h" #include "virterror_internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_INITCTL diff --git a/src/util/viriptables.c b/src/util/viriptables.c index ee3e9a0..178580d 100644 --- a/src/util/viriptables.c +++ b/src/util/viriptables.c @@ -40,7 +40,7 @@ #include "internal.h" #include "viriptables.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "threads.h" diff --git a/src/util/virjson.c b/src/util/virjson.c index 18a28ba..4fa5363 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -24,7 +24,7 @@ #include <config.h> #include "virjson.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" #include "util.h" diff --git a/src/util/virkeyfile.c b/src/util/virkeyfile.c index b43b92d..fc61cf5 100644 --- a/src/util/virkeyfile.c +++ b/src/util/virkeyfile.c @@ -27,7 +27,7 @@ #include "c-ctype.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virhash.h" #include "virkeyfile.h" diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c index b652294..509b162 100644 --- a/src/util/virlockspace.c +++ b/src/util/virlockspace.c @@ -23,7 +23,7 @@ #include "virlockspace.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "util.h" #include "virfile.h" diff --git a/src/util/virlog.c b/src/util/virlog.c index d179de2..cb15a22 100644 --- a/src/util/virlog.c +++ b/src/util/virlog.c @@ -42,7 +42,7 @@ #include "virterror_internal.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virbuffer.h" #include "threads.h" diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index a1d1c12..88a2e4b 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -27,7 +27,7 @@ #include "virfile.h" #include "virterror_internal.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "pci.h" #include "virlog.h" diff --git a/src/util/virnetdevbandwidth.c b/src/util/virnetdevbandwidth.c index bd75a9d..9cc8858 100644 --- a/src/util/virnetdevbandwidth.c +++ b/src/util/virnetdevbandwidth.c @@ -24,7 +24,7 @@ #include "virnetdevbandwidth.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index 2c4a9eb..eb341a2 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -26,7 +26,7 @@ #include "virterror_internal.h" #include "util.h" #include "virfile.h" -#include "memory.h" +#include "viralloc.h" #include "intprops.h" #include <sys/ioctl.h> diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 8d2574c..0f7107b 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -56,7 +56,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST, # define MACVLAN_MODE_PASSTHRU 8 # endif -# include "memory.h" +# include "viralloc.h" # include "virlog.h" # include "uuid.h" # include "virfile.h" diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c index 983a240..b876a4e 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -25,7 +25,7 @@ #include "virnetdevopenvswitch.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #include "virmacaddr.h" diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 644e9a4..339d636 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "virfile.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "util.h" diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c index 630b7c9..c6568b7 100644 --- a/src/util/virnetdevveth.c +++ b/src/util/virnetdevveth.c @@ -26,7 +26,7 @@ #include <sys/wait.h> #include "virnetdevveth.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "vircommand.h" #include "virterror_internal.h" diff --git a/src/util/virnetdevvlan.c b/src/util/virnetdevvlan.c index 7a6ff9b..53c6b65 100644 --- a/src/util/virnetdevvlan.c +++ b/src/util/virnetdevvlan.c @@ -24,7 +24,7 @@ #include "internal.h" #include "virterror_internal.h" #include "virnetdevvlan.h" -#include "memory.h" +#include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index 834b9b9..60acabd 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -24,7 +24,7 @@ #include "virnetdevvportprofile.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_NET diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index 830e9b9..b132d9a 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -37,7 +37,7 @@ #include "virnetlink.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "virmacaddr.h" #include "virterror_internal.h" diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c index e37a2d6..1528cf1 100644 --- a/src/util/virnodesuspend.c +++ b/src/util/virnodesuspend.c @@ -26,7 +26,7 @@ #include "threads.h" #include "datatypes.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/util/virobject.c b/src/util/virobject.c index aa80cab..5cdd2e8 100644 --- a/src/util/virobject.c +++ b/src/util/virobject.c @@ -23,7 +23,7 @@ #include "virobject.h" #include "threads.h" -#include "memory.h" +#include "viralloc.h" #include "viratomic.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/util/virpidfile.c b/src/util/virpidfile.c index 6ec9760..3b3322b 100644 --- a/src/util/virpidfile.c +++ b/src/util/virpidfile.c @@ -29,7 +29,7 @@ #include "virpidfile.h" #include "virfile.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "intprops.h" #include "virlog.h" diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 3c0ed8a..8070b8b 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -28,7 +28,7 @@ #include "virprocess.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "util.h" diff --git a/src/util/virstring.c b/src/util/virstring.c index 228c3fb..5607b3e 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -22,7 +22,7 @@ #include <config.h> #include "virstring.h" -#include "memory.h" +#include "viralloc.h" #include "virbuffer.h" #include "virterror_internal.h" diff --git a/src/util/virterror.c b/src/util/virterror.c index 6e3301b..ce2d837 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "util.h" diff --git a/src/util/virtime.c b/src/util/virtime.c index a2610c4..f9fc282 100644 --- a/src/util/virtime.c +++ b/src/util/virtime.c @@ -38,7 +38,7 @@ #include "virtime.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index 7f0a44b..e08530e 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -24,7 +24,7 @@ #include <stdarg.h> -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virterror_internal.h" diff --git a/src/util/viruri.c b/src/util/viruri.c index dd3b878..f48079d 100644 --- a/src/util/viruri.c +++ b/src/util/viruri.c @@ -22,7 +22,7 @@ #include "viruri.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virterror_internal.h" #include "virbuffer.h" diff --git a/src/util/virusb.c b/src/util/virusb.c index ebc1af5..9786e86 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -33,7 +33,7 @@ #include "virusb.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virterror_internal.h" diff --git a/src/util/xml.c b/src/util/xml.c index 5b08b1f..caf26a3 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -34,7 +34,7 @@ #include "xml.h" #include "virbuffer.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_XML diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index 3194b7c..cab4398 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -30,7 +30,7 @@ #define nsCID CLSID #include "internal.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 5f70283..5296127 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -37,7 +37,7 @@ #include "vbox_XPCOMCGlue.h" #include "internal.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 847af35..daa90bf 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -50,7 +50,7 @@ #include "storage_conf.h" #include "storage_file.h" #include "uuid.h" -#include "memory.h" +#include "viralloc.h" #include "nodeinfo.h" #include "virlog.h" #include "vbox_driver.h" diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c index b32de66..7cf9bcc 100644 --- a/src/vmware/vmware_conf.c +++ b/src/vmware/vmware_conf.c @@ -27,7 +27,7 @@ #include "vircommand.h" #include "cpu/cpu.h" #include "dirname.h" -#include "memory.h" +#include "viralloc.h" #include "nodeinfo.h" #include "virfile.h" #include "uuid.h" diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index d9a1333..233804e 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virfile.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "uuid.h" #include "vircommand.h" diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index e74e9ed..90496ce 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -28,7 +28,7 @@ #include "internal.h" #include "virterror_internal.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "vmx.h" diff --git a/src/xen/block_stats.c b/src/xen/block_stats.c index e50b5ff..126283b 100644 --- a/src/xen/block_stats.c +++ b/src/xen/block_stats.c @@ -42,7 +42,7 @@ # include "datatypes.h" # include "util.h" # include "block_stats.h" -# include "memory.h" +# include "viralloc.h" # include "virfile.h" # define VIR_FROM_THIS VIR_FROM_STATS_LINUX diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index c281c00..94df116 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -55,7 +55,7 @@ #endif #include "xml.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "node_device_conf.h" #include "pci.h" #include "uuid.h" diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index b094313..598ec5e 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -76,7 +76,7 @@ #include "xend_internal.h" #include "virbuffer.h" #include "capabilities.h" -#include "memory.h" +#include "viralloc.h" #include "threads.h" #include "virfile.h" #include "virnodesuspend.h" diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 073663f..35a625c 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "driver.h" -#include "memory.h" +#include "viralloc.h" #include "xen_driver.h" #include "virconf.h" #include "domain_conf.h" diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 0364f84..a4005f4 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -42,7 +42,7 @@ #include "xen_driver.h" #include "xen_hypervisor.h" #include "xs_internal.h" /* To extract VNC port & Serial console TTY */ -#include "memory.h" +#include "viralloc.h" #include "count-one-bits.h" #include "virfile.h" #include "viruri.h" diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index fc7b581..2109972 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -46,7 +46,7 @@ #include "virbuffer.h" #include "uuid.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "count-one-bits.h" diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index 4cc82d8..e414966 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -44,7 +44,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "driver.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "uuid.h" #include "xen_driver.h" diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index f00dcfd..0a0ac0e 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -33,7 +33,7 @@ #include "virauth.h" #include "util.h" #include "uuid.h" -#include "memory.h" +#include "viralloc.h" #include "virbuffer.h" #include "viruri.h" #include "xenapi_driver.h" diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 6f51100..33aa4d7 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -31,7 +31,7 @@ #include "datatypes.h" #include "util.h" #include "uuid.h" -#include "memory.h" +#include "viralloc.h" #include "virbuffer.h" #include "virlog.h" #include "viruri.h" diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index 2aa384d..0cbc248 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -29,7 +29,7 @@ #include "internal.h" #include "virterror_internal.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "verify.h" #include "uuid.h" #include "virlog.h" diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index 7bde7ab..7d67bbe 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -28,7 +28,7 @@ #include "internal.h" #include "virterror_internal.h" #include "virconf.h" -#include "memory.h" +#include "viralloc.h" #include "verify.h" #include "uuid.h" #include "sexpr.h" diff --git a/tests/commandhelper.c b/tests/commandhelper.c index 2100aa0..3c7fef5 100644 --- a/tests/commandhelper.c +++ b/tests/commandhelper.c @@ -28,7 +28,7 @@ #include "internal.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #include "testutils.h" diff --git a/tests/commandtest.c b/tests/commandtest.c index f76bc54..b15c168 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -32,7 +32,7 @@ #include "internal.h" #include "nodeinfo.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "vircommand.h" #include "virfile.h" #include "virpidfile.h" diff --git a/tests/conftest.c b/tests/conftest.c index aacc526..d5467e8 100644 --- a/tests/conftest.c +++ b/tests/conftest.c @@ -6,7 +6,7 @@ #include <string.h> #include <errno.h> #include "virconf.h" -#include "memory.h" +#include "viralloc.h" int main(int argc, char **argv) { diff --git a/tests/cputest.c b/tests/cputest.c index f6110c1..ee1a608 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -32,7 +32,7 @@ #include "internal.h" #include "xml.h" -#include "memory.h" +#include "viralloc.h" #include "virbuffer.h" #include "testutils.h" #include "cpu_conf.h" diff --git a/tests/esxutilstest.c b/tests/esxutilstest.c index 201b930..b65009b 100644 --- a/tests/esxutilstest.c +++ b/tests/esxutilstest.c @@ -7,7 +7,7 @@ # include <unistd.h> # include "internal.h" -# include "memory.h" +# include "viralloc.h" # include "testutils.h" # include "util.h" # include "vmx/vmx.h" diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c index dc0e064..3979540 100644 --- a/tests/networkxml2conftest.c +++ b/tests/networkxml2conftest.c @@ -12,7 +12,7 @@ #include "testutils.h" #include "network_conf.h" #include "vircommand.h" -#include "memory.h" +#include "viralloc.h" #include "network/bridge_driver.h" static int diff --git a/tests/openvzutilstest.c b/tests/openvzutilstest.c index 305c7b1..80701a2 100644 --- a/tests/openvzutilstest.c +++ b/tests/openvzutilstest.c @@ -7,7 +7,7 @@ # include <unistd.h> # include "internal.h" -# include "memory.h" +# include "viralloc.h" # include "testutils.h" # include "util.h" # include "openvz/openvz_conf.h" diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index caa7d64..252ad3a 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -7,7 +7,7 @@ # include "testutils.h" # include "qemu/qemu_capabilities.h" -# include "memory.h" +# include "viralloc.h" struct testInfo { const char *name; diff --git a/tests/qemumonitortest.c b/tests/qemumonitortest.c index 82f861b..21a6828 100644 --- a/tests/qemumonitortest.c +++ b/tests/qemumonitortest.c @@ -8,7 +8,7 @@ #ifdef WITH_QEMU # include "internal.h" -# include "memory.h" +# include "viralloc.h" # include "testutils.h" # include "util.h" # include "qemu/qemu_monitor.h" diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index e4194de..1e3f0da 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -29,7 +29,7 @@ #include "threads.h" #include "qemu/qemu_monitor.h" #include "rpc/virnetsocket.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 1816362..27f3029 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -12,7 +12,7 @@ # include "internal.h" # include "testutils.h" -# include "util/memory.h" +# include "viralloc.h" # include "qemu/qemu_capabilities.h" # include "qemu/qemu_command.h" # include "qemu/qemu_domain.h" diff --git a/tests/securityselinuxtest.c b/tests/securityselinuxtest.c index c021480..045c9c0 100644 --- a/tests/securityselinuxtest.c +++ b/tests/securityselinuxtest.c @@ -30,7 +30,7 @@ #include "internal.h" #include "testutils.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/tests/sockettest.c b/tests/sockettest.c index c6a175f..156ef45 100644 --- a/tests/sockettest.c +++ b/tests/sockettest.c @@ -28,7 +28,7 @@ #include "virsocketaddr.h" #include "testutils.h" #include "virlog.h" -#include "memory.h" +#include "viralloc.h" static void testQuietError(void *userData ATTRIBUTE_UNUSED, virErrorPtr error ATTRIBUTE_UNUSED) diff --git a/tests/testutils.c b/tests/testutils.c index 96e24d4..7bb88f0 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -39,7 +39,7 @@ #include <limits.h> #include "testutils.h" #include "internal.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "threads.h" #include "virterror_internal.h" diff --git a/tests/testutils.h b/tests/testutils.h index 82837ab..581bd3e 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -24,7 +24,7 @@ # define __VIT_TEST_UTILS_H__ # include <stdio.h> -# include "memory.h" +# include "viralloc.h" # define EXIT_AM_SKIP 77 /* tell Automake we're skipping a test */ # define EXIT_AM_HARDFAIL 99 /* tell Automake that the framework is broken */ diff --git a/tests/testutilslxc.c b/tests/testutilslxc.c index 822e518..384414b 100644 --- a/tests/testutilslxc.c +++ b/tests/testutilslxc.c @@ -4,7 +4,7 @@ # include "testutilslxc.h" # include "testutils.h" -# include "memory.h" +# include "viralloc.h" # include "domain_conf.h" diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 4ff4a08..8ee3a27 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -4,7 +4,7 @@ # include "testutilsqemu.h" # include "testutils.h" -# include "memory.h" +# include "viralloc.h" # include "cpu_conf.h" # include "qemu/qemu_driver.h" # include "qemu/qemu_domain.h" diff --git a/tests/utiltest.c b/tests/utiltest.c index 774a2f7..4fbb25c 100644 --- a/tests/utiltest.c +++ b/tests/utiltest.c @@ -6,7 +6,7 @@ #include <unistd.h> #include "internal.h" -#include "memory.h" +#include "viralloc.h" #include "testutils.h" #include "util.h" diff --git a/tests/virauthconfigtest.c b/tests/virauthconfigtest.c index 74cc187..9e7dac5 100644 --- a/tests/virauthconfigtest.c +++ b/tests/virauthconfigtest.c @@ -26,7 +26,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virauthconfig.h" diff --git a/tests/virbuftest.c b/tests/virbuftest.c index 53b9bbe..ec93939 100644 --- a/tests/virbuftest.c +++ b/tests/virbuftest.c @@ -8,7 +8,7 @@ #include "util.h" #include "testutils.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #define TEST_ERROR(...) \ do { \ diff --git a/tests/virdrivermoduletest.c b/tests/virdrivermoduletest.c index 440ee8e..e06179f 100644 --- a/tests/virdrivermoduletest.c +++ b/tests/virdrivermoduletest.c @@ -23,7 +23,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "driver.h" diff --git a/tests/virhashtest.c b/tests/virhashtest.c index 7de16d0..a2a40c6 100644 --- a/tests/virhashtest.c +++ b/tests/virhashtest.c @@ -9,7 +9,7 @@ #include "virhash.h" #include "virhashdata.h" #include "testutils.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virlog.h" diff --git a/tests/virkeyfiletest.c b/tests/virkeyfiletest.c index c6aca86..ad5a516 100644 --- a/tests/virkeyfiletest.c +++ b/tests/virkeyfiletest.c @@ -26,7 +26,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virkeyfile.h" diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c index c95f5d8..80478d9 100644 --- a/tests/virlockspacetest.c +++ b/tests/virlockspacetest.c @@ -27,7 +27,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virlockspace.h" diff --git a/tests/virnetmessagetest.c b/tests/virnetmessagetest.c index c20f5e6..e3517e8 100644 --- a/tests/virnetmessagetest.c +++ b/tests/virnetmessagetest.c @@ -26,7 +26,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "rpc/virnetmessage.h" diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index ba281e9..399c4fd 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -30,7 +30,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c index 0236659..27078ea 100644 --- a/tests/virnettlscontexttest.c +++ b/tests/virnettlscontexttest.c @@ -29,7 +29,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virfile.h" #include "vircommand.h" diff --git a/tests/virstringtest.c b/tests/virstringtest.c index 27e490f..a8f4c79 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -25,7 +25,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virstring.h" diff --git a/tests/virtimetest.c b/tests/virtimetest.c index c8e9a2e..7d7a2d6 100644 --- a/tests/virtimetest.c +++ b/tests/virtimetest.c @@ -26,7 +26,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "virtime.h" diff --git a/tests/viruritest.c b/tests/viruritest.c index 46964b3..57d3895 100644 --- a/tests/viruritest.c +++ b/tests/viruritest.c @@ -26,7 +26,7 @@ #include "testutils.h" #include "util.h" #include "virterror_internal.h" -#include "memory.h" +#include "viralloc.h" #include "virlog.h" #include "viruri.h" diff --git a/tests/vmx2xmltest.c b/tests/vmx2xmltest.c index e523d1c..712536b 100644 --- a/tests/vmx2xmltest.c +++ b/tests/vmx2xmltest.c @@ -7,7 +7,7 @@ # include <unistd.h> # include "internal.h" -# include "memory.h" +# include "viralloc.h" # include "testutils.h" # include "vmx/vmx.h" diff --git a/tests/xmconfigtest.c b/tests/xmconfigtest.c index 3de68fd..a3943e2 100644 --- a/tests/xmconfigtest.c +++ b/tests/xmconfigtest.c @@ -34,7 +34,7 @@ #include "xenxs/xen_xm.h" #include "testutils.h" #include "testutilsxen.h" -#include "memory.h" +#include "viralloc.h" static virCapsPtr caps; diff --git a/tests/xml2vmxtest.c b/tests/xml2vmxtest.c index 94dfcf2..17af6a4 100644 --- a/tests/xml2vmxtest.c +++ b/tests/xml2vmxtest.c @@ -7,7 +7,7 @@ # include <unistd.h> # include "internal.h" -# include "memory.h" +# include "viralloc.h" # include "testutils.h" # include "vmx/vmx.h" diff --git a/tools/console.c b/tools/console.c index dbdaab7..1d21189 100644 --- a/tools/console.c +++ b/tools/console.c @@ -41,7 +41,7 @@ # include "virlog.h" # include "util.h" # include "virfile.h" -# include "memory.h" +# include "viralloc.h" # include "threads.h" # include "virterror_internal.h" diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 0006c11..a443988 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -34,7 +34,7 @@ #include "internal.h" #include "conf/domain_conf.h" #include "intprops.h" -#include "memory.h" +#include "viralloc.h" #include "virmacaddr.h" #include "virsh-domain.h" #include "xml.h" diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 76d9d51..b0b0c94 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -42,7 +42,7 @@ #include "c-ctype.h" #include "conf/domain_conf.h" #include "console.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "virkeycode.h" diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 6f129d1..2d59a75 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virsh-domain.h" #include "xml.h" diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index 956fee8..40216c6 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-network.c b/tools/virsh-network.c index c5d494a..66ee7e3 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "xml.h" #include "conf/network_conf.h" diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 52cd874..7e569b3 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "xml.h" #include "conf/node_device_conf.h" diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index 3108d1b..c3dba0c 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 4a78467..6e29604 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "xml.h" #include "conf/storage_conf.h" diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index ee79b97..d81e8ce 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -34,7 +34,7 @@ #include "internal.h" #include "base64.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "xml.h" diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index d6a381d..3fecde6 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -35,7 +35,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virsh-domain.h" #include "xml.h" diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 1bad6b1..ebfe52d 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -35,7 +35,7 @@ #include "internal.h" #include "virbuffer.h" -#include "memory.h" +#include "viralloc.h" #include "util.h" #include "virfile.h" #include "virsh-pool.h" diff --git a/tools/virsh.c b/tools/virsh.c index 5cb2e06..e894aff 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -59,7 +59,7 @@ #include "virbuffer.h" #include "console.h" #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "xml.h" #include "libvirt/libvirt-qemu.h" #include "virfile.h" diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c index 5bbb5e9..cd75eba 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -28,7 +28,7 @@ #include <sys/utsname.h> #include "util.h" -#include "memory.h" +#include "viralloc.h" #include "virfile.h" #include "virt-host-validate-common.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/conf/node_device_conf.c | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_hal.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/qemu/qemu_conf.h | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_selinux.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/util/pci.c | 2285 ------------------------------------ src/util/pci.h | 136 --- src/util/virnetdev.c | 2 +- src/util/virnetdev.h | 2 +- src/util/virpci.c | 2285 ++++++++++++++++++++++++++++++++++++ src/util/virpci.h | 136 +++ src/xen/xen_driver.c | 2 +- 21 files changed, 2438 insertions(+), 2438 deletions(-) delete mode 100644 src/util/pci.c delete mode 100644 src/util/pci.h create mode 100644 src/util/virpci.c create mode 100644 src/util/virpci.h diff --git a/po/POTFILES.in b/po/POTFILES.in index a9dfcf4..18db09b 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/pci.c src/util/processinfo.c src/util/sexpr.c src/util/stats_linux.c @@ -171,6 +170,7 @@ src/util/virnetdevtap.c src/util/virnetdevvportprofile.c src/util/virnetlink.c src/util/virnodesuspend.c +src/util/virpci.c src/util/virpidfile.c src/util/virprocess.c src/util/virrandom.c diff --git a/src/Makefile.am b/src/Makefile.am index 64f117d..d9f621f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/pci.c util/pci.h \ util/processinfo.c util/processinfo.h \ util/sexpr.c util/sexpr.h \ util/stats_linux.c util/stats_linux.h \ @@ -85,6 +84,7 @@ UTIL_SOURCES = \ util/virjson.c util/virjson.h \ util/virlog.c util/virlog.h \ util/virobject.c util/virobject.h \ + util/virpci.c util/virpci.h \ util/virpidfile.c util/virpidfile.h \ util/virprocess.c util/virprocess.h \ util/virtypedparam.c util/virtypedparam.h \ diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 85de50f..045f05d 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -36,7 +36,7 @@ #include "util.h" #include "virbuffer.h" #include "uuid.h" -#include "pci.h" +#include "virpci.h" #include "virrandom.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 52b36a1..2db9197 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -61,7 +61,7 @@ #include "virdnsmasq.h" #include "configmake.h" #include "virnetdev.h" -#include "pci.h" +#include "virpci.h" #include "virnetdevbridge.h" #include "virnetdevtap.h" #include "virnetdevvportprofile.h" diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 6f89f16..257a363 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -35,7 +35,7 @@ #include "datatypes.h" #include "viralloc.h" #include "uuid.h" -#include "pci.h" +#include "virpci.h" #include "virlog.h" #include "node_device_driver.h" #include "virdbus.h" diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 81a11d7..7289a72 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -37,7 +37,7 @@ #include "uuid.h" #include "util.h" #include "virbuffer.h" -#include "pci.h" +#include "virpci.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 283251a..f928c29 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -35,7 +35,7 @@ # include "threads.h" # include "security/security_manager.h" # include "vircgroup.h" -# include "pci.h" +# include "virpci.h" # include "virusb.h" # include "cpu_conf.h" # include "driver.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 65254b6..14a5e44 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -72,7 +72,7 @@ #include "domain_conf.h" #include "domain_audit.h" #include "node_device_conf.h" -#include "pci.h" +#include "virpci.h" #include "virusb.h" #include "processinfo.h" #include "libvirt_internal.h" diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 754f8d0..5c23ccb 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -27,7 +27,7 @@ #include "virlog.h" #include "virterror_internal.h" #include "viralloc.h" -#include "pci.h" +#include "virpci.h" #include "virusb.h" #include "virnetdev.h" diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index c432a32..e120988 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -36,7 +36,7 @@ #include "datatypes.h" #include "virterror_internal.h" #include "viralloc.h" -#include "pci.h" +#include "virpci.h" #include "virfile.h" #include "qemu_cgroup.h" #include "locking/domain_lock.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index b65384e..d28189f 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -43,7 +43,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "uuid.h" -#include "pci.h" +#include "virpci.h" #include "virusb.h" #include "virfile.h" #include "configmake.h" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index bdb29c7..e4f016a 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -28,7 +28,7 @@ #include "util.h" #include "viralloc.h" #include "virlog.h" -#include "pci.h" +#include "virpci.h" #include "virusb.h" #include "storage_file.h" diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 3a1548d..2adf5c9 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -37,7 +37,7 @@ #include "util.h" #include "viralloc.h" #include "virlog.h" -#include "pci.h" +#include "virpci.h" #include "virusb.h" #include "storage_file.h" #include "virfile.h" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index c9c222a..4945f7c 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -51,7 +51,7 @@ #include "xml.h" #include "uuid.h" #include "virusb.h" -#include "pci.h" +#include "virpci.h" #include "virfile.h" #include "configmake.h" #include "virrandom.h" diff --git a/src/util/pci.c b/src/util/pci.c deleted file mode 100644 index e4009fa..0000000 --- a/src/util/pci.c +++ /dev/null @@ -1,2285 +0,0 @@ -/* - * Copyright (C) 2009-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> - -#include "virlog.h" -#include "viralloc.h" -#include "vircommand.h" -#include "virterror_internal.h" -#include "virfile.h" - -#define PCI_SYSFS "/sys/bus/pci/" -#define PCI_ID_LEN 10 /* "XXXX XXXX" */ -#define PCI_ADDR_LEN 13 /* "XXXX:XX:XX.X" */ - -#define SRIOV_FOUND 0 -#define SRIOV_NOT_FOUND 1 -#define SRIOV_ERROR -1 - -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; - const char *used_by; /* The domain which uses the device */ - - unsigned pcie_cap_pos; - unsigned pci_pm_cap_pos; - unsigned has_flr : 1; - unsigned has_pm_reset : 1; - unsigned managed : 1; - - /* used by reattach function */ - unsigned unbind_from_stub : 1; - unsigned remove_slot : 1; - unsigned reprobe : 1; -}; - -struct _pciDeviceList { - unsigned count; - pciDevice **devs; -}; - - -/* For virReportOOMError() and virReportSystemError() */ -#define VIR_FROM_THIS VIR_FROM_NONE - -/* 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 */ - -#define PCI_EXP_FLAGS 0x2 -#define PCI_EXP_FLAGS_TYPE 0x00f0 -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 - -#define PCI_EXT_CAP_BASE 0x100 -#define PCI_EXT_CAP_LIMIT 0x1000 -#define PCI_EXT_CAP_ID_MASK 0x0000ffff -#define PCI_EXT_CAP_OFFSET_SHIFT 20 -#define PCI_EXT_CAP_OFFSET_MASK 0x00000ffc - -#define PCI_EXT_CAP_ID_ACS 0x000d -#define PCI_EXT_ACS_CTRL 0x06 - -#define PCI_EXT_CAP_ACS_SV 0x01 -#define PCI_EXT_CAP_ACS_RR 0x04 -#define PCI_EXT_CAP_ACS_CR 0x08 -#define PCI_EXT_CAP_ACS_UF 0x10 -#define PCI_EXT_CAP_ACS_ENABLED (PCI_EXT_CAP_ACS_SV | \ - PCI_EXT_CAP_ACS_RR | \ - PCI_EXT_CAP_ACS_CR | \ - PCI_EXT_CAP_ACS_UF) - -static int -pciConfigOpen(pciDevice *dev, bool fatal) -{ - int fd; - - fd = open(dev->path, O_RDWR); - - if (fd < 0) { - if (fatal) { - virReportSystemError(errno, - _("Failed to open config space file '%s'"), - dev->path); - } else { - 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); - return fd; -} - -static void -pciConfigClose(pciDevice *dev, int cfgfd) -{ - if (VIR_CLOSE(cfgfd) < 0) { - char ebuf[1024]; - VIR_WARN("Failed to close config space file '%s': %s", - dev->path, virStrerror(errno, ebuf, sizeof(ebuf))); - } -} - - -static int -pciRead(pciDevice *dev, - int cfgfd, - unsigned pos, - uint8_t *buf, - unsigned buflen) -{ - memset(buf, 0, buflen); - - if (lseek(cfgfd, pos, SEEK_SET) != pos || - saferead(cfgfd, 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, int cfgfd, unsigned pos) -{ - uint8_t buf; - pciRead(dev, cfgfd, pos, &buf, sizeof(buf)); - return buf; -} - -static uint16_t -pciRead16(pciDevice *dev, int cfgfd, unsigned pos) -{ - uint8_t buf[2]; - pciRead(dev, cfgfd, pos, &buf[0], sizeof(buf)); - return (buf[0] << 0) | (buf[1] << 8); -} - -static uint32_t -pciRead32(pciDevice *dev, int cfgfd, unsigned pos) -{ - uint8_t buf[4]; - pciRead(dev, cfgfd, pos, &buf[0], sizeof(buf)); - return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); -} - -static int -pciWrite(pciDevice *dev, - int cfgfd, - unsigned pos, - uint8_t *buf, - unsigned buflen) -{ - if (lseek(cfgfd, pos, SEEK_SET) != pos || - safewrite(cfgfd, 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, int cfgfd, unsigned pos, uint16_t val) -{ - uint8_t buf[2] = { (val >> 0), (val >> 8) }; - pciWrite(dev, cfgfd, pos, &buf[0], sizeof(buf)); -} - -static void -pciWrite32(pciDevice *dev, int cfgfd, unsigned pos, uint32_t val) -{ - uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 24) }; - pciWrite(dev, cfgfd, 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(pciIterPredicate predicate, - pciDevice *dev, - pciDevice **matched, - void *data) -{ - DIR *dir; - struct dirent *entry; - int ret = 0; - int rc; - - *matched = NULL; - - VIR_DEBUG("%s %s: iterating over " PCI_SYSFS "devices", dev->id, dev->name); - - dir = opendir(PCI_SYSFS "devices"); - if (!dir) { - VIR_WARN("Failed to open " PCI_SYSFS "devices"); - return -1; - } - - while ((entry = readdir(dir))) { - unsigned int domain, bus, slot, function; - pciDevice *check; - char *tmp; - - /* Ignore '.' and '..' */ - if (entry->d_name[0] == '.') - continue; - - /* expected format: <domain>:<bus>:<slot>.<function> */ - if (/* domain */ - virStrToLong_ui(entry->d_name, &tmp, 16, &domain) < 0 || *tmp != ':' || - /* bus */ - virStrToLong_ui(tmp + 1, &tmp, 16, &bus) < 0 || *tmp != ':' || - /* slot */ - virStrToLong_ui(tmp + 1, &tmp, 16, &slot) < 0 || *tmp != '.' || - /* function */ - virStrToLong_ui(tmp + 1, NULL, 16, &function) < 0) { - VIR_WARN("Unusual entry in " PCI_SYSFS "devices: %s", entry->d_name); - continue; - } - - check = pciGetDevice(domain, bus, slot, function); - if (!check) { - ret = -1; - break; - } - - rc = predicate(dev, check, data); - if (rc < 0) { - /* the predicate returned an error, bail */ - pciFreeDevice(check); - ret = -1; - break; - } - else if (rc == 1) { - VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name); - *matched = check; - ret = 1; - break; - } - - pciFreeDevice(check); - } - closedir(dir); - return ret; -} - -static uint8_t -pciFindCapabilityOffset(pciDevice *dev, int cfgfd, unsigned capability) -{ - uint16_t status; - uint8_t pos; - - status = pciRead16(dev, cfgfd, PCI_STATUS); - if (!(status & PCI_STATUS_CAP_LIST)) - return 0; - - pos = pciRead8(dev, cfgfd, 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, cfgfd, 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, cfgfd, pos + 1); - } - - VIR_DEBUG("%s %s: failed to find cap 0x%.2x", dev->id, dev->name, capability); - - return 0; -} - -static unsigned int -pciFindExtendedCapabilityOffset(pciDevice *dev, - int cfgfd, - unsigned capability) -{ - int ttl; - unsigned int pos; - uint32_t header; - - /* minimum 8 bytes per capability */ - ttl = (PCI_EXT_CAP_LIMIT - PCI_EXT_CAP_BASE) / 8; - pos = PCI_EXT_CAP_BASE; - - while (ttl > 0 && pos >= PCI_EXT_CAP_BASE) { - header = pciRead32(dev, cfgfd, pos); - - if ((header & PCI_EXT_CAP_ID_MASK) == capability) - return pos; - - pos = (header >> PCI_EXT_CAP_OFFSET_SHIFT) & PCI_EXT_CAP_OFFSET_MASK; - ttl--; - } - - return 0; -} - -/* detects whether this device has FLR. Returns 0 if the device does - * not have FLR, 1 if it does, and -1 on error - */ -static int -pciDetectFunctionLevelReset(pciDevice *dev, int cfgfd) -{ - uint32_t caps; - uint8_t pos; - char *path; - int found; - - /* 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, cfgfd, 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, cfgfd, PCI_CAP_ID_AF); - if (pos) { - caps = pciRead16(dev, cfgfd, pos + PCI_AF_CAP); - if (caps & PCI_AF_CAP_FLR) { - VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name); - return 1; - } - } - - /* there are some buggy devices that do support FLR, but forget to - * advertise that fact in their capabilities. However, FLR is *required* - * to be present for virtual functions (VFs), so if we see that this - * device is a VF, we just assume FLR works - */ - - if (virAsprintf(&path, PCI_SYSFS "devices/%s/physfn", dev->name) < 0) { - virReportOOMError(); - return -1; - } - - found = virFileExists(path); - VIR_FREE(path); - if (found) { - VIR_DEBUG("%s %s: buggy device didn't advertise FLR, but is a VF; forcing flr on", - 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, int cfgfd) -{ - if (dev->pci_pm_cap_pos) { - uint32_t ctl; - - /* require the NO_SOFT_RESET bit is clear */ - ctl = pciRead32(dev, cfgfd, 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 on the same domain/bus ? */ -static int -pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data) -{ - pciDeviceList *inactiveDevs = data; - - /* Different domain, different bus, or simply identical device */ - if (dev->domain != check->domain || - dev->bus != check->bus || - (dev->slot == check->slot && - dev->function == check->function)) - return 0; - - /* same bus, but inactive, i.e. about to be assigned to guest */ - if (inactiveDevs && pciDeviceListFind(inactiveDevs, check)) - return 0; - - return 1; -} - -static pciDevice * -pciBusContainsActiveDevices(pciDevice *dev, - pciDeviceList *inactiveDevs) -{ - pciDevice *active = NULL; - if (pciIterDevices(pciSharesBusWithActive, - dev, &active, inactiveDevs) < 0) - return NULL; - return active; -} - -/* Is @check the parent of @dev ? */ -static int -pciIsParent(pciDevice *dev, pciDevice *check, void *data) -{ - uint16_t device_class; - uint8_t header_type, secondary, subordinate; - pciDevice **best = data; - int ret = 0; - int fd; - - if (dev->domain != check->domain) - return 0; - - if ((fd = pciConfigOpen(check, false)) < 0) - return 0; - - /* Is it a bridge? */ - device_class = pciRead16(check, fd, PCI_CLASS_DEVICE); - if (device_class != PCI_CLASS_BRIDGE_PCI) - goto cleanup; - - /* Is it a plane? */ - header_type = pciRead8(check, fd, PCI_HEADER_TYPE); - if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) - goto cleanup; - - secondary = pciRead8(check, fd, PCI_SECONDARY_BUS); - subordinate = pciRead8(check, fd, PCI_SUBORDINATE_BUS); - - VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name); - - /* if the secondary bus exactly equals the device's bus, then we found - * the direct parent. No further work is necessary - */ - if (dev->bus == secondary) { - ret = 1; - goto cleanup; - } - - /* otherwise, SRIOV allows VFs to be on different busses then their PFs. - * In this case, what we need to do is look for the "best" match; i.e. - * the most restrictive match that still satisfies all of the conditions. - */ - if (dev->bus > secondary && dev->bus <= subordinate) { - if (*best == NULL) { - *best = pciGetDevice(check->domain, check->bus, check->slot, - check->function); - if (*best == NULL) { - ret = -1; - goto cleanup; - } - } else { - /* OK, we had already recorded a previous "best" match for the - * parent. See if the current device is more restrictive than the - * best, and if so, make it the new best - */ - int bestfd; - uint8_t best_secondary; - - if ((bestfd = pciConfigOpen(*best, false)) < 0) - goto cleanup; - best_secondary = pciRead8(*best, bestfd, PCI_SECONDARY_BUS); - pciConfigClose(*best, bestfd); - - if (secondary > best_secondary) { - pciFreeDevice(*best); - *best = pciGetDevice(check->domain, check->bus, check->slot, - check->function); - if (*best == NULL) { - ret = -1; - goto cleanup; - } - } - } - } - -cleanup: - pciConfigClose(check, fd); - return ret; -} - -static int -pciGetParentDevice(pciDevice *dev, pciDevice **parent) -{ - pciDevice *best = NULL; - int ret; - - *parent = NULL; - ret = pciIterDevices(pciIsParent, dev, parent, &best); - if (ret == 1) - pciFreeDevice(best); - else if (ret == 0) - *parent = best; - return ret; -} - -/* Secondary Bus Reset is our sledgehammer - it resets all - * devices behind a bus. - */ -static int -pciTrySecondaryBusReset(pciDevice *dev, - int cfgfd, - pciDeviceList *inactiveDevs) -{ - pciDevice *parent, *conflict; - uint8_t config_space[PCI_CONF_LEN]; - uint16_t ctl; - int ret = -1; - int parentfd; - - /* Refuse to do a secondary bus reset if there are other - * devices/functions behind the bus are used by the host - * or other guests. - */ - if ((conflict = pciBusContainsActiveDevices(dev, inactiveDevs))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Active %s devices on bus with %s, not doing bus reset"), - conflict->name, dev->name); - return -1; - } - - /* Find the parent bus */ - if (pciGetParentDevice(dev, &parent) < 0) - return -1; - if (!parent) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to find parent device for %s"), - dev->name); - return -1; - } - if ((parentfd = pciConfigOpen(parent, true)) < 0) - goto out; - - 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, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to read 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, cfgfd, PCI_BRIDGE_CONTROL); - - pciWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, - ctl | PCI_BRIDGE_CTL_RESET); - - usleep(200 * 1000); /* sleep 200ms */ - - pciWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, ctl); - - usleep(200 * 1000); /* sleep 200ms */ - - if (pciWrite(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to restore PCI config space for %s"), - dev->name); - goto out; - } - ret = 0; - -out: - pciConfigClose(parent, parentfd); - pciFreeDevice(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(pciDevice *dev, int cfgfd) -{ - 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, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to read 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, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL); - ctl &= ~PCI_PM_CTRL_STATE_MASK; - - pciWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL, - ctl | PCI_PM_CTRL_STATE_D3hot); - - usleep(10 * 1000); /* sleep 10ms */ - - pciWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL, - ctl | PCI_PM_CTRL_STATE_D0); - - usleep(10 * 1000); /* sleep 10ms */ - - if (pciWrite(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to restore PCI config space for %s"), - dev->name); - return -1; - } - - return 0; -} - -static int -pciInitDevice(pciDevice *dev, int cfgfd) -{ - int flr; - - dev->pcie_cap_pos = pciFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_EXP); - dev->pci_pm_cap_pos = pciFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_PM); - flr = pciDetectFunctionLevelReset(dev, cfgfd); - if (flr < 0) - return flr; - dev->has_flr = flr; - dev->has_pm_reset = pciDetectPowerManagementReset(dev, cfgfd); - - return 0; -} - -int -pciResetDevice(pciDevice *dev, - pciDeviceList *activeDevs, - pciDeviceList *inactiveDevs) -{ - int ret = -1; - int fd; - - if (activeDevs && pciDeviceListFind(activeDevs, dev)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Not resetting active device %s"), dev->name); - return -1; - } - - if ((fd = pciConfigOpen(dev, true)) < 0) - return -1; - - if (pciInitDevice(dev, fd) < 0) - goto cleanup; - - /* 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) { - ret = 0; - goto cleanup; - } - - /* 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(dev, fd); - - /* Bus reset is not an option with the root bus */ - if (ret < 0 && dev->bus != 0) - ret = pciTrySecondaryBusReset(dev, fd, inactiveDevs); - - if (ret < 0) { - virErrorPtr err = virGetLastError(); - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unable to reset PCI device %s: %s"), - dev->name, - err ? err->message : _("no FLR, PM reset or bus reset available")); - } - -cleanup: - pciConfigClose(dev, fd); - return ret; -} - - -static int -pciDriverDir(char **buffer, const char *driver) -{ - VIR_FREE(*buffer); - - if (virAsprintf(buffer, PCI_SYSFS "drivers/%s", driver) < 0) { - virReportOOMError(); - return -1; - } - - return 0; -} - -static int -pciDriverFile(char **buffer, const char *driver, const char *file) -{ - VIR_FREE(*buffer); - - if (virAsprintf(buffer, PCI_SYSFS "drivers/%s/%s", driver, file) < 0) { - virReportOOMError(); - return -1; - } - - return 0; -} - -static int -pciDeviceFile(char **buffer, const char *device, const char *file) -{ - VIR_FREE(*buffer); - - if (virAsprintf(buffer, PCI_SYSFS "devices/%s/%s", device, file) < 0) { - virReportOOMError(); - return -1; - } - - return 0; -} - - -static const char * -pciFindStubDriver(void) -{ - char *drvpath = NULL; - int probed = 0; - -recheck: - if (pciDriverDir(&drvpath, "pci-stub") < 0) { - return NULL; - } - - if (virFileExists(drvpath)) { - VIR_FREE(drvpath); - return "pci-stub"; - } - - if (pciDriverDir(&drvpath, "pciback") < 0) { - return NULL; - } - - if (virFileExists(drvpath)) { - VIR_FREE(drvpath); - return "pciback"; - } - - VIR_FREE(drvpath); - - 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(backprobe, NULL) < 0 && - virRun(stubprobe, NULL) < 0) { - char ebuf[1024]; - VIR_WARN("failed to load pci-stub or pciback drivers: %s", - virStrerror(errno, ebuf, sizeof(ebuf))); - return NULL; - } - - goto recheck; - } - - return NULL; -} - -static int -pciUnbindDeviceFromStub(pciDevice *dev, const char *driver) -{ - int result = -1; - char *drvdir = NULL; - char *path = NULL; - - if (pciDriverDir(&drvdir, driver) < 0) - goto cleanup; - - if (!dev->unbind_from_stub) - goto remove_slot; - - /* If the device is bound to stub, unbind it. - */ - if (pciDeviceFile(&path, dev->name, "driver") < 0) - goto cleanup; - - if (virFileExists(drvdir) && virFileLinkPointsTo(path, drvdir)) { - if (pciDriverFile(&path, driver, "unbind") < 0) { - goto cleanup; - } - - if (virFileWriteStr(path, dev->name, 0) < 0) { - virReportSystemError(errno, - _("Failed to unbind PCI device '%s' from %s"), - dev->name, driver); - goto cleanup; - } - } - dev->unbind_from_stub = 0; - -remove_slot: - if (!dev->remove_slot) - goto reprobe; - - /* Xen's pciback.ko wants you to use remove_slot on the specific device */ - if (pciDriverFile(&path, driver, "remove_slot") < 0) { - goto cleanup; - } - - if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { - virReportSystemError(errno, - _("Failed to remove slot for PCI device '%s' from %s"), - dev->name, driver); - goto cleanup; - } - dev->remove_slot = 0; - -reprobe: - if (!dev->reprobe) { - result = 0; - goto cleanup; - } - - /* 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. - */ - if (pciDriverFile(&path, driver, "remove_id") < 0) { - goto cleanup; - } - - if (!virFileExists(drvdir) || virFileExists(path)) { - if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name, 0) < 0) { - virReportSystemError(errno, - _("Failed to trigger a re-probe for PCI device '%s'"), - dev->name); - goto cleanup; - } - } - - result = 0; - -cleanup: - /* do not do it again */ - dev->unbind_from_stub = 0; - dev->remove_slot = 0; - dev->reprobe = 0; - - VIR_FREE(drvdir); - VIR_FREE(path); - - return result; -} - - -static int -pciBindDeviceToStub(pciDevice *dev, const char *driver) -{ - int result = -1; - char *drvdir = NULL; - char *path = NULL; - int reprobe = 0; - - /* check whether the device is already bound to a driver */ - if (pciDriverDir(&drvdir, driver) < 0 || - pciDeviceFile(&path, dev->name, "driver") < 0) { - goto cleanup; - } - - if (virFileExists(path)) { - if (virFileLinkPointsTo(path, drvdir)) { - /* The device is already bound to pci-stub */ - result = 0; - goto cleanup; - } - reprobe = 1; - } - - /* 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. - */ - if (pciDriverFile(&path, driver, "new_id") < 0) { - goto cleanup; - } - - if (virFileWriteStr(path, dev->id, 0) < 0) { - virReportSystemError(errno, - _("Failed to add PCI device ID '%s' to %s"), - dev->id, driver); - goto cleanup; - } - - /* check whether the device is bound to pci-stub when we write dev->id to - * new_id. - */ - if (pciDriverDir(&drvdir, driver) < 0 || - pciDeviceFile(&path, dev->name, "driver") < 0) { - goto remove_id; - } - - if (virFileLinkPointsTo(path, drvdir)) { - dev->unbind_from_stub = 1; - dev->remove_slot = 1; - goto remove_id; - } - - /* 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. - */ - if (pciDeviceFile(&path, dev->name, "driver/unbind") < 0) { - goto cleanup; - } - - if (virFileExists(path)) { - if (virFileWriteStr(path, dev->name, 0) < 0) { - virReportSystemError(errno, - _("Failed to unbind PCI device '%s'"), - dev->name); - goto cleanup; - } - dev->reprobe = reprobe; - } - - /* If the device isn't already bound to pci-stub, try binding it now. - */ - if (pciDriverDir(&drvdir, driver) < 0 || - pciDeviceFile(&path, dev->name, "driver") < 0) { - goto remove_id; - } - - if (!virFileLinkPointsTo(path, drvdir)) { - /* Xen's pciback.ko wants you to use new_slot first */ - if (pciDriverFile(&path, driver, "new_slot") < 0) { - goto remove_id; - } - - if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { - virReportSystemError(errno, - _("Failed to add slot for PCI device '%s' to %s"), - dev->name, driver); - goto remove_id; - } - dev->remove_slot = 1; - - if (pciDriverFile(&path, driver, "bind") < 0) { - goto remove_id; - } - - if (virFileWriteStr(path, dev->name, 0) < 0) { - virReportSystemError(errno, - _("Failed to bind PCI device '%s' to %s"), - dev->name, driver); - goto remove_id; - } - dev->unbind_from_stub = 1; - } - -remove_id: - /* If 'remove_id' exists, remove the device id from pci-stub's dynamic - * ID table so that 'drivers_probe' works below. - */ - if (pciDriverFile(&path, driver, "remove_id") < 0) { - /* We do not remove PCI ID from pci-stub, and we cannot reprobe it */ - if (dev->reprobe) { - VIR_WARN("Could not remove PCI ID '%s' from %s, and the device " - "cannot be probed again.", dev->id, driver); - } - dev->reprobe = 0; - goto cleanup; - } - - if (virFileExists(path) && virFileWriteStr(path, dev->id, 0) < 0) { - virReportSystemError(errno, - _("Failed to remove PCI ID '%s' from %s"), - dev->id, driver); - - /* remove PCI ID from pci-stub failed, and we cannot reprobe it */ - if (dev->reprobe) { - VIR_WARN("Failed to remove PCI ID '%s' from %s, and the device " - "cannot be probed again.", dev->id, driver); - } - dev->reprobe = 0; - goto cleanup; - } - - result = 0; - -cleanup: - VIR_FREE(drvdir); - VIR_FREE(path); - - if (result < 0) { - pciUnbindDeviceFromStub(dev, driver); - } - - return result; -} - -int -pciDettachDevice(pciDevice *dev, - pciDeviceList *activeDevs, - pciDeviceList *inactiveDevs) -{ - const char *driver = pciFindStubDriver(); - if (!driver) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot find any PCI stub module")); - return -1; - } - - if (activeDevs && pciDeviceListFind(activeDevs, dev)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Not detaching active device %s"), dev->name); - return -1; - } - - if (pciBindDeviceToStub(dev, driver) < 0) - return -1; - - /* Add the dev into list inactiveDevs */ - if (inactiveDevs && !pciDeviceListFind(inactiveDevs, dev)) { - if (pciDeviceListAdd(inactiveDevs, dev) < 0) - return -1; - } - - return 0; -} - -int -pciReAttachDevice(pciDevice *dev, - pciDeviceList *activeDevs, - pciDeviceList *inactiveDevs) -{ - const char *driver = pciFindStubDriver(); - if (!driver) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot find any PCI stub module")); - return -1; - } - - if (activeDevs && pciDeviceListFind(activeDevs, dev)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Not reattaching active device %s"), dev->name); - return -1; - } - - if (pciUnbindDeviceFromStub(dev, driver) < 0) - return -1; - - /* Steal the dev from list inactiveDevs */ - if (inactiveDevs) - pciDeviceListSteal(inactiveDevs, dev); - - return 0; -} - -/* Certain hypervisors (like qemu/kvm) map the PCI bar(s) on - * the host when doing device passthrough. This can lead to a race - * condition where the hypervisor is still cleaning up the device while - * libvirt is trying to re-attach it to the host device driver. To avoid - * this situation, we look through /proc/iomem, and if the hypervisor is - * still holding onto the bar (denoted by the string in the matcher variable), - * then we can wait around a bit for that to clear up. - * - * A typical /proc/iomem looks like this (snipped for brevity): - * 00010000-0008efff : System RAM - * 0008f000-0008ffff : reserved - * ... - * 00100000-cc9fcfff : System RAM - * 00200000-00483d3b : Kernel code - * 00483d3c-005c88df : Kernel data - * cc9fd000-ccc71fff : ACPI Non-volatile Storage - * ... - * d0200000-d02fffff : PCI Bus #05 - * d0200000-d021ffff : 0000:05:00.0 - * d0200000-d021ffff : e1000e - * d0220000-d023ffff : 0000:05:00.0 - * d0220000-d023ffff : e1000e - * ... - * f0000000-f0003fff : 0000:00:1b.0 - * f0000000-f0003fff : kvm_assigned_device - * - * Returns 0 if we are clear to continue, and 1 if the hypervisor is still - * holding onto the resource. - */ -int -pciWaitForDeviceCleanup(pciDevice *dev, const char *matcher) -{ - FILE *fp; - char line[160]; - char *tmp; - unsigned long long start, end; - unsigned int domain, bus, slot, function; - int in_matching_device; - int ret; - size_t match_depth; - - fp = fopen("/proc/iomem", "r"); - if (!fp) { - /* If we failed to open iomem, we just basically ignore the error. The - * unbind might succeed anyway, and besides, it's very likely we have - * no way to report the error - */ - VIR_DEBUG("Failed to open /proc/iomem, trying to continue anyway"); - return 0; - } - - ret = 0; - in_matching_device = 0; - match_depth = 0; - while (fgets(line, sizeof(line), fp) != 0) { - /* the logic here is a bit confusing. For each line, we look to - * see if it matches the domain:bus:slot.function we were given. - * If this line matches the DBSF, then any subsequent lines indented - * by 2 spaces are the PCI regions for this device. It's also - * possible that none of the PCI regions are currently mapped, in - * which case we have no indented regions. This code handles all - * of these situations - */ - if (in_matching_device && (strspn(line, " ") == (match_depth + 2))) { - /* expected format: <start>-<end> : <suffix> */ - if (/* start */ - virStrToLong_ull(line, &tmp, 16, &start) < 0 || *tmp != '-' || - /* end */ - virStrToLong_ull(tmp + 1, &tmp, 16, &end) < 0 || - (tmp = STRSKIP(tmp, " : ")) == NULL) - continue; - - if (STRPREFIX(tmp, matcher)) { - ret = 1; - break; - } - } - else { - in_matching_device = 0; - - /* expected format: <start>-<end> : <domain>:<bus>:<slot>.<function> */ - if (/* start */ - virStrToLong_ull(line, &tmp, 16, &start) < 0 || *tmp != '-' || - /* end */ - virStrToLong_ull(tmp + 1, &tmp, 16, &end) < 0 || - (tmp = STRSKIP(tmp, " : ")) == NULL || - /* domain */ - virStrToLong_ui(tmp, &tmp, 16, &domain) < 0 || *tmp != ':' || - /* bus */ - virStrToLong_ui(tmp + 1, &tmp, 16, &bus) < 0 || *tmp != ':' || - /* slot */ - virStrToLong_ui(tmp + 1, &tmp, 16, &slot) < 0 || *tmp != '.' || - /* function */ - virStrToLong_ui(tmp + 1, &tmp, 16, &function) < 0 || *tmp != '\n') - continue; - - if (domain != dev->domain || bus != dev->bus || slot != dev->slot || - function != dev->function) - continue; - in_matching_device = 1; - match_depth = strspn(line, " "); - } - } - - VIR_FORCE_FCLOSE(fp); - - return ret; -} - -static char * -pciReadDeviceID(pciDevice *dev, const char *id_name) -{ - char *path = NULL; - char *id_str; - - if (pciDeviceFile(&path, dev->name, id_name) < 0) { - return NULL; - } - - /* ID string is '0xNNNN\n' ... i.e. 7 bytes */ - if (virFileReadAll(path, 7, &id_str) < 0) { - VIR_FREE(path); - return NULL; - } - - VIR_FREE(path); - - /* 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; -} - -int -pciGetDeviceAddrString(unsigned domain, - unsigned bus, - unsigned slot, - unsigned function, - char **pciConfigAddr) -{ - pciDevice *dev = NULL; - int ret = -1; - - dev = pciGetDevice(domain, bus, slot, function); - if (dev != NULL) { - if ((*pciConfigAddr = strdup(dev->name)) == NULL) { - virReportOOMError(); - goto cleanup; - } - ret = 0; - } - -cleanup: - pciFreeDevice(dev); - return ret; -} - -pciDevice * -pciGetDevice(unsigned domain, - unsigned bus, - unsigned slot, - unsigned function) -{ - pciDevice *dev; - char *vendor = NULL; - char *product = NULL; - - if (VIR_ALLOC(dev) < 0) { - virReportOOMError(); - return NULL; - } - - dev->domain = domain; - dev->bus = bus; - dev->slot = slot; - dev->function = function; - - if (snprintf(dev->name, sizeof(dev->name), "%.4x:%.2x:%.2x.%.1x", - dev->domain, dev->bus, dev->slot, - dev->function) >= sizeof(dev->name)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("dev->name buffer overflow: %.4x:%.2x:%.2x.%.1x"), - dev->domain, dev->bus, dev->slot, dev->function); - goto error; - } - if (virAsprintf(&dev->path, PCI_SYSFS "devices/%s/config", - dev->name) < 0) { - virReportOOMError(); - goto error; - } - - if (access(dev->path, F_OK) != 0) { - virReportSystemError(errno, - _("Device %s not found: could not access %s"), - dev->name, dev->path); - goto error; - } - - vendor = pciReadDeviceID(dev, "vendor"); - product = pciReadDeviceID(dev, "device"); - - if (!vendor || !product) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to read product/vendor ID for %s"), - dev->name); - goto error; - } - - /* strings contain '0x' prefix */ - if (snprintf(dev->id, sizeof(dev->id), "%s %s", &vendor[2], - &product[2]) >= sizeof(dev->id)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("dev->id buffer overflow: %s %s"), - &vendor[2], &product[2]); - goto error; - } - - VIR_DEBUG("%s %s: initialized", dev->id, dev->name); - -cleanup: - VIR_FREE(product); - VIR_FREE(vendor); - return dev; - -error: - pciFreeDevice(dev); - dev = NULL; - goto cleanup; -} - -void -pciFreeDevice(pciDevice *dev) -{ - if (!dev) - return; - VIR_DEBUG("%s %s: freeing", dev->id, dev->name); - VIR_FREE(dev->path); - VIR_FREE(dev); -} - -const char * -pciDeviceGetName(pciDevice *dev) -{ - return dev->name; -} - -void pciDeviceSetManaged(pciDevice *dev, unsigned managed) -{ - dev->managed = !!managed; -} - -unsigned pciDeviceGetManaged(pciDevice *dev) -{ - return dev->managed; -} - -unsigned -pciDeviceGetUnbindFromStub(pciDevice *dev) -{ - return dev->unbind_from_stub; -} - -void -pciDeviceSetUnbindFromStub(pciDevice *dev, unsigned unbind) -{ - dev->unbind_from_stub = !!unbind; -} - -unsigned -pciDeviceGetRemoveSlot(pciDevice *dev) -{ - return dev->remove_slot; -} - -void -pciDeviceSetRemoveSlot(pciDevice *dev, unsigned remove_slot) -{ - dev->remove_slot = !!remove_slot; -} - -unsigned -pciDeviceGetReprobe(pciDevice *dev) -{ - return dev->reprobe; -} - -void -pciDeviceSetReprobe(pciDevice *dev, unsigned reprobe) -{ - dev->reprobe = !!reprobe; -} - -void -pciDeviceSetUsedBy(pciDevice *dev, const char *name) -{ - dev->used_by = name; -} - -const char * -pciDeviceGetUsedBy(pciDevice *dev) -{ - return dev->used_by; -} - -void pciDeviceReAttachInit(pciDevice *pci) -{ - pci->unbind_from_stub = 1; - pci->remove_slot = 1; - pci->reprobe = 1; -} - - -pciDeviceList * -pciDeviceListNew(void) -{ - pciDeviceList *list; - - if (VIR_ALLOC(list) < 0) { - virReportOOMError(); - return NULL; - } - - return list; -} - -void -pciDeviceListFree(pciDeviceList *list) -{ - int i; - - if (!list) - return; - - for (i = 0; i < list->count; i++) { - pciFreeDevice(list->devs[i]); - list->devs[i] = NULL; - } - - list->count = 0; - VIR_FREE(list->devs); - VIR_FREE(list); -} - -int -pciDeviceListAdd(pciDeviceList *list, - pciDevice *dev) -{ - if (pciDeviceListFind(list, dev)) { - virReportError(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(); - return -1; - } - - list->devs[list->count++] = dev; - - return 0; -} - -pciDevice * -pciDeviceListGet(pciDeviceList *list, - int idx) -{ - if (idx >= list->count) - return NULL; - if (idx < 0) - return NULL; - - return list->devs[idx]; -} - -int -pciDeviceListCount(pciDeviceList *list) -{ - return list->count; -} - -pciDevice * -pciDeviceListStealIndex(pciDeviceList *list, - int idx) -{ - pciDevice *ret; - - if (idx < 0 || idx >= list->count) - return NULL; - - ret = list->devs[idx]; - - if (idx != --list->count) { - memmove(&list->devs[idx], - &list->devs[idx + 1], - sizeof(*list->devs) * (list->count - idx)); - } - - if (VIR_REALLOC_N(list->devs, list->count) < 0) { - ; /* not fatal */ - } - - return ret; -} - -pciDevice * -pciDeviceListSteal(pciDeviceList *list, - pciDevice *dev) -{ - return pciDeviceListStealIndex(list, pciDeviceListFindIndex(list, dev)); -} - -void -pciDeviceListDel(pciDeviceList *list, - pciDevice *dev) -{ - pciDevice *ret = pciDeviceListSteal(list, dev); - if (ret) - pciFreeDevice(ret); -} - -int -pciDeviceListFindIndex(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 i; - return -1; -} - -pciDevice * -pciDeviceListFind(pciDeviceList *list, pciDevice *dev) -{ - int i; - - if ((i = pciDeviceListFindIndex(list, dev)) >= 0) - return list->devs[i]; - else - return NULL; -} - - -int pciDeviceFileIterate(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(); - goto cleanup; - } - - if (!(dir = opendir(pcidir))) { - virReportSystemError(errno, - _("cannot open %s"), pcidir); - goto cleanup; - } - - while ((ent = readdir(dir)) != NULL) { - /* Device assignment requires: - * $PCIDIR/config, $PCIDIR/resource, $PCIDIR/resourceNNN, - * $PCIDIR/rom, $PCIDIR/reset - */ - if (STREQ(ent->d_name, "config") || - STRPREFIX(ent->d_name, "resource") || - STREQ(ent->d_name, "rom") || - STREQ(ent->d_name, "reset")) { - if (virAsprintf(&file, "%s/%s", pcidir, ent->d_name) < 0) { - virReportOOMError(); - goto cleanup; - } - if ((actor)(dev, file, opaque) < 0) - goto cleanup; - - VIR_FREE(file); - } - } - - ret = 0; - -cleanup: - if (dir) - closedir(dir); - VIR_FREE(file); - VIR_FREE(pcidir); - return ret; -} - -static int -pciDeviceDownstreamLacksACS(pciDevice *dev) -{ - uint16_t flags; - uint16_t ctrl; - unsigned int pos; - int fd; - int ret = 0; - - if ((fd = pciConfigOpen(dev, true)) < 0) - return -1; - - if (pciInitDevice(dev, fd) < 0) { - ret = -1; - goto cleanup; - } - - pos = dev->pcie_cap_pos; - if (!pos || pciRead16(dev, fd, PCI_CLASS_DEVICE) != PCI_CLASS_BRIDGE_PCI) - goto cleanup; - - flags = pciRead16(dev, fd, pos + PCI_EXP_FLAGS); - if (((flags & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_DOWNSTREAM) - goto cleanup; - - pos = pciFindExtendedCapabilityOffset(dev, fd, PCI_EXT_CAP_ID_ACS); - if (!pos) { - VIR_DEBUG("%s %s: downstream port lacks ACS", dev->id, dev->name); - ret = 1; - goto cleanup; - } - - ctrl = pciRead16(dev, fd, pos + PCI_EXT_ACS_CTRL); - if ((ctrl & PCI_EXT_CAP_ACS_ENABLED) != PCI_EXT_CAP_ACS_ENABLED) { - VIR_DEBUG("%s %s: downstream port has ACS disabled", - dev->id, dev->name); - ret = 1; - goto cleanup; - } - -cleanup: - pciConfigClose(dev, fd); - return ret; -} - -static int -pciDeviceIsBehindSwitchLackingACS(pciDevice *dev) -{ - pciDevice *parent; - - if (pciGetParentDevice(dev, &parent) < 0) - return -1; - if (!parent) { - /* if we have no parent, and this is the root bus, ACS doesn't come - * into play since devices on the root bus can't P2P without going - * through the root IOMMU. - */ - if (dev->bus == 0) - return 0; - else { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to find parent device for %s"), - dev->name); - return -1; - } - } - - /* XXX we should rather fail when we can't find device's parent and - * stop the loop when we get to root instead of just stopping when no - * parent can be found - */ - do { - pciDevice *tmp; - int acs; - int ret; - - acs = pciDeviceDownstreamLacksACS(parent); - - if (acs) { - pciFreeDevice(parent); - if (acs < 0) - return -1; - else - return 1; - } - - tmp = parent; - ret = pciGetParentDevice(parent, &parent); - pciFreeDevice(tmp); - if (ret < 0) - return -1; - } while (parent); - - return 0; -} - -int pciDeviceIsAssignable(pciDevice *dev, - int strict_acs_check) -{ - int ret; - - /* XXX This could be a great place to actually check that a non-managed - * device isn't in use, e.g. by checking that device is either un-bound - * or bound to a stub driver. - */ - - ret = pciDeviceIsBehindSwitchLackingACS(dev); - if (ret < 0) - return 0; - - if (ret) { - if (!strict_acs_check) { - VIR_DEBUG("%s %s: strict ACS check disabled; device assignment allowed", - dev->id, dev->name); - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Device %s is behind a switch lacking ACS and " - "cannot be assigned"), - dev->name); - return 0; - } - } - - return 1; -} - -#ifdef __linux__ - -/* - * returns true if equal - */ -static bool -pciConfigAddressEqual(struct pci_config_address *bdf1, - struct pci_config_address *bdf2) -{ - return ((bdf1->domain == bdf2->domain) && - (bdf1->bus == bdf2->bus) && - (bdf1->slot == bdf2->slot) && - (bdf1->function == bdf2->function)); -} - -static int -logStrToLong_ui(char const *s, - char **end_ptr, - int base, - unsigned int *result) -{ - int ret = 0; - - ret = virStrToLong_ui(s, end_ptr, base, result); - if (ret != 0) { - VIR_ERROR(_("Failed to convert '%s' to unsigned int"), s); - } else { - VIR_DEBUG("Converted '%s' to unsigned int %u", s, *result); - } - - return ret; -} - -static int -pciParsePciConfigAddress(char *address, - struct pci_config_address *bdf) -{ - char *p = NULL; - int ret = -1; - - if ((address == NULL) || (logStrToLong_ui(address, &p, 16, - &bdf->domain) == -1)) { - goto out; - } - - if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16, - &bdf->bus) == -1)) { - goto out; - } - - if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16, - &bdf->slot) == -1)) { - goto out; - } - - if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16, - &bdf->function) == -1)) { - goto out; - } - - ret = 0; - -out: - return ret; -} - -static int -pciGetPciConfigAddressFromSysfsDeviceLink(const char *device_link, - struct pci_config_address **bdf) -{ - char *config_address = NULL; - char *device_path = NULL; - char errbuf[64]; - int ret = -1; - - VIR_DEBUG("Attempting to resolve device path from device link '%s'", - device_link); - - if (!virFileExists(device_link)) { - VIR_DEBUG("sysfs_path '%s' does not exist", device_link); - return ret; - } - - device_path = canonicalize_file_name(device_link); - if (device_path == NULL) { - memset(errbuf, '\0', sizeof(errbuf)); - virReportSystemError(errno, - _("Failed to resolve device link '%s'"), - device_link); - return ret; - } - - config_address = basename(device_path); - if (VIR_ALLOC(*bdf) != 0) { - virReportOOMError(); - goto out; - } - - if (pciParsePciConfigAddress(config_address, *bdf) != 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to parse PCI config address '%s'"), - config_address); - VIR_FREE(*bdf); - goto out; - } - - VIR_DEBUG("pci_config_address %.4x:%.2x:%.2x.%.1x", - (*bdf)->domain, - (*bdf)->bus, - (*bdf)->slot, - (*bdf)->function); - - ret = 0; - -out: - VIR_FREE(device_path); - - return ret; -} - -/* - * Returns Physical function given a virtual function - */ -int -pciGetPhysicalFunction(const char *vf_sysfs_path, - struct pci_config_address **physical_function) -{ - int ret = -1; - char *device_link = NULL; - - VIR_DEBUG("Attempting to get SR IOV physical function for device " - "with sysfs path '%s'", vf_sysfs_path); - - if (virBuildPath(&device_link, vf_sysfs_path, "physfn") == -1) { - virReportOOMError(); - return ret; - } else { - ret = pciGetPciConfigAddressFromSysfsDeviceLink(device_link, - physical_function); - } - - VIR_FREE(device_link); - - return ret; -} - -/* - * Returns virtual functions of a physical function - */ -int -pciGetVirtualFunctions(const char *sysfs_path, - struct pci_config_address ***virtual_functions, - unsigned int *num_virtual_functions) -{ - int ret = -1; - DIR *dir = NULL; - struct dirent *entry = NULL; - char *device_link = NULL; - char errbuf[64]; - - VIR_DEBUG("Attempting to get SR IOV virtual functions for device" - "with sysfs path '%s'", sysfs_path); - - dir = opendir(sysfs_path); - if (dir == NULL) { - memset(errbuf, '\0', sizeof(errbuf)); - virReportSystemError(errno, - _("Failed to open dir '%s'"), - sysfs_path); - return ret; - } - - *virtual_functions = NULL; - *num_virtual_functions = 0; - while ((entry = readdir(dir))) { - if (STRPREFIX(entry->d_name, "virtfn")) { - - if (virBuildPath(&device_link, sysfs_path, entry->d_name) == -1) { - virReportOOMError(); - goto out; - } - - VIR_DEBUG("Number of virtual functions: %d", - *num_virtual_functions); - if (VIR_REALLOC_N(*virtual_functions, - (*num_virtual_functions) + 1) != 0) { - virReportOOMError(); - VIR_FREE(device_link); - goto out; - } - - if (pciGetPciConfigAddressFromSysfsDeviceLink(device_link, - &((*virtual_functions)[*num_virtual_functions])) != - SRIOV_FOUND) { - /* We should not get back SRIOV_NOT_FOUND in this - * case, so if we do, it's an error. */ - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to get SR IOV function from device " - "link '%s'"), device_link); - VIR_FREE(device_link); - goto out; - } else { - (*num_virtual_functions)++; - } - VIR_FREE(device_link); - } - } - - ret = 0; - -out: - if (dir) - closedir(dir); - - return ret; -} - -/* - * Returns 1 if vf device is a virtual function, 0 if not, -1 on error - */ -int -pciDeviceIsVirtualFunction(const char *vf_sysfs_device_link) -{ - char *vf_sysfs_physfn_link = NULL; - int ret = -1; - - if (virAsprintf(&vf_sysfs_physfn_link, "%s/physfn", - vf_sysfs_device_link) < 0) { - virReportOOMError(); - return ret; - } - - ret = virFileExists(vf_sysfs_physfn_link); - - VIR_FREE(vf_sysfs_physfn_link); - - return ret; -} - -/* - * Returns the sriov virtual function index of vf given its pf - */ -int -pciGetVirtualFunctionIndex(const char *pf_sysfs_device_link, - const char *vf_sysfs_device_link, - int *vf_index) -{ - int ret = -1, i; - unsigned int num_virt_fns = 0; - struct pci_config_address *vf_bdf = NULL; - struct pci_config_address **virt_fns = NULL; - - if (pciGetPciConfigAddressFromSysfsDeviceLink(vf_sysfs_device_link, - &vf_bdf) < 0) - return ret; - - if (pciGetVirtualFunctions(pf_sysfs_device_link, &virt_fns, - &num_virt_fns) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Error getting physical function's '%s' " - "virtual_functions"), pf_sysfs_device_link); - goto out; - } - - for (i = 0; i < num_virt_fns; i++) { - if (pciConfigAddressEqual(vf_bdf, virt_fns[i])) { - *vf_index = i; - ret = 0; - break; - } - } - -out: - - /* free virtual functions */ - for (i = 0; i < num_virt_fns; i++) - VIR_FREE(virt_fns[i]); - - VIR_FREE(virt_fns); - VIR_FREE(vf_bdf); - - return ret; -} - -/* - * Returns a path to the PCI sysfs file given the BDF of the PCI function - */ - -int -pciSysfsFile(char *pciDeviceName, char **pci_sysfs_device_link) -{ - if (virAsprintf(pci_sysfs_device_link, PCI_SYSFS "devices/%s", - pciDeviceName) < 0) { - virReportOOMError(); - return -1; - } - - return 0; -} - -int -pciConfigAddressToSysfsFile(struct pci_config_address *dev, - char **pci_sysfs_device_link) -{ - if (virAsprintf(pci_sysfs_device_link, - PCI_SYSFS "devices/%04x:%02x:%02x.%x", dev->domain, - dev->bus, dev->slot, dev->function) < 0) { - virReportOOMError(); - return -1; - } - - return 0; -} - -/* - * Returns the network device name of a pci device - */ -int -pciDeviceNetName(char *device_link_sysfs_path, char **netname) -{ - char *pcidev_sysfs_net_path = NULL; - int ret = -1; - DIR *dir = NULL; - struct dirent *entry = NULL; - - if (virBuildPath(&pcidev_sysfs_net_path, device_link_sysfs_path, - "net") == -1) { - virReportOOMError(); - return -1; - } - - dir = opendir(pcidev_sysfs_net_path); - if (dir == NULL) - goto out; - - while ((entry = readdir(dir))) { - if (STREQ(entry->d_name, ".") || - STREQ(entry->d_name, "..")) - continue; - - /* Assume a single directory entry */ - *netname = strdup(entry->d_name); - if (!*netname) - virReportOOMError(); - else - ret = 0; - break; - } - - closedir(dir); - -out: - VIR_FREE(pcidev_sysfs_net_path); - - return ret; -} - -int -pciDeviceGetVirtualFunctionInfo(const char *vf_sysfs_device_path, - char **pfname, int *vf_index) -{ - struct pci_config_address *pf_config_address = NULL; - char *pf_sysfs_device_path = NULL; - int ret = -1; - - if (pciGetPhysicalFunction(vf_sysfs_device_path, &pf_config_address) < 0) - return ret; - - if (pciConfigAddressToSysfsFile(pf_config_address, - &pf_sysfs_device_path) < 0) { - - VIR_FREE(pf_config_address); - return ret; - } - - if (pciGetVirtualFunctionIndex(pf_sysfs_device_path, vf_sysfs_device_path, - vf_index) < 0) - goto cleanup; - - ret = pciDeviceNetName(pf_sysfs_device_path, pfname); - -cleanup: - VIR_FREE(pf_config_address); - VIR_FREE(pf_sysfs_device_path); - - return ret; -} - -#else -static const char *unsupported = N_("not supported on non-linux platforms"); - -int -pciGetPhysicalFunction(const char *vf_sysfs_path ATTRIBUTE_UNUSED, - struct pci_config_address **physical_function ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -pciGetVirtualFunctions(const char *sysfs_path ATTRIBUTE_UNUSED, - struct pci_config_address ***virtual_functions ATTRIBUTE_UNUSED, - unsigned int *num_virtual_functions ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -pciDeviceIsVirtualFunction(const char *vf_sysfs_device_link ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -pciGetVirtualFunctionIndex(const char *pf_sysfs_device_link ATTRIBUTE_UNUSED, - const char *vf_sysfs_device_link ATTRIBUTE_UNUSED, - int *vf_index ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; - -} - -int -pciConfigAddressToSysfsFile(struct pci_config_address *dev ATTRIBUTE_UNUSED, - char **pci_sysfs_device_link ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -pciDeviceNetName(char *device_link_sysfs_path ATTRIBUTE_UNUSED, - char **netname ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} - -int -pciDeviceGetVirtualFunctionInfo(const char *vf_sysfs_device_path ATTRIBUTE_UNUSED, - char **pfname ATTRIBUTE_UNUSED, - int *vf_index ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); - return -1; -} -#endif /* __linux__ */ diff --git a/src/util/pci.h b/src/util/pci.h deleted file mode 100644 index 814c24e..0000000 --- a/src/util/pci.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2009, 2011-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Mark McLoughlin <markmc@redhat.com> - */ - -#ifndef __VIR_PCI_H__ -# define __VIR_PCI_H__ - -# include "internal.h" - -typedef struct _pciDevice pciDevice; -typedef struct _pciDeviceList pciDeviceList; - -struct pci_config_address { - unsigned int domain; - unsigned int bus; - unsigned int slot; - unsigned int function; -}; - -pciDevice *pciGetDevice (unsigned domain, - unsigned bus, - unsigned slot, - unsigned function); -void pciFreeDevice (pciDevice *dev); -const char *pciDeviceGetName (pciDevice *dev); -int pciDettachDevice (pciDevice *dev, - pciDeviceList *activeDevs, - pciDeviceList *inactiveDevs); -int pciReAttachDevice (pciDevice *dev, - pciDeviceList *activeDevs, - pciDeviceList *inactiveDevs); -int pciResetDevice (pciDevice *dev, - pciDeviceList *activeDevs, - pciDeviceList *inactiveDevs); -void pciDeviceSetManaged(pciDevice *dev, - unsigned managed); -unsigned pciDeviceGetManaged(pciDevice *dev); -void pciDeviceSetUsedBy(pciDevice *dev, - const char *used_by); -const char *pciDeviceGetUsedBy(pciDevice *dev); -unsigned pciDeviceGetUnbindFromStub(pciDevice *dev); -void pciDeviceSetUnbindFromStub(pciDevice *dev, - unsigned unbind); -unsigned pciDeviceGetRemoveSlot(pciDevice *dev); -void pciDeviceSetRemoveSlot(pciDevice *dev, - unsigned remove_slot); -unsigned pciDeviceGetReprobe(pciDevice *dev); -void pciDeviceSetReprobe(pciDevice *dev, - unsigned reprobe); -void pciDeviceReAttachInit(pciDevice *dev); - -pciDeviceList *pciDeviceListNew (void); -void pciDeviceListFree (pciDeviceList *list); -int pciDeviceListAdd (pciDeviceList *list, - pciDevice *dev); -pciDevice * pciDeviceListGet (pciDeviceList *list, - int idx); -int pciDeviceListCount (pciDeviceList *list); -pciDevice * pciDeviceListSteal (pciDeviceList *list, - pciDevice *dev); -pciDevice * pciDeviceListStealIndex(pciDeviceList *list, - int idx); -void pciDeviceListDel (pciDeviceList *list, - pciDevice *dev); -pciDevice * pciDeviceListFind (pciDeviceList *list, - pciDevice *dev); -int pciDeviceListFindIndex(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)(pciDevice *dev, - const char *path, void *opaque); - -int pciDeviceFileIterate(pciDevice *dev, - pciDeviceFileActor actor, - void *opaque); - -int pciDeviceIsAssignable(pciDevice *dev, - int strict_acs_check); -int pciWaitForDeviceCleanup(pciDevice *dev, const char *matcher); - -int pciGetPhysicalFunction(const char *sysfs_path, - struct pci_config_address **phys_fn); - -int pciGetVirtualFunctions(const char *sysfs_path, - struct pci_config_address ***virtual_functions, - unsigned int *num_virtual_functions); - -int pciDeviceIsVirtualFunction(const char *vf_sysfs_device_link); - -int pciGetVirtualFunctionIndex(const char *pf_sysfs_device_link, - const char *vf_sysfs_device_link, - int *vf_index); - -int pciConfigAddressToSysfsFile(struct pci_config_address *dev, - char **pci_sysfs_device_link); - -int pciDeviceNetName(char *device_link_sysfs_path, char **netname); - -int pciSysfsFile(char *pciDeviceName, char **pci_sysfs_device_link) - ATTRIBUTE_RETURN_CHECK; - -int pciGetDeviceAddrString(unsigned domain, - unsigned bus, - unsigned slot, - unsigned function, - char **pciConfigAddr) - ATTRIBUTE_NONNULL(5) ATTRIBUTE_RETURN_CHECK; - -int pciDeviceGetVirtualFunctionInfo(const char *vf_sysfs_device_path, - char **pfname, int *vf_index); - -#endif /* __VIR_PCI_H__ */ diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 88a2e4b..3ea0e39 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -28,7 +28,7 @@ #include "virterror_internal.h" #include "vircommand.h" #include "viralloc.h" -#include "pci.h" +#include "virpci.h" #include "virlog.h" #include <sys/ioctl.h> diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h index 123667c..d588e89 100644 --- a/src/util/virnetdev.h +++ b/src/util/virnetdev.h @@ -26,7 +26,7 @@ # include "virsocketaddr.h" # include "virnetlink.h" # include "virmacaddr.h" -# include "pci.h" +# include "virpci.h" int virNetDevExists(const char *brname) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; diff --git a/src/util/virpci.c b/src/util/virpci.c new file mode 100644 index 0000000..8875aa6 --- /dev/null +++ b/src/util/virpci.c @@ -0,0 +1,2285 @@ +/* + * Copyright (C) 2009-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Mark McLoughlin <markmc@redhat.com> + */ + +#include <config.h> + +#include "virpci.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 <stdlib.h> + +#include "virlog.h" +#include "viralloc.h" +#include "vircommand.h" +#include "virterror_internal.h" +#include "virfile.h" + +#define PCI_SYSFS "/sys/bus/pci/" +#define PCI_ID_LEN 10 /* "XXXX XXXX" */ +#define PCI_ADDR_LEN 13 /* "XXXX:XX:XX.X" */ + +#define SRIOV_FOUND 0 +#define SRIOV_NOT_FOUND 1 +#define SRIOV_ERROR -1 + +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; + const char *used_by; /* The domain which uses the device */ + + unsigned pcie_cap_pos; + unsigned pci_pm_cap_pos; + unsigned has_flr : 1; + unsigned has_pm_reset : 1; + unsigned managed : 1; + + /* used by reattach function */ + unsigned unbind_from_stub : 1; + unsigned remove_slot : 1; + unsigned reprobe : 1; +}; + +struct _pciDeviceList { + unsigned count; + pciDevice **devs; +}; + + +/* For virReportOOMError() and virReportSystemError() */ +#define VIR_FROM_THIS VIR_FROM_NONE + +/* 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 */ + +#define PCI_EXP_FLAGS 0x2 +#define PCI_EXP_FLAGS_TYPE 0x00f0 +#define PCI_EXP_TYPE_DOWNSTREAM 0x6 + +#define PCI_EXT_CAP_BASE 0x100 +#define PCI_EXT_CAP_LIMIT 0x1000 +#define PCI_EXT_CAP_ID_MASK 0x0000ffff +#define PCI_EXT_CAP_OFFSET_SHIFT 20 +#define PCI_EXT_CAP_OFFSET_MASK 0x00000ffc + +#define PCI_EXT_CAP_ID_ACS 0x000d +#define PCI_EXT_ACS_CTRL 0x06 + +#define PCI_EXT_CAP_ACS_SV 0x01 +#define PCI_EXT_CAP_ACS_RR 0x04 +#define PCI_EXT_CAP_ACS_CR 0x08 +#define PCI_EXT_CAP_ACS_UF 0x10 +#define PCI_EXT_CAP_ACS_ENABLED (PCI_EXT_CAP_ACS_SV | \ + PCI_EXT_CAP_ACS_RR | \ + PCI_EXT_CAP_ACS_CR | \ + PCI_EXT_CAP_ACS_UF) + +static int +pciConfigOpen(pciDevice *dev, bool fatal) +{ + int fd; + + fd = open(dev->path, O_RDWR); + + if (fd < 0) { + if (fatal) { + virReportSystemError(errno, + _("Failed to open config space file '%s'"), + dev->path); + } else { + 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); + return fd; +} + +static void +pciConfigClose(pciDevice *dev, int cfgfd) +{ + if (VIR_CLOSE(cfgfd) < 0) { + char ebuf[1024]; + VIR_WARN("Failed to close config space file '%s': %s", + dev->path, virStrerror(errno, ebuf, sizeof(ebuf))); + } +} + + +static int +pciRead(pciDevice *dev, + int cfgfd, + unsigned pos, + uint8_t *buf, + unsigned buflen) +{ + memset(buf, 0, buflen); + + if (lseek(cfgfd, pos, SEEK_SET) != pos || + saferead(cfgfd, 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, int cfgfd, unsigned pos) +{ + uint8_t buf; + pciRead(dev, cfgfd, pos, &buf, sizeof(buf)); + return buf; +} + +static uint16_t +pciRead16(pciDevice *dev, int cfgfd, unsigned pos) +{ + uint8_t buf[2]; + pciRead(dev, cfgfd, pos, &buf[0], sizeof(buf)); + return (buf[0] << 0) | (buf[1] << 8); +} + +static uint32_t +pciRead32(pciDevice *dev, int cfgfd, unsigned pos) +{ + uint8_t buf[4]; + pciRead(dev, cfgfd, pos, &buf[0], sizeof(buf)); + return (buf[0] << 0) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} + +static int +pciWrite(pciDevice *dev, + int cfgfd, + unsigned pos, + uint8_t *buf, + unsigned buflen) +{ + if (lseek(cfgfd, pos, SEEK_SET) != pos || + safewrite(cfgfd, 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, int cfgfd, unsigned pos, uint16_t val) +{ + uint8_t buf[2] = { (val >> 0), (val >> 8) }; + pciWrite(dev, cfgfd, pos, &buf[0], sizeof(buf)); +} + +static void +pciWrite32(pciDevice *dev, int cfgfd, unsigned pos, uint32_t val) +{ + uint8_t buf[4] = { (val >> 0), (val >> 8), (val >> 16), (val >> 24) }; + pciWrite(dev, cfgfd, 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(pciIterPredicate predicate, + pciDevice *dev, + pciDevice **matched, + void *data) +{ + DIR *dir; + struct dirent *entry; + int ret = 0; + int rc; + + *matched = NULL; + + VIR_DEBUG("%s %s: iterating over " PCI_SYSFS "devices", dev->id, dev->name); + + dir = opendir(PCI_SYSFS "devices"); + if (!dir) { + VIR_WARN("Failed to open " PCI_SYSFS "devices"); + return -1; + } + + while ((entry = readdir(dir))) { + unsigned int domain, bus, slot, function; + pciDevice *check; + char *tmp; + + /* Ignore '.' and '..' */ + if (entry->d_name[0] == '.') + continue; + + /* expected format: <domain>:<bus>:<slot>.<function> */ + if (/* domain */ + virStrToLong_ui(entry->d_name, &tmp, 16, &domain) < 0 || *tmp != ':' || + /* bus */ + virStrToLong_ui(tmp + 1, &tmp, 16, &bus) < 0 || *tmp != ':' || + /* slot */ + virStrToLong_ui(tmp + 1, &tmp, 16, &slot) < 0 || *tmp != '.' || + /* function */ + virStrToLong_ui(tmp + 1, NULL, 16, &function) < 0) { + VIR_WARN("Unusual entry in " PCI_SYSFS "devices: %s", entry->d_name); + continue; + } + + check = pciGetDevice(domain, bus, slot, function); + if (!check) { + ret = -1; + break; + } + + rc = predicate(dev, check, data); + if (rc < 0) { + /* the predicate returned an error, bail */ + pciFreeDevice(check); + ret = -1; + break; + } + else if (rc == 1) { + VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name); + *matched = check; + ret = 1; + break; + } + + pciFreeDevice(check); + } + closedir(dir); + return ret; +} + +static uint8_t +pciFindCapabilityOffset(pciDevice *dev, int cfgfd, unsigned capability) +{ + uint16_t status; + uint8_t pos; + + status = pciRead16(dev, cfgfd, PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + + pos = pciRead8(dev, cfgfd, 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, cfgfd, 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, cfgfd, pos + 1); + } + + VIR_DEBUG("%s %s: failed to find cap 0x%.2x", dev->id, dev->name, capability); + + return 0; +} + +static unsigned int +pciFindExtendedCapabilityOffset(pciDevice *dev, + int cfgfd, + unsigned capability) +{ + int ttl; + unsigned int pos; + uint32_t header; + + /* minimum 8 bytes per capability */ + ttl = (PCI_EXT_CAP_LIMIT - PCI_EXT_CAP_BASE) / 8; + pos = PCI_EXT_CAP_BASE; + + while (ttl > 0 && pos >= PCI_EXT_CAP_BASE) { + header = pciRead32(dev, cfgfd, pos); + + if ((header & PCI_EXT_CAP_ID_MASK) == capability) + return pos; + + pos = (header >> PCI_EXT_CAP_OFFSET_SHIFT) & PCI_EXT_CAP_OFFSET_MASK; + ttl--; + } + + return 0; +} + +/* detects whether this device has FLR. Returns 0 if the device does + * not have FLR, 1 if it does, and -1 on error + */ +static int +pciDetectFunctionLevelReset(pciDevice *dev, int cfgfd) +{ + uint32_t caps; + uint8_t pos; + char *path; + int found; + + /* 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, cfgfd, 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, cfgfd, PCI_CAP_ID_AF); + if (pos) { + caps = pciRead16(dev, cfgfd, pos + PCI_AF_CAP); + if (caps & PCI_AF_CAP_FLR) { + VIR_DEBUG("%s %s: detected PCI FLR capability", dev->id, dev->name); + return 1; + } + } + + /* there are some buggy devices that do support FLR, but forget to + * advertise that fact in their capabilities. However, FLR is *required* + * to be present for virtual functions (VFs), so if we see that this + * device is a VF, we just assume FLR works + */ + + if (virAsprintf(&path, PCI_SYSFS "devices/%s/physfn", dev->name) < 0) { + virReportOOMError(); + return -1; + } + + found = virFileExists(path); + VIR_FREE(path); + if (found) { + VIR_DEBUG("%s %s: buggy device didn't advertise FLR, but is a VF; forcing flr on", + 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, int cfgfd) +{ + if (dev->pci_pm_cap_pos) { + uint32_t ctl; + + /* require the NO_SOFT_RESET bit is clear */ + ctl = pciRead32(dev, cfgfd, 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 on the same domain/bus ? */ +static int +pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data) +{ + pciDeviceList *inactiveDevs = data; + + /* Different domain, different bus, or simply identical device */ + if (dev->domain != check->domain || + dev->bus != check->bus || + (dev->slot == check->slot && + dev->function == check->function)) + return 0; + + /* same bus, but inactive, i.e. about to be assigned to guest */ + if (inactiveDevs && pciDeviceListFind(inactiveDevs, check)) + return 0; + + return 1; +} + +static pciDevice * +pciBusContainsActiveDevices(pciDevice *dev, + pciDeviceList *inactiveDevs) +{ + pciDevice *active = NULL; + if (pciIterDevices(pciSharesBusWithActive, + dev, &active, inactiveDevs) < 0) + return NULL; + return active; +} + +/* Is @check the parent of @dev ? */ +static int +pciIsParent(pciDevice *dev, pciDevice *check, void *data) +{ + uint16_t device_class; + uint8_t header_type, secondary, subordinate; + pciDevice **best = data; + int ret = 0; + int fd; + + if (dev->domain != check->domain) + return 0; + + if ((fd = pciConfigOpen(check, false)) < 0) + return 0; + + /* Is it a bridge? */ + device_class = pciRead16(check, fd, PCI_CLASS_DEVICE); + if (device_class != PCI_CLASS_BRIDGE_PCI) + goto cleanup; + + /* Is it a plane? */ + header_type = pciRead8(check, fd, PCI_HEADER_TYPE); + if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) + goto cleanup; + + secondary = pciRead8(check, fd, PCI_SECONDARY_BUS); + subordinate = pciRead8(check, fd, PCI_SUBORDINATE_BUS); + + VIR_DEBUG("%s %s: found parent device %s", dev->id, dev->name, check->name); + + /* if the secondary bus exactly equals the device's bus, then we found + * the direct parent. No further work is necessary + */ + if (dev->bus == secondary) { + ret = 1; + goto cleanup; + } + + /* otherwise, SRIOV allows VFs to be on different busses then their PFs. + * In this case, what we need to do is look for the "best" match; i.e. + * the most restrictive match that still satisfies all of the conditions. + */ + if (dev->bus > secondary && dev->bus <= subordinate) { + if (*best == NULL) { + *best = pciGetDevice(check->domain, check->bus, check->slot, + check->function); + if (*best == NULL) { + ret = -1; + goto cleanup; + } + } else { + /* OK, we had already recorded a previous "best" match for the + * parent. See if the current device is more restrictive than the + * best, and if so, make it the new best + */ + int bestfd; + uint8_t best_secondary; + + if ((bestfd = pciConfigOpen(*best, false)) < 0) + goto cleanup; + best_secondary = pciRead8(*best, bestfd, PCI_SECONDARY_BUS); + pciConfigClose(*best, bestfd); + + if (secondary > best_secondary) { + pciFreeDevice(*best); + *best = pciGetDevice(check->domain, check->bus, check->slot, + check->function); + if (*best == NULL) { + ret = -1; + goto cleanup; + } + } + } + } + +cleanup: + pciConfigClose(check, fd); + return ret; +} + +static int +pciGetParentDevice(pciDevice *dev, pciDevice **parent) +{ + pciDevice *best = NULL; + int ret; + + *parent = NULL; + ret = pciIterDevices(pciIsParent, dev, parent, &best); + if (ret == 1) + pciFreeDevice(best); + else if (ret == 0) + *parent = best; + return ret; +} + +/* Secondary Bus Reset is our sledgehammer - it resets all + * devices behind a bus. + */ +static int +pciTrySecondaryBusReset(pciDevice *dev, + int cfgfd, + pciDeviceList *inactiveDevs) +{ + pciDevice *parent, *conflict; + uint8_t config_space[PCI_CONF_LEN]; + uint16_t ctl; + int ret = -1; + int parentfd; + + /* Refuse to do a secondary bus reset if there are other + * devices/functions behind the bus are used by the host + * or other guests. + */ + if ((conflict = pciBusContainsActiveDevices(dev, inactiveDevs))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Active %s devices on bus with %s, not doing bus reset"), + conflict->name, dev->name); + return -1; + } + + /* Find the parent bus */ + if (pciGetParentDevice(dev, &parent) < 0) + return -1; + if (!parent) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to find parent device for %s"), + dev->name); + return -1; + } + if ((parentfd = pciConfigOpen(parent, true)) < 0) + goto out; + + 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, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to read 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, cfgfd, PCI_BRIDGE_CONTROL); + + pciWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, + ctl | PCI_BRIDGE_CTL_RESET); + + usleep(200 * 1000); /* sleep 200ms */ + + pciWrite16(parent, parentfd, PCI_BRIDGE_CONTROL, ctl); + + usleep(200 * 1000); /* sleep 200ms */ + + if (pciWrite(dev, cfgfd, 0, config_space, PCI_CONF_LEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to restore PCI config space for %s"), + dev->name); + goto out; + } + ret = 0; + +out: + pciConfigClose(parent, parentfd); + pciFreeDevice(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(pciDevice *dev, int cfgfd) +{ + 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, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to read 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, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL); + ctl &= ~PCI_PM_CTRL_STATE_MASK; + + pciWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL, + ctl | PCI_PM_CTRL_STATE_D3hot); + + usleep(10 * 1000); /* sleep 10ms */ + + pciWrite32(dev, cfgfd, dev->pci_pm_cap_pos + PCI_PM_CTRL, + ctl | PCI_PM_CTRL_STATE_D0); + + usleep(10 * 1000); /* sleep 10ms */ + + if (pciWrite(dev, cfgfd, 0, &config_space[0], PCI_CONF_LEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to restore PCI config space for %s"), + dev->name); + return -1; + } + + return 0; +} + +static int +pciInitDevice(pciDevice *dev, int cfgfd) +{ + int flr; + + dev->pcie_cap_pos = pciFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_EXP); + dev->pci_pm_cap_pos = pciFindCapabilityOffset(dev, cfgfd, PCI_CAP_ID_PM); + flr = pciDetectFunctionLevelReset(dev, cfgfd); + if (flr < 0) + return flr; + dev->has_flr = flr; + dev->has_pm_reset = pciDetectPowerManagementReset(dev, cfgfd); + + return 0; +} + +int +pciResetDevice(pciDevice *dev, + pciDeviceList *activeDevs, + pciDeviceList *inactiveDevs) +{ + int ret = -1; + int fd; + + if (activeDevs && pciDeviceListFind(activeDevs, dev)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Not resetting active device %s"), dev->name); + return -1; + } + + if ((fd = pciConfigOpen(dev, true)) < 0) + return -1; + + if (pciInitDevice(dev, fd) < 0) + goto cleanup; + + /* 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) { + ret = 0; + goto cleanup; + } + + /* 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(dev, fd); + + /* Bus reset is not an option with the root bus */ + if (ret < 0 && dev->bus != 0) + ret = pciTrySecondaryBusReset(dev, fd, inactiveDevs); + + if (ret < 0) { + virErrorPtr err = virGetLastError(); + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unable to reset PCI device %s: %s"), + dev->name, + err ? err->message : _("no FLR, PM reset or bus reset available")); + } + +cleanup: + pciConfigClose(dev, fd); + return ret; +} + + +static int +pciDriverDir(char **buffer, const char *driver) +{ + VIR_FREE(*buffer); + + if (virAsprintf(buffer, PCI_SYSFS "drivers/%s", driver) < 0) { + virReportOOMError(); + return -1; + } + + return 0; +} + +static int +pciDriverFile(char **buffer, const char *driver, const char *file) +{ + VIR_FREE(*buffer); + + if (virAsprintf(buffer, PCI_SYSFS "drivers/%s/%s", driver, file) < 0) { + virReportOOMError(); + return -1; + } + + return 0; +} + +static int +pciDeviceFile(char **buffer, const char *device, const char *file) +{ + VIR_FREE(*buffer); + + if (virAsprintf(buffer, PCI_SYSFS "devices/%s/%s", device, file) < 0) { + virReportOOMError(); + return -1; + } + + return 0; +} + + +static const char * +pciFindStubDriver(void) +{ + char *drvpath = NULL; + int probed = 0; + +recheck: + if (pciDriverDir(&drvpath, "pci-stub") < 0) { + return NULL; + } + + if (virFileExists(drvpath)) { + VIR_FREE(drvpath); + return "pci-stub"; + } + + if (pciDriverDir(&drvpath, "pciback") < 0) { + return NULL; + } + + if (virFileExists(drvpath)) { + VIR_FREE(drvpath); + return "pciback"; + } + + VIR_FREE(drvpath); + + 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(backprobe, NULL) < 0 && + virRun(stubprobe, NULL) < 0) { + char ebuf[1024]; + VIR_WARN("failed to load pci-stub or pciback drivers: %s", + virStrerror(errno, ebuf, sizeof(ebuf))); + return NULL; + } + + goto recheck; + } + + return NULL; +} + +static int +pciUnbindDeviceFromStub(pciDevice *dev, const char *driver) +{ + int result = -1; + char *drvdir = NULL; + char *path = NULL; + + if (pciDriverDir(&drvdir, driver) < 0) + goto cleanup; + + if (!dev->unbind_from_stub) + goto remove_slot; + + /* If the device is bound to stub, unbind it. + */ + if (pciDeviceFile(&path, dev->name, "driver") < 0) + goto cleanup; + + if (virFileExists(drvdir) && virFileLinkPointsTo(path, drvdir)) { + if (pciDriverFile(&path, driver, "unbind") < 0) { + goto cleanup; + } + + if (virFileWriteStr(path, dev->name, 0) < 0) { + virReportSystemError(errno, + _("Failed to unbind PCI device '%s' from %s"), + dev->name, driver); + goto cleanup; + } + } + dev->unbind_from_stub = 0; + +remove_slot: + if (!dev->remove_slot) + goto reprobe; + + /* Xen's pciback.ko wants you to use remove_slot on the specific device */ + if (pciDriverFile(&path, driver, "remove_slot") < 0) { + goto cleanup; + } + + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { + virReportSystemError(errno, + _("Failed to remove slot for PCI device '%s' from %s"), + dev->name, driver); + goto cleanup; + } + dev->remove_slot = 0; + +reprobe: + if (!dev->reprobe) { + result = 0; + goto cleanup; + } + + /* 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. + */ + if (pciDriverFile(&path, driver, "remove_id") < 0) { + goto cleanup; + } + + if (!virFileExists(drvdir) || virFileExists(path)) { + if (virFileWriteStr(PCI_SYSFS "drivers_probe", dev->name, 0) < 0) { + virReportSystemError(errno, + _("Failed to trigger a re-probe for PCI device '%s'"), + dev->name); + goto cleanup; + } + } + + result = 0; + +cleanup: + /* do not do it again */ + dev->unbind_from_stub = 0; + dev->remove_slot = 0; + dev->reprobe = 0; + + VIR_FREE(drvdir); + VIR_FREE(path); + + return result; +} + + +static int +pciBindDeviceToStub(pciDevice *dev, const char *driver) +{ + int result = -1; + char *drvdir = NULL; + char *path = NULL; + int reprobe = 0; + + /* check whether the device is already bound to a driver */ + if (pciDriverDir(&drvdir, driver) < 0 || + pciDeviceFile(&path, dev->name, "driver") < 0) { + goto cleanup; + } + + if (virFileExists(path)) { + if (virFileLinkPointsTo(path, drvdir)) { + /* The device is already bound to pci-stub */ + result = 0; + goto cleanup; + } + reprobe = 1; + } + + /* 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. + */ + if (pciDriverFile(&path, driver, "new_id") < 0) { + goto cleanup; + } + + if (virFileWriteStr(path, dev->id, 0) < 0) { + virReportSystemError(errno, + _("Failed to add PCI device ID '%s' to %s"), + dev->id, driver); + goto cleanup; + } + + /* check whether the device is bound to pci-stub when we write dev->id to + * new_id. + */ + if (pciDriverDir(&drvdir, driver) < 0 || + pciDeviceFile(&path, dev->name, "driver") < 0) { + goto remove_id; + } + + if (virFileLinkPointsTo(path, drvdir)) { + dev->unbind_from_stub = 1; + dev->remove_slot = 1; + goto remove_id; + } + + /* 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. + */ + if (pciDeviceFile(&path, dev->name, "driver/unbind") < 0) { + goto cleanup; + } + + if (virFileExists(path)) { + if (virFileWriteStr(path, dev->name, 0) < 0) { + virReportSystemError(errno, + _("Failed to unbind PCI device '%s'"), + dev->name); + goto cleanup; + } + dev->reprobe = reprobe; + } + + /* If the device isn't already bound to pci-stub, try binding it now. + */ + if (pciDriverDir(&drvdir, driver) < 0 || + pciDeviceFile(&path, dev->name, "driver") < 0) { + goto remove_id; + } + + if (!virFileLinkPointsTo(path, drvdir)) { + /* Xen's pciback.ko wants you to use new_slot first */ + if (pciDriverFile(&path, driver, "new_slot") < 0) { + goto remove_id; + } + + if (virFileExists(path) && virFileWriteStr(path, dev->name, 0) < 0) { + virReportSystemError(errno, + _("Failed to add slot for PCI device '%s' to %s"), + dev->name, driver); + goto remove_id; + } + dev->remove_slot = 1; + + if (pciDriverFile(&path, driver, "bind") < 0) { + goto remove_id; + } + + if (virFileWriteStr(path, dev->name, 0) < 0) { + virReportSystemError(errno, + _("Failed to bind PCI device '%s' to %s"), + dev->name, driver); + goto remove_id; + } + dev->unbind_from_stub = 1; + } + +remove_id: + /* If 'remove_id' exists, remove the device id from pci-stub's dynamic + * ID table so that 'drivers_probe' works below. + */ + if (pciDriverFile(&path, driver, "remove_id") < 0) { + /* We do not remove PCI ID from pci-stub, and we cannot reprobe it */ + if (dev->reprobe) { + VIR_WARN("Could not remove PCI ID '%s' from %s, and the device " + "cannot be probed again.", dev->id, driver); + } + dev->reprobe = 0; + goto cleanup; + } + + if (virFileExists(path) && virFileWriteStr(path, dev->id, 0) < 0) { + virReportSystemError(errno, + _("Failed to remove PCI ID '%s' from %s"), + dev->id, driver); + + /* remove PCI ID from pci-stub failed, and we cannot reprobe it */ + if (dev->reprobe) { + VIR_WARN("Failed to remove PCI ID '%s' from %s, and the device " + "cannot be probed again.", dev->id, driver); + } + dev->reprobe = 0; + goto cleanup; + } + + result = 0; + +cleanup: + VIR_FREE(drvdir); + VIR_FREE(path); + + if (result < 0) { + pciUnbindDeviceFromStub(dev, driver); + } + + return result; +} + +int +pciDettachDevice(pciDevice *dev, + pciDeviceList *activeDevs, + pciDeviceList *inactiveDevs) +{ + const char *driver = pciFindStubDriver(); + if (!driver) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot find any PCI stub module")); + return -1; + } + + if (activeDevs && pciDeviceListFind(activeDevs, dev)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Not detaching active device %s"), dev->name); + return -1; + } + + if (pciBindDeviceToStub(dev, driver) < 0) + return -1; + + /* Add the dev into list inactiveDevs */ + if (inactiveDevs && !pciDeviceListFind(inactiveDevs, dev)) { + if (pciDeviceListAdd(inactiveDevs, dev) < 0) + return -1; + } + + return 0; +} + +int +pciReAttachDevice(pciDevice *dev, + pciDeviceList *activeDevs, + pciDeviceList *inactiveDevs) +{ + const char *driver = pciFindStubDriver(); + if (!driver) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot find any PCI stub module")); + return -1; + } + + if (activeDevs && pciDeviceListFind(activeDevs, dev)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Not reattaching active device %s"), dev->name); + return -1; + } + + if (pciUnbindDeviceFromStub(dev, driver) < 0) + return -1; + + /* Steal the dev from list inactiveDevs */ + if (inactiveDevs) + pciDeviceListSteal(inactiveDevs, dev); + + return 0; +} + +/* Certain hypervisors (like qemu/kvm) map the PCI bar(s) on + * the host when doing device passthrough. This can lead to a race + * condition where the hypervisor is still cleaning up the device while + * libvirt is trying to re-attach it to the host device driver. To avoid + * this situation, we look through /proc/iomem, and if the hypervisor is + * still holding onto the bar (denoted by the string in the matcher variable), + * then we can wait around a bit for that to clear up. + * + * A typical /proc/iomem looks like this (snipped for brevity): + * 00010000-0008efff : System RAM + * 0008f000-0008ffff : reserved + * ... + * 00100000-cc9fcfff : System RAM + * 00200000-00483d3b : Kernel code + * 00483d3c-005c88df : Kernel data + * cc9fd000-ccc71fff : ACPI Non-volatile Storage + * ... + * d0200000-d02fffff : PCI Bus #05 + * d0200000-d021ffff : 0000:05:00.0 + * d0200000-d021ffff : e1000e + * d0220000-d023ffff : 0000:05:00.0 + * d0220000-d023ffff : e1000e + * ... + * f0000000-f0003fff : 0000:00:1b.0 + * f0000000-f0003fff : kvm_assigned_device + * + * Returns 0 if we are clear to continue, and 1 if the hypervisor is still + * holding onto the resource. + */ +int +pciWaitForDeviceCleanup(pciDevice *dev, const char *matcher) +{ + FILE *fp; + char line[160]; + char *tmp; + unsigned long long start, end; + unsigned int domain, bus, slot, function; + int in_matching_device; + int ret; + size_t match_depth; + + fp = fopen("/proc/iomem", "r"); + if (!fp) { + /* If we failed to open iomem, we just basically ignore the error. The + * unbind might succeed anyway, and besides, it's very likely we have + * no way to report the error + */ + VIR_DEBUG("Failed to open /proc/iomem, trying to continue anyway"); + return 0; + } + + ret = 0; + in_matching_device = 0; + match_depth = 0; + while (fgets(line, sizeof(line), fp) != 0) { + /* the logic here is a bit confusing. For each line, we look to + * see if it matches the domain:bus:slot.function we were given. + * If this line matches the DBSF, then any subsequent lines indented + * by 2 spaces are the PCI regions for this device. It's also + * possible that none of the PCI regions are currently mapped, in + * which case we have no indented regions. This code handles all + * of these situations + */ + if (in_matching_device && (strspn(line, " ") == (match_depth + 2))) { + /* expected format: <start>-<end> : <suffix> */ + if (/* start */ + virStrToLong_ull(line, &tmp, 16, &start) < 0 || *tmp != '-' || + /* end */ + virStrToLong_ull(tmp + 1, &tmp, 16, &end) < 0 || + (tmp = STRSKIP(tmp, " : ")) == NULL) + continue; + + if (STRPREFIX(tmp, matcher)) { + ret = 1; + break; + } + } + else { + in_matching_device = 0; + + /* expected format: <start>-<end> : <domain>:<bus>:<slot>.<function> */ + if (/* start */ + virStrToLong_ull(line, &tmp, 16, &start) < 0 || *tmp != '-' || + /* end */ + virStrToLong_ull(tmp + 1, &tmp, 16, &end) < 0 || + (tmp = STRSKIP(tmp, " : ")) == NULL || + /* domain */ + virStrToLong_ui(tmp, &tmp, 16, &domain) < 0 || *tmp != ':' || + /* bus */ + virStrToLong_ui(tmp + 1, &tmp, 16, &bus) < 0 || *tmp != ':' || + /* slot */ + virStrToLong_ui(tmp + 1, &tmp, 16, &slot) < 0 || *tmp != '.' || + /* function */ + virStrToLong_ui(tmp + 1, &tmp, 16, &function) < 0 || *tmp != '\n') + continue; + + if (domain != dev->domain || bus != dev->bus || slot != dev->slot || + function != dev->function) + continue; + in_matching_device = 1; + match_depth = strspn(line, " "); + } + } + + VIR_FORCE_FCLOSE(fp); + + return ret; +} + +static char * +pciReadDeviceID(pciDevice *dev, const char *id_name) +{ + char *path = NULL; + char *id_str; + + if (pciDeviceFile(&path, dev->name, id_name) < 0) { + return NULL; + } + + /* ID string is '0xNNNN\n' ... i.e. 7 bytes */ + if (virFileReadAll(path, 7, &id_str) < 0) { + VIR_FREE(path); + return NULL; + } + + VIR_FREE(path); + + /* 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; +} + +int +pciGetDeviceAddrString(unsigned domain, + unsigned bus, + unsigned slot, + unsigned function, + char **pciConfigAddr) +{ + pciDevice *dev = NULL; + int ret = -1; + + dev = pciGetDevice(domain, bus, slot, function); + if (dev != NULL) { + if ((*pciConfigAddr = strdup(dev->name)) == NULL) { + virReportOOMError(); + goto cleanup; + } + ret = 0; + } + +cleanup: + pciFreeDevice(dev); + return ret; +} + +pciDevice * +pciGetDevice(unsigned domain, + unsigned bus, + unsigned slot, + unsigned function) +{ + pciDevice *dev; + char *vendor = NULL; + char *product = NULL; + + if (VIR_ALLOC(dev) < 0) { + virReportOOMError(); + return NULL; + } + + dev->domain = domain; + dev->bus = bus; + dev->slot = slot; + dev->function = function; + + if (snprintf(dev->name, sizeof(dev->name), "%.4x:%.2x:%.2x.%.1x", + dev->domain, dev->bus, dev->slot, + dev->function) >= sizeof(dev->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("dev->name buffer overflow: %.4x:%.2x:%.2x.%.1x"), + dev->domain, dev->bus, dev->slot, dev->function); + goto error; + } + if (virAsprintf(&dev->path, PCI_SYSFS "devices/%s/config", + dev->name) < 0) { + virReportOOMError(); + goto error; + } + + if (access(dev->path, F_OK) != 0) { + virReportSystemError(errno, + _("Device %s not found: could not access %s"), + dev->name, dev->path); + goto error; + } + + vendor = pciReadDeviceID(dev, "vendor"); + product = pciReadDeviceID(dev, "device"); + + if (!vendor || !product) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to read product/vendor ID for %s"), + dev->name); + goto error; + } + + /* strings contain '0x' prefix */ + if (snprintf(dev->id, sizeof(dev->id), "%s %s", &vendor[2], + &product[2]) >= sizeof(dev->id)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("dev->id buffer overflow: %s %s"), + &vendor[2], &product[2]); + goto error; + } + + VIR_DEBUG("%s %s: initialized", dev->id, dev->name); + +cleanup: + VIR_FREE(product); + VIR_FREE(vendor); + return dev; + +error: + pciFreeDevice(dev); + dev = NULL; + goto cleanup; +} + +void +pciFreeDevice(pciDevice *dev) +{ + if (!dev) + return; + VIR_DEBUG("%s %s: freeing", dev->id, dev->name); + VIR_FREE(dev->path); + VIR_FREE(dev); +} + +const char * +pciDeviceGetName(pciDevice *dev) +{ + return dev->name; +} + +void pciDeviceSetManaged(pciDevice *dev, unsigned managed) +{ + dev->managed = !!managed; +} + +unsigned pciDeviceGetManaged(pciDevice *dev) +{ + return dev->managed; +} + +unsigned +pciDeviceGetUnbindFromStub(pciDevice *dev) +{ + return dev->unbind_from_stub; +} + +void +pciDeviceSetUnbindFromStub(pciDevice *dev, unsigned unbind) +{ + dev->unbind_from_stub = !!unbind; +} + +unsigned +pciDeviceGetRemoveSlot(pciDevice *dev) +{ + return dev->remove_slot; +} + +void +pciDeviceSetRemoveSlot(pciDevice *dev, unsigned remove_slot) +{ + dev->remove_slot = !!remove_slot; +} + +unsigned +pciDeviceGetReprobe(pciDevice *dev) +{ + return dev->reprobe; +} + +void +pciDeviceSetReprobe(pciDevice *dev, unsigned reprobe) +{ + dev->reprobe = !!reprobe; +} + +void +pciDeviceSetUsedBy(pciDevice *dev, const char *name) +{ + dev->used_by = name; +} + +const char * +pciDeviceGetUsedBy(pciDevice *dev) +{ + return dev->used_by; +} + +void pciDeviceReAttachInit(pciDevice *pci) +{ + pci->unbind_from_stub = 1; + pci->remove_slot = 1; + pci->reprobe = 1; +} + + +pciDeviceList * +pciDeviceListNew(void) +{ + pciDeviceList *list; + + if (VIR_ALLOC(list) < 0) { + virReportOOMError(); + return NULL; + } + + return list; +} + +void +pciDeviceListFree(pciDeviceList *list) +{ + int i; + + if (!list) + return; + + for (i = 0; i < list->count; i++) { + pciFreeDevice(list->devs[i]); + list->devs[i] = NULL; + } + + list->count = 0; + VIR_FREE(list->devs); + VIR_FREE(list); +} + +int +pciDeviceListAdd(pciDeviceList *list, + pciDevice *dev) +{ + if (pciDeviceListFind(list, dev)) { + virReportError(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(); + return -1; + } + + list->devs[list->count++] = dev; + + return 0; +} + +pciDevice * +pciDeviceListGet(pciDeviceList *list, + int idx) +{ + if (idx >= list->count) + return NULL; + if (idx < 0) + return NULL; + + return list->devs[idx]; +} + +int +pciDeviceListCount(pciDeviceList *list) +{ + return list->count; +} + +pciDevice * +pciDeviceListStealIndex(pciDeviceList *list, + int idx) +{ + pciDevice *ret; + + if (idx < 0 || idx >= list->count) + return NULL; + + ret = list->devs[idx]; + + if (idx != --list->count) { + memmove(&list->devs[idx], + &list->devs[idx + 1], + sizeof(*list->devs) * (list->count - idx)); + } + + if (VIR_REALLOC_N(list->devs, list->count) < 0) { + ; /* not fatal */ + } + + return ret; +} + +pciDevice * +pciDeviceListSteal(pciDeviceList *list, + pciDevice *dev) +{ + return pciDeviceListStealIndex(list, pciDeviceListFindIndex(list, dev)); +} + +void +pciDeviceListDel(pciDeviceList *list, + pciDevice *dev) +{ + pciDevice *ret = pciDeviceListSteal(list, dev); + if (ret) + pciFreeDevice(ret); +} + +int +pciDeviceListFindIndex(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 i; + return -1; +} + +pciDevice * +pciDeviceListFind(pciDeviceList *list, pciDevice *dev) +{ + int i; + + if ((i = pciDeviceListFindIndex(list, dev)) >= 0) + return list->devs[i]; + else + return NULL; +} + + +int pciDeviceFileIterate(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(); + goto cleanup; + } + + if (!(dir = opendir(pcidir))) { + virReportSystemError(errno, + _("cannot open %s"), pcidir); + goto cleanup; + } + + while ((ent = readdir(dir)) != NULL) { + /* Device assignment requires: + * $PCIDIR/config, $PCIDIR/resource, $PCIDIR/resourceNNN, + * $PCIDIR/rom, $PCIDIR/reset + */ + if (STREQ(ent->d_name, "config") || + STRPREFIX(ent->d_name, "resource") || + STREQ(ent->d_name, "rom") || + STREQ(ent->d_name, "reset")) { + if (virAsprintf(&file, "%s/%s", pcidir, ent->d_name) < 0) { + virReportOOMError(); + goto cleanup; + } + if ((actor)(dev, file, opaque) < 0) + goto cleanup; + + VIR_FREE(file); + } + } + + ret = 0; + +cleanup: + if (dir) + closedir(dir); + VIR_FREE(file); + VIR_FREE(pcidir); + return ret; +} + +static int +pciDeviceDownstreamLacksACS(pciDevice *dev) +{ + uint16_t flags; + uint16_t ctrl; + unsigned int pos; + int fd; + int ret = 0; + + if ((fd = pciConfigOpen(dev, true)) < 0) + return -1; + + if (pciInitDevice(dev, fd) < 0) { + ret = -1; + goto cleanup; + } + + pos = dev->pcie_cap_pos; + if (!pos || pciRead16(dev, fd, PCI_CLASS_DEVICE) != PCI_CLASS_BRIDGE_PCI) + goto cleanup; + + flags = pciRead16(dev, fd, pos + PCI_EXP_FLAGS); + if (((flags & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_DOWNSTREAM) + goto cleanup; + + pos = pciFindExtendedCapabilityOffset(dev, fd, PCI_EXT_CAP_ID_ACS); + if (!pos) { + VIR_DEBUG("%s %s: downstream port lacks ACS", dev->id, dev->name); + ret = 1; + goto cleanup; + } + + ctrl = pciRead16(dev, fd, pos + PCI_EXT_ACS_CTRL); + if ((ctrl & PCI_EXT_CAP_ACS_ENABLED) != PCI_EXT_CAP_ACS_ENABLED) { + VIR_DEBUG("%s %s: downstream port has ACS disabled", + dev->id, dev->name); + ret = 1; + goto cleanup; + } + +cleanup: + pciConfigClose(dev, fd); + return ret; +} + +static int +pciDeviceIsBehindSwitchLackingACS(pciDevice *dev) +{ + pciDevice *parent; + + if (pciGetParentDevice(dev, &parent) < 0) + return -1; + if (!parent) { + /* if we have no parent, and this is the root bus, ACS doesn't come + * into play since devices on the root bus can't P2P without going + * through the root IOMMU. + */ + if (dev->bus == 0) + return 0; + else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to find parent device for %s"), + dev->name); + return -1; + } + } + + /* XXX we should rather fail when we can't find device's parent and + * stop the loop when we get to root instead of just stopping when no + * parent can be found + */ + do { + pciDevice *tmp; + int acs; + int ret; + + acs = pciDeviceDownstreamLacksACS(parent); + + if (acs) { + pciFreeDevice(parent); + if (acs < 0) + return -1; + else + return 1; + } + + tmp = parent; + ret = pciGetParentDevice(parent, &parent); + pciFreeDevice(tmp); + if (ret < 0) + return -1; + } while (parent); + + return 0; +} + +int pciDeviceIsAssignable(pciDevice *dev, + int strict_acs_check) +{ + int ret; + + /* XXX This could be a great place to actually check that a non-managed + * device isn't in use, e.g. by checking that device is either un-bound + * or bound to a stub driver. + */ + + ret = pciDeviceIsBehindSwitchLackingACS(dev); + if (ret < 0) + return 0; + + if (ret) { + if (!strict_acs_check) { + VIR_DEBUG("%s %s: strict ACS check disabled; device assignment allowed", + dev->id, dev->name); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Device %s is behind a switch lacking ACS and " + "cannot be assigned"), + dev->name); + return 0; + } + } + + return 1; +} + +#ifdef __linux__ + +/* + * returns true if equal + */ +static bool +pciConfigAddressEqual(struct pci_config_address *bdf1, + struct pci_config_address *bdf2) +{ + return ((bdf1->domain == bdf2->domain) && + (bdf1->bus == bdf2->bus) && + (bdf1->slot == bdf2->slot) && + (bdf1->function == bdf2->function)); +} + +static int +logStrToLong_ui(char const *s, + char **end_ptr, + int base, + unsigned int *result) +{ + int ret = 0; + + ret = virStrToLong_ui(s, end_ptr, base, result); + if (ret != 0) { + VIR_ERROR(_("Failed to convert '%s' to unsigned int"), s); + } else { + VIR_DEBUG("Converted '%s' to unsigned int %u", s, *result); + } + + return ret; +} + +static int +pciParsePciConfigAddress(char *address, + struct pci_config_address *bdf) +{ + char *p = NULL; + int ret = -1; + + if ((address == NULL) || (logStrToLong_ui(address, &p, 16, + &bdf->domain) == -1)) { + goto out; + } + + if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16, + &bdf->bus) == -1)) { + goto out; + } + + if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16, + &bdf->slot) == -1)) { + goto out; + } + + if ((p == NULL) || (logStrToLong_ui(p+1, &p, 16, + &bdf->function) == -1)) { + goto out; + } + + ret = 0; + +out: + return ret; +} + +static int +pciGetPciConfigAddressFromSysfsDeviceLink(const char *device_link, + struct pci_config_address **bdf) +{ + char *config_address = NULL; + char *device_path = NULL; + char errbuf[64]; + int ret = -1; + + VIR_DEBUG("Attempting to resolve device path from device link '%s'", + device_link); + + if (!virFileExists(device_link)) { + VIR_DEBUG("sysfs_path '%s' does not exist", device_link); + return ret; + } + + device_path = canonicalize_file_name(device_link); + if (device_path == NULL) { + memset(errbuf, '\0', sizeof(errbuf)); + virReportSystemError(errno, + _("Failed to resolve device link '%s'"), + device_link); + return ret; + } + + config_address = basename(device_path); + if (VIR_ALLOC(*bdf) != 0) { + virReportOOMError(); + goto out; + } + + if (pciParsePciConfigAddress(config_address, *bdf) != 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to parse PCI config address '%s'"), + config_address); + VIR_FREE(*bdf); + goto out; + } + + VIR_DEBUG("pci_config_address %.4x:%.2x:%.2x.%.1x", + (*bdf)->domain, + (*bdf)->bus, + (*bdf)->slot, + (*bdf)->function); + + ret = 0; + +out: + VIR_FREE(device_path); + + return ret; +} + +/* + * Returns Physical function given a virtual function + */ +int +pciGetPhysicalFunction(const char *vf_sysfs_path, + struct pci_config_address **physical_function) +{ + int ret = -1; + char *device_link = NULL; + + VIR_DEBUG("Attempting to get SR IOV physical function for device " + "with sysfs path '%s'", vf_sysfs_path); + + if (virBuildPath(&device_link, vf_sysfs_path, "physfn") == -1) { + virReportOOMError(); + return ret; + } else { + ret = pciGetPciConfigAddressFromSysfsDeviceLink(device_link, + physical_function); + } + + VIR_FREE(device_link); + + return ret; +} + +/* + * Returns virtual functions of a physical function + */ +int +pciGetVirtualFunctions(const char *sysfs_path, + struct pci_config_address ***virtual_functions, + unsigned int *num_virtual_functions) +{ + int ret = -1; + DIR *dir = NULL; + struct dirent *entry = NULL; + char *device_link = NULL; + char errbuf[64]; + + VIR_DEBUG("Attempting to get SR IOV virtual functions for device" + "with sysfs path '%s'", sysfs_path); + + dir = opendir(sysfs_path); + if (dir == NULL) { + memset(errbuf, '\0', sizeof(errbuf)); + virReportSystemError(errno, + _("Failed to open dir '%s'"), + sysfs_path); + return ret; + } + + *virtual_functions = NULL; + *num_virtual_functions = 0; + while ((entry = readdir(dir))) { + if (STRPREFIX(entry->d_name, "virtfn")) { + + if (virBuildPath(&device_link, sysfs_path, entry->d_name) == -1) { + virReportOOMError(); + goto out; + } + + VIR_DEBUG("Number of virtual functions: %d", + *num_virtual_functions); + if (VIR_REALLOC_N(*virtual_functions, + (*num_virtual_functions) + 1) != 0) { + virReportOOMError(); + VIR_FREE(device_link); + goto out; + } + + if (pciGetPciConfigAddressFromSysfsDeviceLink(device_link, + &((*virtual_functions)[*num_virtual_functions])) != + SRIOV_FOUND) { + /* We should not get back SRIOV_NOT_FOUND in this + * case, so if we do, it's an error. */ + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to get SR IOV function from device " + "link '%s'"), device_link); + VIR_FREE(device_link); + goto out; + } else { + (*num_virtual_functions)++; + } + VIR_FREE(device_link); + } + } + + ret = 0; + +out: + if (dir) + closedir(dir); + + return ret; +} + +/* + * Returns 1 if vf device is a virtual function, 0 if not, -1 on error + */ +int +pciDeviceIsVirtualFunction(const char *vf_sysfs_device_link) +{ + char *vf_sysfs_physfn_link = NULL; + int ret = -1; + + if (virAsprintf(&vf_sysfs_physfn_link, "%s/physfn", + vf_sysfs_device_link) < 0) { + virReportOOMError(); + return ret; + } + + ret = virFileExists(vf_sysfs_physfn_link); + + VIR_FREE(vf_sysfs_physfn_link); + + return ret; +} + +/* + * Returns the sriov virtual function index of vf given its pf + */ +int +pciGetVirtualFunctionIndex(const char *pf_sysfs_device_link, + const char *vf_sysfs_device_link, + int *vf_index) +{ + int ret = -1, i; + unsigned int num_virt_fns = 0; + struct pci_config_address *vf_bdf = NULL; + struct pci_config_address **virt_fns = NULL; + + if (pciGetPciConfigAddressFromSysfsDeviceLink(vf_sysfs_device_link, + &vf_bdf) < 0) + return ret; + + if (pciGetVirtualFunctions(pf_sysfs_device_link, &virt_fns, + &num_virt_fns) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error getting physical function's '%s' " + "virtual_functions"), pf_sysfs_device_link); + goto out; + } + + for (i = 0; i < num_virt_fns; i++) { + if (pciConfigAddressEqual(vf_bdf, virt_fns[i])) { + *vf_index = i; + ret = 0; + break; + } + } + +out: + + /* free virtual functions */ + for (i = 0; i < num_virt_fns; i++) + VIR_FREE(virt_fns[i]); + + VIR_FREE(virt_fns); + VIR_FREE(vf_bdf); + + return ret; +} + +/* + * Returns a path to the PCI sysfs file given the BDF of the PCI function + */ + +int +pciSysfsFile(char *pciDeviceName, char **pci_sysfs_device_link) +{ + if (virAsprintf(pci_sysfs_device_link, PCI_SYSFS "devices/%s", + pciDeviceName) < 0) { + virReportOOMError(); + return -1; + } + + return 0; +} + +int +pciConfigAddressToSysfsFile(struct pci_config_address *dev, + char **pci_sysfs_device_link) +{ + if (virAsprintf(pci_sysfs_device_link, + PCI_SYSFS "devices/%04x:%02x:%02x.%x", dev->domain, + dev->bus, dev->slot, dev->function) < 0) { + virReportOOMError(); + return -1; + } + + return 0; +} + +/* + * Returns the network device name of a pci device + */ +int +pciDeviceNetName(char *device_link_sysfs_path, char **netname) +{ + char *pcidev_sysfs_net_path = NULL; + int ret = -1; + DIR *dir = NULL; + struct dirent *entry = NULL; + + if (virBuildPath(&pcidev_sysfs_net_path, device_link_sysfs_path, + "net") == -1) { + virReportOOMError(); + return -1; + } + + dir = opendir(pcidev_sysfs_net_path); + if (dir == NULL) + goto out; + + while ((entry = readdir(dir))) { + if (STREQ(entry->d_name, ".") || + STREQ(entry->d_name, "..")) + continue; + + /* Assume a single directory entry */ + *netname = strdup(entry->d_name); + if (!*netname) + virReportOOMError(); + else + ret = 0; + break; + } + + closedir(dir); + +out: + VIR_FREE(pcidev_sysfs_net_path); + + return ret; +} + +int +pciDeviceGetVirtualFunctionInfo(const char *vf_sysfs_device_path, + char **pfname, int *vf_index) +{ + struct pci_config_address *pf_config_address = NULL; + char *pf_sysfs_device_path = NULL; + int ret = -1; + + if (pciGetPhysicalFunction(vf_sysfs_device_path, &pf_config_address) < 0) + return ret; + + if (pciConfigAddressToSysfsFile(pf_config_address, + &pf_sysfs_device_path) < 0) { + + VIR_FREE(pf_config_address); + return ret; + } + + if (pciGetVirtualFunctionIndex(pf_sysfs_device_path, vf_sysfs_device_path, + vf_index) < 0) + goto cleanup; + + ret = pciDeviceNetName(pf_sysfs_device_path, pfname); + +cleanup: + VIR_FREE(pf_config_address); + VIR_FREE(pf_sysfs_device_path); + + return ret; +} + +#else +static const char *unsupported = N_("not supported on non-linux platforms"); + +int +pciGetPhysicalFunction(const char *vf_sysfs_path ATTRIBUTE_UNUSED, + struct pci_config_address **physical_function ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return -1; +} + +int +pciGetVirtualFunctions(const char *sysfs_path ATTRIBUTE_UNUSED, + struct pci_config_address ***virtual_functions ATTRIBUTE_UNUSED, + unsigned int *num_virtual_functions ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return -1; +} + +int +pciDeviceIsVirtualFunction(const char *vf_sysfs_device_link ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return -1; +} + +int +pciGetVirtualFunctionIndex(const char *pf_sysfs_device_link ATTRIBUTE_UNUSED, + const char *vf_sysfs_device_link ATTRIBUTE_UNUSED, + int *vf_index ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return -1; + +} + +int +pciConfigAddressToSysfsFile(struct pci_config_address *dev ATTRIBUTE_UNUSED, + char **pci_sysfs_device_link ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return -1; +} + +int +pciDeviceNetName(char *device_link_sysfs_path ATTRIBUTE_UNUSED, + char **netname ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return -1; +} + +int +pciDeviceGetVirtualFunctionInfo(const char *vf_sysfs_device_path ATTRIBUTE_UNUSED, + char **pfname ATTRIBUTE_UNUSED, + int *vf_index ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(unsupported)); + return -1; +} +#endif /* __linux__ */ diff --git a/src/util/virpci.h b/src/util/virpci.h new file mode 100644 index 0000000..814c24e --- /dev/null +++ b/src/util/virpci.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009, 2011-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Mark McLoughlin <markmc@redhat.com> + */ + +#ifndef __VIR_PCI_H__ +# define __VIR_PCI_H__ + +# include "internal.h" + +typedef struct _pciDevice pciDevice; +typedef struct _pciDeviceList pciDeviceList; + +struct pci_config_address { + unsigned int domain; + unsigned int bus; + unsigned int slot; + unsigned int function; +}; + +pciDevice *pciGetDevice (unsigned domain, + unsigned bus, + unsigned slot, + unsigned function); +void pciFreeDevice (pciDevice *dev); +const char *pciDeviceGetName (pciDevice *dev); +int pciDettachDevice (pciDevice *dev, + pciDeviceList *activeDevs, + pciDeviceList *inactiveDevs); +int pciReAttachDevice (pciDevice *dev, + pciDeviceList *activeDevs, + pciDeviceList *inactiveDevs); +int pciResetDevice (pciDevice *dev, + pciDeviceList *activeDevs, + pciDeviceList *inactiveDevs); +void pciDeviceSetManaged(pciDevice *dev, + unsigned managed); +unsigned pciDeviceGetManaged(pciDevice *dev); +void pciDeviceSetUsedBy(pciDevice *dev, + const char *used_by); +const char *pciDeviceGetUsedBy(pciDevice *dev); +unsigned pciDeviceGetUnbindFromStub(pciDevice *dev); +void pciDeviceSetUnbindFromStub(pciDevice *dev, + unsigned unbind); +unsigned pciDeviceGetRemoveSlot(pciDevice *dev); +void pciDeviceSetRemoveSlot(pciDevice *dev, + unsigned remove_slot); +unsigned pciDeviceGetReprobe(pciDevice *dev); +void pciDeviceSetReprobe(pciDevice *dev, + unsigned reprobe); +void pciDeviceReAttachInit(pciDevice *dev); + +pciDeviceList *pciDeviceListNew (void); +void pciDeviceListFree (pciDeviceList *list); +int pciDeviceListAdd (pciDeviceList *list, + pciDevice *dev); +pciDevice * pciDeviceListGet (pciDeviceList *list, + int idx); +int pciDeviceListCount (pciDeviceList *list); +pciDevice * pciDeviceListSteal (pciDeviceList *list, + pciDevice *dev); +pciDevice * pciDeviceListStealIndex(pciDeviceList *list, + int idx); +void pciDeviceListDel (pciDeviceList *list, + pciDevice *dev); +pciDevice * pciDeviceListFind (pciDeviceList *list, + pciDevice *dev); +int pciDeviceListFindIndex(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)(pciDevice *dev, + const char *path, void *opaque); + +int pciDeviceFileIterate(pciDevice *dev, + pciDeviceFileActor actor, + void *opaque); + +int pciDeviceIsAssignable(pciDevice *dev, + int strict_acs_check); +int pciWaitForDeviceCleanup(pciDevice *dev, const char *matcher); + +int pciGetPhysicalFunction(const char *sysfs_path, + struct pci_config_address **phys_fn); + +int pciGetVirtualFunctions(const char *sysfs_path, + struct pci_config_address ***virtual_functions, + unsigned int *num_virtual_functions); + +int pciDeviceIsVirtualFunction(const char *vf_sysfs_device_link); + +int pciGetVirtualFunctionIndex(const char *pf_sysfs_device_link, + const char *vf_sysfs_device_link, + int *vf_index); + +int pciConfigAddressToSysfsFile(struct pci_config_address *dev, + char **pci_sysfs_device_link); + +int pciDeviceNetName(char *device_link_sysfs_path, char **netname); + +int pciSysfsFile(char *pciDeviceName, char **pci_sysfs_device_link) + ATTRIBUTE_RETURN_CHECK; + +int pciGetDeviceAddrString(unsigned domain, + unsigned bus, + unsigned slot, + unsigned function, + char **pciConfigAddr) + ATTRIBUTE_NONNULL(5) ATTRIBUTE_RETURN_CHECK; + +int pciDeviceGetVirtualFunctionInfo(const char *vf_sysfs_device_path, + char **pfname, int *vf_index); + +#endif /* __VIR_PCI_H__ */ diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 94df116..9b2fcf3 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -57,7 +57,7 @@ #include "util.h" #include "viralloc.h" #include "node_device_conf.h" -#include "pci.h" +#include "virpci.h" #include "uuid.h" #include "fdstream.h" #include "virfile.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 1 - src/Makefile.am | 1 - src/libvirt_private.syms | 7 +- src/lxc/lxc_controller.c | 3 +- src/qemu/qemu_driver.c | 14 ++-- src/qemu/qemu_process.c | 9 +-- src/util/processinfo.c | 189 ----------------------------------------------- src/util/processinfo.h | 34 --------- src/util/virprocess.c | 161 ++++++++++++++++++++++++++++++++++++++++ src/util/virprocess.h | 6 ++ 10 files changed, 181 insertions(+), 244 deletions(-) delete mode 100644 src/util/processinfo.c delete mode 100644 src/util/processinfo.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 18db09b..fb73807 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/processinfo.c src/util/sexpr.c src/util/stats_linux.c src/util/storage_file.c diff --git a/src/Makefile.am b/src/Makefile.am index d9f621f..c0e35dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/processinfo.c util/processinfo.h \ util/sexpr.c util/sexpr.h \ util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 9288ad3..5f79484 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1027,11 +1027,6 @@ pciResetDevice; pciWaitForDeviceCleanup; -# processinfo.h -virProcessInfoGetAffinity; -virProcessInfoSetAffinity; - - # secret_conf.h virSecretDefFormat; virSecretDefFree; @@ -1784,8 +1779,10 @@ virPidFileWritePath; # virprocess.h virProcessAbort; +virProcessGetAffinity; virProcessKill; virProcessKillPainfully; +virProcessSetAffinity; virProcessTranslateStatus; virProcessWait; diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 8a83e71..6b6ec82 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -68,7 +68,6 @@ #include "virfile.h" #include "virpidfile.h" #include "vircommand.h" -#include "processinfo.h" #include "nodeinfo.h" #include "virrandom.h" #include "virprocess.h" @@ -542,7 +541,7 @@ static int virLXCControllerSetupCpuAffinity(virLXCControllerPtr ctrl) * so use '0' to indicate our own process ID. No threads are * running at this point */ - if (virProcessInfoSetAffinity(0 /* Self */, cpumapToSet) < 0) { + if (virProcessSetAffinity(0 /* Self */, cpumapToSet) < 0) { virBitmapFree(cpumap); return -1; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 14a5e44..488c814 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -74,7 +74,7 @@ #include "node_device_conf.h" #include "virpci.h" #include "virusb.h" -#include "processinfo.h" +#include "virprocess.h" #include "libvirt_internal.h" #include "xml.h" #include "cpu/cpu.h" @@ -3881,8 +3881,8 @@ static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, goto cleanup; } } else { - if (virProcessInfoSetAffinity(cpupids[i], - vcpupin->cpumask) < 0) { + if (virProcessSetAffinity(cpupids[i], + vcpupin->cpumask) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to set cpu affinity for vcpu %d"), i); @@ -4155,7 +4155,7 @@ qemuDomainPinVcpuFlags(virDomainPtr dom, goto cleanup; } } else { - if (virProcessInfoSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) { + if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, _("failed to set cpu affinity for vcpu %d"), vcpu); @@ -4423,7 +4423,7 @@ qemuDomainPinEmulator(virDomainPtr dom, } } } else { - if (virProcessInfoSetAffinity(pid, pcpumap) < 0) { + if (virProcessSetAffinity(pid, pcpumap) < 0) { virReportError(VIR_ERR_SYSTEM_ERROR, "%s", _("failed to set cpu affinity for " "emulator threads")); @@ -4641,8 +4641,8 @@ qemuDomainGetVcpus(virDomainPtr dom, unsigned char *tmpmap = NULL; int tmpmapLen = 0; - if (virProcessInfoGetAffinity(priv->vcpupids[v], - &map, maxcpu) < 0) + if (virProcessGetAffinity(priv->vcpupids[v], + &map, maxcpu) < 0) goto cleanup; virBitmapToData(map, &tmpmap, &tmpmapLen); if (tmpmapLen > maplen) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index b20734d..794596b 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -60,7 +60,6 @@ #include "util.h" #include "c-ctype.h" #include "nodeinfo.h" -#include "processinfo.h" #include "domain_audit.h" #include "domain_nwfilter.h" #include "locking/domain_lock.h" @@ -1980,7 +1979,7 @@ qemuProcessInitCpuAffinity(virQEMUDriverPtr driver, * so use '0' to indicate our own process ID. No threads are * running at this point */ - if (virProcessInfoSetAffinity(0 /* Self */, cpumapToSet) < 0) + if (virProcessSetAffinity(0 /* Self */, cpumapToSet) < 0) goto cleanup; ret = 0; @@ -2045,8 +2044,8 @@ qemuProcessSetVcpuAffinites(virConnectPtr conn ATTRIBUTE_UNUSED, for (n = 0; n < def->cputune.nvcpupin; n++) { vcpu = def->cputune.vcpupin[n]->vcpuid; - if (virProcessInfoSetAffinity(priv->vcpupids[vcpu], - def->cputune.vcpupin[n]->cpumask) < 0) { + if (virProcessSetAffinity(priv->vcpupids[vcpu], + def->cputune.vcpupin[n]->cpumask) < 0) { goto cleanup; } } @@ -2072,7 +2071,7 @@ qemuProcessSetEmulatorAffinites(virConnectPtr conn ATTRIBUTE_UNUSED, else return 0; - ret = virProcessInfoSetAffinity(vm->pid, cpumask); + ret = virProcessSetAffinity(vm->pid, cpumask); return ret; } diff --git a/src/util/processinfo.c b/src/util/processinfo.c deleted file mode 100644 index b1db049..0000000 --- a/src/util/processinfo.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2009-2010, 2012 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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Daniel P. Berrange <berrange@redhat.com> - */ - -#include <config.h> - -#include <stdlib.h> -#include <sched.h> - -#include "processinfo.h" -#include "virterror_internal.h" - -#define VIR_FROM_THIS VIR_FROM_NONE - -#if HAVE_SCHED_GETAFFINITY - -int virProcessInfoSetAffinity(pid_t pid, virBitmapPtr map) -{ - int i; - bool set = false; -# ifdef CPU_ALLOC - /* New method dynamically allocates cpu mask, allowing unlimted cpus */ - int numcpus = 1024; - size_t masklen; - cpu_set_t *mask; - - /* Not only may the statically allocated cpu_set_t be too small, - * but there is no way to ask the kernel what size is large enough. - * So you have no option but to pick a size, try, catch EINVAL, - * enlarge, and re-try. - * - * http://lkml.org/lkml/2009/7/28/620 - */ -realloc: - masklen = CPU_ALLOC_SIZE(numcpus); - mask = CPU_ALLOC(numcpus); - - if (!mask) { - virReportOOMError(); - return -1; - } - - CPU_ZERO_S(masklen, mask); - for (i = 0 ; i < virBitmapSize(map); i++) { - if (virBitmapGetBit(map, i, &set) < 0) - return -1; - if (set) - CPU_SET_S(i, masklen, mask); - } - - if (sched_setaffinity(pid, masklen, mask) < 0) { - CPU_FREE(mask); - if (errno == EINVAL && - numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */ - numcpus = numcpus << 2; - goto realloc; - } - virReportSystemError(errno, - _("cannot set CPU affinity on process %d"), pid); - return -1; - } - CPU_FREE(mask); -# else - /* Legacy method uses a fixed size cpu mask, only allows up to 1024 cpus */ - cpu_set_t mask; - - CPU_ZERO(&mask); - for (i = 0 ; i < virBitmapSize(map); i++) { - if (virBitmapGetBit(map, i, &set) < 0) - return -1; - if (set) - CPU_SET(i, &mask); - } - - if (sched_setaffinity(pid, sizeof(mask), &mask) < 0) { - virReportSystemError(errno, - _("cannot set CPU affinity on process %d"), pid); - return -1; - } -# endif - - return 0; -} - -int virProcessInfoGetAffinity(pid_t pid, - virBitmapPtr *map, - int maxcpu) -{ - int i; -# ifdef CPU_ALLOC - /* New method dynamically allocates cpu mask, allowing unlimted cpus */ - int numcpus = 1024; - size_t masklen; - cpu_set_t *mask; - - /* Not only may the statically allocated cpu_set_t be too small, - * but there is no way to ask the kernel what size is large enough. - * So you have no option but to pick a size, try, catch EINVAL, - * enlarge, and re-try. - * - * http://lkml.org/lkml/2009/7/28/620 - */ -realloc: - masklen = CPU_ALLOC_SIZE(numcpus); - mask = CPU_ALLOC(numcpus); - - if (!mask) { - virReportOOMError(); - return -1; - } - - CPU_ZERO_S(masklen, mask); - if (sched_getaffinity(pid, masklen, mask) < 0) { - CPU_FREE(mask); - if (errno == EINVAL && - numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */ - numcpus = numcpus << 2; - goto realloc; - } - virReportSystemError(errno, - _("cannot get CPU affinity of process %d"), pid); - return -1; - } - - *map = virBitmapNew(maxcpu); - if (!*map) { - virReportOOMError(); - return -1; - } - - for (i = 0 ; i < maxcpu ; i++) - if (CPU_ISSET_S(i, masklen, mask)) - ignore_value(virBitmapSetBit(*map, i)); - CPU_FREE(mask); -# else - /* Legacy method uses a fixed size cpu mask, only allows up to 1024 cpus */ - cpu_set_t mask; - - CPU_ZERO(&mask); - if (sched_getaffinity(pid, sizeof(mask), &mask) < 0) { - virReportSystemError(errno, - _("cannot get CPU affinity of process %d"), pid); - return -1; - } - - for (i = 0 ; i < maxcpu ; i++) - if (CPU_ISSET(i, &mask)) - ignore_value(virBitmapSetBit(*map, i)); -# endif - - return 0; -} - -#else /* HAVE_SCHED_GETAFFINITY */ - -int virProcessInfoSetAffinity(pid_t pid ATTRIBUTE_UNUSED, - virBitmapPtr map ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Process CPU affinity is not supported on this platform")); - return -1; -} - -int virProcessInfoGetAffinity(pid_t pid ATTRIBUTE_UNUSED, - virBitmapPtr *map ATTRIBUTE_UNUSED, - int maxcpu ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, "%s", - _("Process CPU affinity is not supported on this platform")); - return -1; -} -#endif /* HAVE_SCHED_GETAFFINITY */ diff --git a/src/util/processinfo.h b/src/util/processinfo.h deleted file mode 100644 index 0ae23c6..0000000 --- a/src/util/processinfo.h +++ /dev/null @@ -1,34 +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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Daniel P. Berrange <berrange@redhat.com> - */ - -#ifndef __VIR_PROCESSINFO_H__ -# define __VIR_PROCESSINFO_H__ - -# include "internal.h" -# include "virbitmap.h" - -int virProcessInfoSetAffinity(pid_t pid, virBitmapPtr map); - -int virProcessInfoGetAffinity(pid_t pid, - virBitmapPtr *map, - int maxcpu); - -#endif /* __VIR_PROCESSINFO_H__ */ diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 8070b8b..155e4e2 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -25,6 +25,7 @@ #include <signal.h> #include <errno.h> #include <sys/wait.h> +#include <sched.h> #include "virprocess.h" #include "virterror_internal.h" @@ -300,3 +301,163 @@ virProcessKillPainfully(pid_t pid, bool force) cleanup: return ret; } + + +#if HAVE_SCHED_GETAFFINITY + +int virProcessSetAffinity(pid_t pid, virBitmapPtr map) +{ + int i; + bool set = false; +# ifdef CPU_ALLOC + /* New method dynamically allocates cpu mask, allowing unlimted cpus */ + int numcpus = 1024; + size_t masklen; + cpu_set_t *mask; + + /* Not only may the statically allocated cpu_set_t be too small, + * but there is no way to ask the kernel what size is large enough. + * So you have no option but to pick a size, try, catch EINVAL, + * enlarge, and re-try. + * + * http://lkml.org/lkml/2009/7/28/620 + */ +realloc: + masklen = CPU_ALLOC_SIZE(numcpus); + mask = CPU_ALLOC(numcpus); + + if (!mask) { + virReportOOMError(); + return -1; + } + + CPU_ZERO_S(masklen, mask); + for (i = 0 ; i < virBitmapSize(map); i++) { + if (virBitmapGetBit(map, i, &set) < 0) + return -1; + if (set) + CPU_SET_S(i, masklen, mask); + } + + if (sched_setaffinity(pid, masklen, mask) < 0) { + CPU_FREE(mask); + if (errno == EINVAL && + numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */ + numcpus = numcpus << 2; + goto realloc; + } + virReportSystemError(errno, + _("cannot set CPU affinity on process %d"), pid); + return -1; + } + CPU_FREE(mask); +# else + /* Legacy method uses a fixed size cpu mask, only allows up to 1024 cpus */ + cpu_set_t mask; + + CPU_ZERO(&mask); + for (i = 0 ; i < virBitmapSize(map); i++) { + if (virBitmapGetBit(map, i, &set) < 0) + return -1; + if (set) + CPU_SET(i, &mask); + } + + if (sched_setaffinity(pid, sizeof(mask), &mask) < 0) { + virReportSystemError(errno, + _("cannot set CPU affinity on process %d"), pid); + return -1; + } +# endif + + return 0; +} + +int virProcessGetAffinity(pid_t pid, + virBitmapPtr *map, + int maxcpu) +{ + int i; +# ifdef CPU_ALLOC + /* New method dynamically allocates cpu mask, allowing unlimted cpus */ + int numcpus = 1024; + size_t masklen; + cpu_set_t *mask; + + /* Not only may the statically allocated cpu_set_t be too small, + * but there is no way to ask the kernel what size is large enough. + * So you have no option but to pick a size, try, catch EINVAL, + * enlarge, and re-try. + * + * http://lkml.org/lkml/2009/7/28/620 + */ +realloc: + masklen = CPU_ALLOC_SIZE(numcpus); + mask = CPU_ALLOC(numcpus); + + if (!mask) { + virReportOOMError(); + return -1; + } + + CPU_ZERO_S(masklen, mask); + if (sched_getaffinity(pid, masklen, mask) < 0) { + CPU_FREE(mask); + if (errno == EINVAL && + numcpus < (1024 << 8)) { /* 262144 cpus ought to be enough for anyone */ + numcpus = numcpus << 2; + goto realloc; + } + virReportSystemError(errno, + _("cannot get CPU affinity of process %d"), pid); + return -1; + } + + *map = virBitmapNew(maxcpu); + if (!*map) { + virReportOOMError(); + return -1; + } + + for (i = 0 ; i < maxcpu ; i++) + if (CPU_ISSET_S(i, masklen, mask)) + ignore_value(virBitmapSetBit(*map, i)); + CPU_FREE(mask); +# else + /* Legacy method uses a fixed size cpu mask, only allows up to 1024 cpus */ + cpu_set_t mask; + + CPU_ZERO(&mask); + if (sched_getaffinity(pid, sizeof(mask), &mask) < 0) { + virReportSystemError(errno, + _("cannot get CPU affinity of process %d"), pid); + return -1; + } + + for (i = 0 ; i < maxcpu ; i++) + if (CPU_ISSET(i, &mask)) + ignore_value(virBitmapSetBit(*map, i)); +# endif + + return 0; +} + +#else /* HAVE_SCHED_GETAFFINITY */ + +int virProcessSetAffinity(pid_t pid ATTRIBUTE_UNUSED, + virBitmapPtr map ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Process CPU affinity is not supported on this platform")); + return -1; +} + +int virProcessGetAffinity(pid_t pid ATTRIBUTE_UNUSED, + virBitmapPtr *map ATTRIBUTE_UNUSED, + int maxcpu ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Process CPU affinity is not supported on this platform")); + return -1; +} +#endif /* HAVE_SCHED_GETAFFINITY */ diff --git a/src/util/virprocess.h b/src/util/virprocess.h index d537d92..8724f64 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -25,6 +25,7 @@ # include <sys/types.h> # include "internal.h" +# include "virbitmap.h" char * virProcessTranslateStatus(int status); @@ -40,5 +41,10 @@ int virProcessKill(pid_t pid, int sig); int virProcessKillPainfully(pid_t pid, bool force); +int virProcessSetAffinity(pid_t pid, virBitmapPtr map); + +int virProcessGetAffinity(pid_t pid, + virBitmapPtr *map, + int maxcpu); #endif /* __VIR_PROCESS_H__ */ -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- cfg.mk | 2 +- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/util/sexpr.c | 625 ------------------------------------------------ src/util/sexpr.h | 58 ----- src/util/virsexpr.c | 625 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virsexpr.h | 58 +++++ src/xen/xend_internal.c | 2 +- src/xenxs/xen_sxpr.h | 2 +- src/xenxs/xen_xm.c | 2 +- 10 files changed, 689 insertions(+), 689 deletions(-) delete mode 100644 src/util/sexpr.c delete mode 100644 src/util/sexpr.h create mode 100644 src/util/virsexpr.c create mode 100644 src/util/virsexpr.h diff --git a/cfg.mk b/cfg.mk index e23f1c5..0a66797 100644 --- a/cfg.mk +++ b/cfg.mk @@ -807,7 +807,7 @@ exclude_file_name_regexp--sc_prohibit_sprintf = \ exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/util\.c$$ exclude_file_name_regexp--sc_prohibit_strtol = \ - ^src/(util/sexpr|(vbox|xen|xenxs)/.*)\.c$$ + ^src/(util/virsexpr|(vbox|xen|xenxs)/.*)\.c$$ exclude_file_name_regexp--sc_prohibit_xmlGetProp = ^src/util/xml\.c$$ diff --git a/po/POTFILES.in b/po/POTFILES.in index fb73807..2b09531 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/sexpr.c src/util/stats_linux.c src/util/storage_file.c src/util/sysinfo.c @@ -173,6 +172,7 @@ src/util/virpci.c src/util/virpidfile.c src/util/virprocess.c src/util/virrandom.c +src/util/virsexpr.c src/util/virsocketaddr.c src/util/virterror.c src/util/virterror_internal.h diff --git a/src/Makefile.am b/src/Makefile.am index c0e35dc..c0dfd38 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/sexpr.c util/sexpr.h \ util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ util/sysinfo.c util/sysinfo.h \ @@ -86,6 +85,7 @@ UTIL_SOURCES = \ util/virpci.c util/virpci.h \ util/virpidfile.c util/virpidfile.h \ util/virprocess.c util/virprocess.h \ + util/virsexpr.c util/virsexpr.h \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ diff --git a/src/util/sexpr.c b/src/util/sexpr.c deleted file mode 100644 index ae0cc18..0000000 --- a/src/util/sexpr.c +++ /dev/null @@ -1,625 +0,0 @@ -/* - * sexpr.c : S-Expression routines to communicate with the Xen Daemon - * - * Copyright (C) 2010-2011 Red Hat, Inc. - * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License. See the file COPYING.LIB in the main directory of this - * archive for more details. - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "c-ctype.h" -#include <errno.h> - -#include "virterror_internal.h" -#include "sexpr.h" -#include "util.h" -#include "viralloc.h" - -#define VIR_FROM_THIS VIR_FROM_SEXPR - - -/** - * sexpr_new: - * - * Create a new S-Expression - * - * Returns the new node or NULL in case of memory allocation error - */ -static struct sexpr * -sexpr_new(void) -{ - struct sexpr *ret; - - if (VIR_ALLOC(ret) < 0) { - virReportOOMError(); - return NULL; - } - ret->kind = SEXPR_NIL; - return ret; -} - -/** - * sexpr_free: - * @sexpr: the S-Expression pointer - * - * Free an S-Expression - */ -void -sexpr_free(struct sexpr *sexpr) -{ - int serrno = errno; - - if (sexpr == NULL) { - return; - } - - switch (sexpr->kind) { - case SEXPR_CONS: - sexpr_free(sexpr->u.s.car); - sexpr_free(sexpr->u.s.cdr); - break; - case SEXPR_VALUE: - VIR_FREE(sexpr->u.value); - break; - case SEXPR_NIL: - break; - } - - VIR_FREE(sexpr); - - errno = serrno; -} - -/** - * sexpr_nil: - * - * Provide a NIL S-Expression (the pointer is not shared so NIL equality - * testing won't work at the pointer level). - * - * Returns a new NIL S-Expression of NULL in case of error. - */ -struct sexpr * -sexpr_nil(void) -{ - return sexpr_new(); -} - -/** - * sexpr_string: - * @str: the input string, assumed to be UTF-8 - * @len: the length in bytes of the input - * - * Parse the input S-Expression and return a pointer to the result - * - * Returns the S-Expression pointer or NULL in case of error - */ -struct sexpr * -sexpr_string(const char *str, ssize_t len) -{ - struct sexpr *ret = sexpr_new(); - - if (ret == NULL) - return ret; - ret->kind = SEXPR_VALUE; - if (len > 0) { - ret->u.value = strndup(str, len); - } else { - ret->u.value = strdup(str); - } - - if (ret->u.value == NULL) { - VIR_FREE(ret); - return NULL; - } - - return ret; -} - -/** - * sexpr_cons: - * @car: the left operand - * @cdr: the right operand - * - * Implement the CONS operation assembling 2 existing S-Expressions. - * Note that in case of error the input data are not freed. - * - * Returns the resulting S-Expression pointer or NULL in case of error. - */ -struct sexpr * -sexpr_cons(const struct sexpr *car, const struct sexpr *cdr) -{ - struct sexpr *ret = sexpr_new(); - - if (ret == NULL) - return ret; - ret->kind = SEXPR_CONS; - ret->u.s.car = (struct sexpr *) car; - ret->u.s.cdr = (struct sexpr *) cdr; - - return ret; -} - -/** - * append: - * @lst: an existing list - * @value: the value - * - * Internal operation appending a value at the end of an existing list - */ -static int -append(struct sexpr *lst, const struct sexpr *value) -{ - struct sexpr *nil = sexpr_nil(); - - if (nil == NULL) - return -1; - - while (lst->kind != SEXPR_NIL) { - lst = lst->u.s.cdr; - } - - lst->kind = SEXPR_CONS; - lst->u.s.car = (struct sexpr *) value; - lst->u.s.cdr = nil; - - return 0; -} - -/** - * @lst: an existing list - * @value: the value - * - * Append a value at the end of an existing list - * - * Returns lst or NULL in case of error - */ -struct sexpr * -sexpr_append(struct sexpr *lst, const struct sexpr *value) -{ - if (lst == NULL) - return NULL; - if (value == NULL) - return lst; - if (append(lst, value) < 0) - return NULL; - return lst; -} - -/** - * sexpr2string: - * @sexpr: an S-Expression pointer - * @buffer: the output buffer - * - * Serialize the S-Expression in the buffer. - * - * Returns 0 on success, -1 on error. - */ -int -sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer) -{ - if ((sexpr == NULL) || (buffer == NULL)) - return -1; - - switch (sexpr->kind) { - case SEXPR_CONS: - virBufferAddChar(buffer, '('); - - if (sexpr2string(sexpr->u.s.car, buffer) < 0) - return -1; - - while (sexpr->u.s.cdr->kind != SEXPR_NIL) { - sexpr = sexpr->u.s.cdr; - - virBufferAddChar(buffer, ' '); - - if (sexpr2string(sexpr->u.s.car, buffer) < 0) - return -1; - } - - virBufferAddChar(buffer, ')'); - break; - case SEXPR_VALUE: - if (strchr(sexpr->u.value, ' ') || - strchr(sexpr->u.value, ')') || - strchr(sexpr->u.value, '(')) - virBufferAsprintf(buffer, "'%s'", sexpr->u.value); - else - virBufferAdd(buffer, sexpr->u.value, -1); - - break; - case SEXPR_NIL: - virBufferAddLit(buffer, "()"); - break; - default: - virReportError(VIR_ERR_SEXPR_SERIAL, - _("unknown s-expression kind %d"), sexpr->kind); - return -1; - } - - return 0; -} - -#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA)) - -static const char * -trim(const char *string) -{ - while (IS_SPACE(*string)) - string++; - return string; -} - -/** - * _string2sexpr: - * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 - * @end: pointer to an index in the buffer for the already parsed bytes - * - * Internal routine implementing the parse of S-Expression - * Note that failure in this function is catastrophic. If it returns - * NULL, you've leaked memory and you're currently OOM. It will always - * parse an SEXPR given a buffer - * - * Returns a pointer to the resulting parsed S-Expression, or NULL in case of - * hard error. - */ -static struct sexpr * -_string2sexpr(const char *buffer, size_t * end) -{ - const char *ptr = buffer + *end; - struct sexpr *ret = sexpr_new(); - - if (ret == NULL) - return NULL; - - ptr = trim(ptr); - - if (ptr[0] == '(') { - ret->kind = SEXPR_NIL; - - ptr = trim(ptr + 1); - while (*ptr && *ptr != ')') { - struct sexpr *tmp; - size_t tmp_len = 0; - - tmp = _string2sexpr(ptr, &tmp_len); - if (tmp == NULL) - goto error; - if (append(ret, tmp) < 0) { - sexpr_free(tmp); - goto error; - } - ptr = trim(ptr + tmp_len); - } - - if (*ptr == ')') { - ptr++; - } - } else { - const char *start; - - if (*ptr == '\'') { - ptr++; - start = ptr; - - while (*ptr && *ptr != '\'') { - if (*ptr == '\\' && ptr[1]) - ptr++; - ptr++; - } - - ret->u.value = strndup(start, ptr - start); - if (ret->u.value == NULL) { - virReportOOMError(); - goto error; - } - - if (*ptr == '\'') - ptr++; - } else { - start = ptr; - - while (*ptr && !c_isspace(*ptr) - && *ptr != ')' && *ptr != '(') { - ptr++; - } - - ret->u.value = strndup(start, ptr - start); - if (ret->u.value == NULL) { - virReportOOMError(); - goto error; - } - } - - ret->kind = SEXPR_VALUE; - if (ret->u.value == NULL) - goto error; - } - - *end = ptr - buffer; - - return ret; - - error: - sexpr_free(ret); - return NULL; -} - -/** - * string2sexpr: - * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 - * - * Parse the S-Expression in the buffer. - * Note that failure in this function is catastrophic. If it returns - * NULL, you've leaked memory and you're currently OOM. It will always - * parse an SEXPR given a buffer - * - * Returns a pointer to the resulting parsed S-Expression, or NULL in case of - * hard error. - */ -struct sexpr * -string2sexpr(const char *buffer) -{ - size_t dummy = 0; - - return _string2sexpr(buffer, &dummy); -} - - -/** - * sexpr_lookup_key: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the sub expression to lookup in the S-Expression - * - * Search a sub expression in the S-Expression based on its path - * Returns the key node, rather than the data node. - * NOTE: path are limited to 4096 bytes. - * - * Returns the pointer to the sub expression or NULL if not found. - */ -static struct sexpr * -sexpr_lookup_key(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *result = NULL; - char *buffer, *ptr, *token; - - if ((node == NULL) || (sexpr == NULL)) - return NULL; - - buffer = strdup(node); - - if (buffer == NULL) { - virReportOOMError(); - return NULL; - } - - ptr = buffer; - token = strsep(&ptr, "/"); - - if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) { - goto cleanup; - } - - if (STRNEQ(sexpr->u.s.car->u.value, token)) { - goto cleanup; - } - - for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) { - const struct sexpr *i; - - sexpr = sexpr->u.s.cdr; - for (i = sexpr; i->kind != SEXPR_NIL; i = i->u.s.cdr) { - if (i->kind != SEXPR_CONS || - i->u.s.car->kind != SEXPR_CONS || - i->u.s.car->u.s.car->kind != SEXPR_VALUE) { - continue; - } - - if (STREQ(i->u.s.car->u.s.car->u.value, token)) { - sexpr = i->u.s.car; - break; - } - } - - if (i->kind == SEXPR_NIL) { - break; - } - } - - if (token != NULL) { - goto cleanup; - } - - result = (struct sexpr *) sexpr; - -cleanup: - VIR_FREE(buffer); - - return result; -} - -/** - * sexpr_lookup: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the sub expression to lookup in the S-Expression - * - * Search a sub expression in the S-Expression based on its path. - * NOTE: path are limited to 4096 bytes. - * - * Returns the pointer to the sub expression or NULL if not found. - */ -struct sexpr * -sexpr_lookup(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *s = sexpr_lookup_key(sexpr, node); - - if (s == NULL) - return NULL; - - if (s->kind != SEXPR_CONS || s->u.s.cdr->kind != SEXPR_CONS) - return NULL; - - return s->u.s.cdr; -} - -/** - * sexpr_has: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the sub expression to lookup in the S-Expression - * - * Search a sub expression in the S-Expression based on its path. - * NOTE: path are limited to 4096 bytes. - * NB, even if the key was found sexpr_lookup may return NULL if - * the corresponding value was empty - * - * Returns true if the key was found, false otherwise - */ -int -sexpr_has(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *s = sexpr_lookup_key(sexpr, node); - - if (s == NULL) - return 0; - - if (s->kind != SEXPR_CONS) - return 0; - - return 1; -} - -/** - * sexpr_node: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the node to lookup in the S-Expression - * - * Search a node value in the S-Expression based on its path - * NOTE: path are limited to 4096 bytes. - * - * Returns the value of the node or NULL if not found. - */ -const char * -sexpr_node(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *n = sexpr_lookup(sexpr, node); - - return (n && n->u.s.car->kind == SEXPR_VALUE) ? n->u.s.car->u.value : NULL; -} - -int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst) -{ - const char *val = sexpr_node(sexpr, node); - - if (val && *val) { - *dst = strdup(val); - if (!(*dst)) - return -1; - } else { - *dst = NULL; - } - return 0; -} - - -/** - * sexpr_fmt_node: - * @sexpr: a pointer to a parsed S-Expression - * @fmt: a path for the node to lookup in the S-Expression - * @... extra data to build the path - * - * Search a node value in the S-Expression based on its path - * - * Returns the value of the node or NULL if not found. - */ -const char * -sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) -{ - int result; - va_list ap; - char *node; - const char *value; - - va_start(ap, fmt); - result = virVasprintf(&node, fmt, ap); - va_end(ap); - - if (result < 0) { - return NULL; - } - - value = sexpr_node(sexpr, node); - - VIR_FREE(node); - - return value; -} - -/** - * sexpr_int: - * @sexpr: an S-Expression - * @name: the name for the value - * - * convenience function to lookup an int value in the S-Expression - * - * Returns the value found or 0 if not found (but may not be an error). - * This function suffers from the flaw that zero is both a correct - * return value and an error indicator: careful! - */ -int -sexpr_int(const struct sexpr *sexpr, const char *name) -{ - const char *value = sexpr_node(sexpr, name); - - if (value) { - return strtol(value, NULL, 0); - } - return 0; -} - - -/** - * sexpr_float: - * @sexpr: an S-Expression - * @name: the name for the value - * - * convenience function to lookup a float value in the S-Expression - * - * Returns the value found or 0 if not found (but may not be an error) - */ -double -sexpr_float(const struct sexpr *sexpr, const char *name) -{ - const char *value = sexpr_node(sexpr, name); - - if (value) { - return strtod(value, NULL); - } - return 0; -} - -/** - * sexpr_u64: - * @sexpr: an S-Expression - * @name: the name for the value - * - * convenience function to lookup a 64bits unsigned int value in the - * S-Expression - * - * Returns the value found or 0 if not found (but may not be an error) - */ -uint64_t -sexpr_u64(const struct sexpr *sexpr, const char *name) -{ - const char *value = sexpr_node(sexpr, name); - - if (value) { - return strtoll(value, NULL, 0); - } - return 0; -} diff --git a/src/util/sexpr.h b/src/util/sexpr.h deleted file mode 100644 index 13ec481..0000000 --- a/src/util/sexpr.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * sexpr.h : S-Expression interfaces needed to communicate with the Xen Daemon - * - * Copyright (C) 2012 Red Hat, Inc. - * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License. See the file COPYING.LIB in the main directory of this - * archive for more details. - */ - -#ifndef _LIBVIR_SEXPR_H_ -# define _LIBVIR_SEXPR_H_ - -# include "internal.h" -# include "virbuffer.h" - -enum sexpr_type { - SEXPR_NIL, - SEXPR_CONS, - SEXPR_VALUE, -}; - -struct sexpr { - enum sexpr_type kind; - union { - struct { - struct sexpr *car; - struct sexpr *cdr; - } s; - char *value; - } u; -}; - -/* conversion to/from strings */ -int sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer); -struct sexpr *string2sexpr(const char *buffer); - -/* constructors and destructors */ -struct sexpr *sexpr_nil(void); -struct sexpr *sexpr_string(const char *str, ssize_t len); -struct sexpr *sexpr_cons(const struct sexpr *car, const struct sexpr *cdr); -struct sexpr *sexpr_append(struct sexpr *lst, const struct sexpr *item); -void sexpr_free(struct sexpr *sexpr); - -/* lookup in S-Expressions */ -const char *sexpr_node(const struct sexpr *sexpr, const char *node); -int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst); -const char *sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) - ATTRIBUTE_FMT_PRINTF(2,3); -struct sexpr *sexpr_lookup(const struct sexpr *sexpr, const char *node); -int sexpr_has(const struct sexpr *sexpr, const char *node); - -int sexpr_int(const struct sexpr *sexpr, const char *name); -double sexpr_float(const struct sexpr *sexpr, const char *name); -uint64_t sexpr_u64(const struct sexpr *sexpr, const char *name); - -#endif diff --git a/src/util/virsexpr.c b/src/util/virsexpr.c new file mode 100644 index 0000000..80c24c4 --- /dev/null +++ b/src/util/virsexpr.c @@ -0,0 +1,625 @@ +/* + * sexpr.c : S-Expression routines to communicate with the Xen Daemon + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file COPYING.LIB in the main directory of this + * archive for more details. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "c-ctype.h" +#include <errno.h> + +#include "virterror_internal.h" +#include "virsexpr.h" +#include "util.h" +#include "viralloc.h" + +#define VIR_FROM_THIS VIR_FROM_SEXPR + + +/** + * sexpr_new: + * + * Create a new S-Expression + * + * Returns the new node or NULL in case of memory allocation error + */ +static struct sexpr * +sexpr_new(void) +{ + struct sexpr *ret; + + if (VIR_ALLOC(ret) < 0) { + virReportOOMError(); + return NULL; + } + ret->kind = SEXPR_NIL; + return ret; +} + +/** + * sexpr_free: + * @sexpr: the S-Expression pointer + * + * Free an S-Expression + */ +void +sexpr_free(struct sexpr *sexpr) +{ + int serrno = errno; + + if (sexpr == NULL) { + return; + } + + switch (sexpr->kind) { + case SEXPR_CONS: + sexpr_free(sexpr->u.s.car); + sexpr_free(sexpr->u.s.cdr); + break; + case SEXPR_VALUE: + VIR_FREE(sexpr->u.value); + break; + case SEXPR_NIL: + break; + } + + VIR_FREE(sexpr); + + errno = serrno; +} + +/** + * sexpr_nil: + * + * Provide a NIL S-Expression (the pointer is not shared so NIL equality + * testing won't work at the pointer level). + * + * Returns a new NIL S-Expression of NULL in case of error. + */ +struct sexpr * +sexpr_nil(void) +{ + return sexpr_new(); +} + +/** + * sexpr_string: + * @str: the input string, assumed to be UTF-8 + * @len: the length in bytes of the input + * + * Parse the input S-Expression and return a pointer to the result + * + * Returns the S-Expression pointer or NULL in case of error + */ +struct sexpr * +sexpr_string(const char *str, ssize_t len) +{ + struct sexpr *ret = sexpr_new(); + + if (ret == NULL) + return ret; + ret->kind = SEXPR_VALUE; + if (len > 0) { + ret->u.value = strndup(str, len); + } else { + ret->u.value = strdup(str); + } + + if (ret->u.value == NULL) { + VIR_FREE(ret); + return NULL; + } + + return ret; +} + +/** + * sexpr_cons: + * @car: the left operand + * @cdr: the right operand + * + * Implement the CONS operation assembling 2 existing S-Expressions. + * Note that in case of error the input data are not freed. + * + * Returns the resulting S-Expression pointer or NULL in case of error. + */ +struct sexpr * +sexpr_cons(const struct sexpr *car, const struct sexpr *cdr) +{ + struct sexpr *ret = sexpr_new(); + + if (ret == NULL) + return ret; + ret->kind = SEXPR_CONS; + ret->u.s.car = (struct sexpr *) car; + ret->u.s.cdr = (struct sexpr *) cdr; + + return ret; +} + +/** + * append: + * @lst: an existing list + * @value: the value + * + * Internal operation appending a value at the end of an existing list + */ +static int +append(struct sexpr *lst, const struct sexpr *value) +{ + struct sexpr *nil = sexpr_nil(); + + if (nil == NULL) + return -1; + + while (lst->kind != SEXPR_NIL) { + lst = lst->u.s.cdr; + } + + lst->kind = SEXPR_CONS; + lst->u.s.car = (struct sexpr *) value; + lst->u.s.cdr = nil; + + return 0; +} + +/** + * @lst: an existing list + * @value: the value + * + * Append a value at the end of an existing list + * + * Returns lst or NULL in case of error + */ +struct sexpr * +sexpr_append(struct sexpr *lst, const struct sexpr *value) +{ + if (lst == NULL) + return NULL; + if (value == NULL) + return lst; + if (append(lst, value) < 0) + return NULL; + return lst; +} + +/** + * sexpr2string: + * @sexpr: an S-Expression pointer + * @buffer: the output buffer + * + * Serialize the S-Expression in the buffer. + * + * Returns 0 on success, -1 on error. + */ +int +sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer) +{ + if ((sexpr == NULL) || (buffer == NULL)) + return -1; + + switch (sexpr->kind) { + case SEXPR_CONS: + virBufferAddChar(buffer, '('); + + if (sexpr2string(sexpr->u.s.car, buffer) < 0) + return -1; + + while (sexpr->u.s.cdr->kind != SEXPR_NIL) { + sexpr = sexpr->u.s.cdr; + + virBufferAddChar(buffer, ' '); + + if (sexpr2string(sexpr->u.s.car, buffer) < 0) + return -1; + } + + virBufferAddChar(buffer, ')'); + break; + case SEXPR_VALUE: + if (strchr(sexpr->u.value, ' ') || + strchr(sexpr->u.value, ')') || + strchr(sexpr->u.value, '(')) + virBufferAsprintf(buffer, "'%s'", sexpr->u.value); + else + virBufferAdd(buffer, sexpr->u.value, -1); + + break; + case SEXPR_NIL: + virBufferAddLit(buffer, "()"); + break; + default: + virReportError(VIR_ERR_SEXPR_SERIAL, + _("unknown s-expression kind %d"), sexpr->kind); + return -1; + } + + return 0; +} + +#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA)) + +static const char * +trim(const char *string) +{ + while (IS_SPACE(*string)) + string++; + return string; +} + +/** + * _string2sexpr: + * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 + * @end: pointer to an index in the buffer for the already parsed bytes + * + * Internal routine implementing the parse of S-Expression + * Note that failure in this function is catastrophic. If it returns + * NULL, you've leaked memory and you're currently OOM. It will always + * parse an SEXPR given a buffer + * + * Returns a pointer to the resulting parsed S-Expression, or NULL in case of + * hard error. + */ +static struct sexpr * +_string2sexpr(const char *buffer, size_t * end) +{ + const char *ptr = buffer + *end; + struct sexpr *ret = sexpr_new(); + + if (ret == NULL) + return NULL; + + ptr = trim(ptr); + + if (ptr[0] == '(') { + ret->kind = SEXPR_NIL; + + ptr = trim(ptr + 1); + while (*ptr && *ptr != ')') { + struct sexpr *tmp; + size_t tmp_len = 0; + + tmp = _string2sexpr(ptr, &tmp_len); + if (tmp == NULL) + goto error; + if (append(ret, tmp) < 0) { + sexpr_free(tmp); + goto error; + } + ptr = trim(ptr + tmp_len); + } + + if (*ptr == ')') { + ptr++; + } + } else { + const char *start; + + if (*ptr == '\'') { + ptr++; + start = ptr; + + while (*ptr && *ptr != '\'') { + if (*ptr == '\\' && ptr[1]) + ptr++; + ptr++; + } + + ret->u.value = strndup(start, ptr - start); + if (ret->u.value == NULL) { + virReportOOMError(); + goto error; + } + + if (*ptr == '\'') + ptr++; + } else { + start = ptr; + + while (*ptr && !c_isspace(*ptr) + && *ptr != ')' && *ptr != '(') { + ptr++; + } + + ret->u.value = strndup(start, ptr - start); + if (ret->u.value == NULL) { + virReportOOMError(); + goto error; + } + } + + ret->kind = SEXPR_VALUE; + if (ret->u.value == NULL) + goto error; + } + + *end = ptr - buffer; + + return ret; + + error: + sexpr_free(ret); + return NULL; +} + +/** + * string2sexpr: + * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 + * + * Parse the S-Expression in the buffer. + * Note that failure in this function is catastrophic. If it returns + * NULL, you've leaked memory and you're currently OOM. It will always + * parse an SEXPR given a buffer + * + * Returns a pointer to the resulting parsed S-Expression, or NULL in case of + * hard error. + */ +struct sexpr * +string2sexpr(const char *buffer) +{ + size_t dummy = 0; + + return _string2sexpr(buffer, &dummy); +} + + +/** + * sexpr_lookup_key: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the sub expression to lookup in the S-Expression + * + * Search a sub expression in the S-Expression based on its path + * Returns the key node, rather than the data node. + * NOTE: path are limited to 4096 bytes. + * + * Returns the pointer to the sub expression or NULL if not found. + */ +static struct sexpr * +sexpr_lookup_key(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *result = NULL; + char *buffer, *ptr, *token; + + if ((node == NULL) || (sexpr == NULL)) + return NULL; + + buffer = strdup(node); + + if (buffer == NULL) { + virReportOOMError(); + return NULL; + } + + ptr = buffer; + token = strsep(&ptr, "/"); + + if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) { + goto cleanup; + } + + if (STRNEQ(sexpr->u.s.car->u.value, token)) { + goto cleanup; + } + + for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) { + const struct sexpr *i; + + sexpr = sexpr->u.s.cdr; + for (i = sexpr; i->kind != SEXPR_NIL; i = i->u.s.cdr) { + if (i->kind != SEXPR_CONS || + i->u.s.car->kind != SEXPR_CONS || + i->u.s.car->u.s.car->kind != SEXPR_VALUE) { + continue; + } + + if (STREQ(i->u.s.car->u.s.car->u.value, token)) { + sexpr = i->u.s.car; + break; + } + } + + if (i->kind == SEXPR_NIL) { + break; + } + } + + if (token != NULL) { + goto cleanup; + } + + result = (struct sexpr *) sexpr; + +cleanup: + VIR_FREE(buffer); + + return result; +} + +/** + * sexpr_lookup: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the sub expression to lookup in the S-Expression + * + * Search a sub expression in the S-Expression based on its path. + * NOTE: path are limited to 4096 bytes. + * + * Returns the pointer to the sub expression or NULL if not found. + */ +struct sexpr * +sexpr_lookup(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *s = sexpr_lookup_key(sexpr, node); + + if (s == NULL) + return NULL; + + if (s->kind != SEXPR_CONS || s->u.s.cdr->kind != SEXPR_CONS) + return NULL; + + return s->u.s.cdr; +} + +/** + * sexpr_has: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the sub expression to lookup in the S-Expression + * + * Search a sub expression in the S-Expression based on its path. + * NOTE: path are limited to 4096 bytes. + * NB, even if the key was found sexpr_lookup may return NULL if + * the corresponding value was empty + * + * Returns true if the key was found, false otherwise + */ +int +sexpr_has(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *s = sexpr_lookup_key(sexpr, node); + + if (s == NULL) + return 0; + + if (s->kind != SEXPR_CONS) + return 0; + + return 1; +} + +/** + * sexpr_node: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the node to lookup in the S-Expression + * + * Search a node value in the S-Expression based on its path + * NOTE: path are limited to 4096 bytes. + * + * Returns the value of the node or NULL if not found. + */ +const char * +sexpr_node(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *n = sexpr_lookup(sexpr, node); + + return (n && n->u.s.car->kind == SEXPR_VALUE) ? n->u.s.car->u.value : NULL; +} + +int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst) +{ + const char *val = sexpr_node(sexpr, node); + + if (val && *val) { + *dst = strdup(val); + if (!(*dst)) + return -1; + } else { + *dst = NULL; + } + return 0; +} + + +/** + * sexpr_fmt_node: + * @sexpr: a pointer to a parsed S-Expression + * @fmt: a path for the node to lookup in the S-Expression + * @... extra data to build the path + * + * Search a node value in the S-Expression based on its path + * + * Returns the value of the node or NULL if not found. + */ +const char * +sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) +{ + int result; + va_list ap; + char *node; + const char *value; + + va_start(ap, fmt); + result = virVasprintf(&node, fmt, ap); + va_end(ap); + + if (result < 0) { + return NULL; + } + + value = sexpr_node(sexpr, node); + + VIR_FREE(node); + + return value; +} + +/** + * sexpr_int: + * @sexpr: an S-Expression + * @name: the name for the value + * + * convenience function to lookup an int value in the S-Expression + * + * Returns the value found or 0 if not found (but may not be an error). + * This function suffers from the flaw that zero is both a correct + * return value and an error indicator: careful! + */ +int +sexpr_int(const struct sexpr *sexpr, const char *name) +{ + const char *value = sexpr_node(sexpr, name); + + if (value) { + return strtol(value, NULL, 0); + } + return 0; +} + + +/** + * sexpr_float: + * @sexpr: an S-Expression + * @name: the name for the value + * + * convenience function to lookup a float value in the S-Expression + * + * Returns the value found or 0 if not found (but may not be an error) + */ +double +sexpr_float(const struct sexpr *sexpr, const char *name) +{ + const char *value = sexpr_node(sexpr, name); + + if (value) { + return strtod(value, NULL); + } + return 0; +} + +/** + * sexpr_u64: + * @sexpr: an S-Expression + * @name: the name for the value + * + * convenience function to lookup a 64bits unsigned int value in the + * S-Expression + * + * Returns the value found or 0 if not found (but may not be an error) + */ +uint64_t +sexpr_u64(const struct sexpr *sexpr, const char *name) +{ + const char *value = sexpr_node(sexpr, name); + + if (value) { + return strtoll(value, NULL, 0); + } + return 0; +} diff --git a/src/util/virsexpr.h b/src/util/virsexpr.h new file mode 100644 index 0000000..13ec481 --- /dev/null +++ b/src/util/virsexpr.h @@ -0,0 +1,58 @@ +/* + * sexpr.h : S-Expression interfaces needed to communicate with the Xen Daemon + * + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file COPYING.LIB in the main directory of this + * archive for more details. + */ + +#ifndef _LIBVIR_SEXPR_H_ +# define _LIBVIR_SEXPR_H_ + +# include "internal.h" +# include "virbuffer.h" + +enum sexpr_type { + SEXPR_NIL, + SEXPR_CONS, + SEXPR_VALUE, +}; + +struct sexpr { + enum sexpr_type kind; + union { + struct { + struct sexpr *car; + struct sexpr *cdr; + } s; + char *value; + } u; +}; + +/* conversion to/from strings */ +int sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer); +struct sexpr *string2sexpr(const char *buffer); + +/* constructors and destructors */ +struct sexpr *sexpr_nil(void); +struct sexpr *sexpr_string(const char *str, ssize_t len); +struct sexpr *sexpr_cons(const struct sexpr *car, const struct sexpr *cdr); +struct sexpr *sexpr_append(struct sexpr *lst, const struct sexpr *item); +void sexpr_free(struct sexpr *sexpr); + +/* lookup in S-Expressions */ +const char *sexpr_node(const struct sexpr *sexpr, const char *node); +int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst); +const char *sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) + ATTRIBUTE_FMT_PRINTF(2,3); +struct sexpr *sexpr_lookup(const struct sexpr *sexpr, const char *node); +int sexpr_has(const struct sexpr *sexpr, const char *node); + +int sexpr_int(const struct sexpr *sexpr, const char *name); +double sexpr_float(const struct sexpr *sexpr, const char *name); +uint64_t sexpr_u64(const struct sexpr *sexpr, const char *name); + +#endif diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index a4005f4..6e8bc2f 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -35,7 +35,7 @@ #include "xend_internal.h" #include "driver.h" #include "util.h" -#include "sexpr.h" +#include "virsexpr.h" #include "xen_sxpr.h" #include "virbuffer.h" #include "uuid.h" diff --git a/src/xenxs/xen_sxpr.h b/src/xenxs/xen_sxpr.h index 4ff640c..d7ce46a 100644 --- a/src/xenxs/xen_sxpr.h +++ b/src/xenxs/xen_sxpr.h @@ -30,7 +30,7 @@ # include "internal.h" # include "virconf.h" # include "domain_conf.h" -# include "sexpr.h" +# include "virsexpr.h" typedef enum { XEND_CONFIG_VERSION_3_0_2 = 1, diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index 7d67bbe..c29df1c 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "verify.h" #include "uuid.h" -#include "sexpr.h" +#include "virsexpr.h" #include "count-one-bits.h" #include "xenxs_private.h" #include "xen_xm.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/lxc/lxc_driver.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/stats_linux.c | 122 --------------------------------------------- src/util/stats_linux.h | 35 ------------- src/util/virstatslinux.c | 122 +++++++++++++++++++++++++++++++++++++++++++++ src/util/virstatslinux.h | 35 +++++++++++++ src/xen/xen_hypervisor.c | 2 +- tests/statstest.c | 2 +- 12 files changed, 165 insertions(+), 165 deletions(-) delete mode 100644 src/util/stats_linux.c delete mode 100644 src/util/stats_linux.h create mode 100644 src/util/virstatslinux.c create mode 100644 src/util/virstatslinux.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 2b09531..ecb4498 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/stats_linux.c src/util/storage_file.c src/util/sysinfo.c src/util/util.c @@ -174,6 +173,7 @@ src/util/virprocess.c src/util/virrandom.c src/util/virsexpr.c src/util/virsocketaddr.c +src/util/virstatslinux.c src/util/virterror.c src/util/virterror_internal.h src/util/virtime.c diff --git a/src/Makefile.am b/src/Makefile.am index c0dfd38..feb4b77 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ util/sysinfo.c util/sysinfo.h \ util/threads.c util/threads.h \ @@ -86,6 +85,7 @@ UTIL_SOURCES = \ util/virpidfile.c util/virpidfile.h \ util/virprocess.c util/virprocess.h \ util/virsexpr.c util/virsexpr.h \ + util/virstatslinux.c util/virstatslinux.h \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 35e8ac9..57c1767 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -49,7 +49,7 @@ #include "virnetdevveth.h" #include "nodeinfo.h" #include "uuid.h" -#include "stats_linux.h" +#include "virstatslinux.h" #include "virhooks.h" #include "virfile.h" #include "virpidfile.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index f6327fd..a35a6b1 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -59,7 +59,7 @@ #include "virlog.h" #include "vircommand.h" #include "viruri.h" -#include "stats_linux.h" +#include "virstatslinux.h" #define VIR_FROM_THIS VIR_FROM_OPENVZ diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 488c814..c5bd054 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -65,7 +65,7 @@ #include "virbuffer.h" #include "util.h" #include "nodeinfo.h" -#include "stats_linux.h" +#include "virstatslinux.h" #include "capabilities.h" #include "viralloc.h" #include "uuid.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index cece114..b20998f 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -49,7 +49,7 @@ #include "virbuffer.h" #include "util.h" #include "nodeinfo.h" -#include "stats_linux.h" +#include "virstatslinux.h" #include "capabilities.h" #include "viralloc.h" #include "uuid.h" diff --git a/src/util/stats_linux.c b/src/util/stats_linux.c deleted file mode 100644 index 67ef82e..0000000 --- a/src/util/stats_linux.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Linux block and network stats. - * - * Copyright (C) 2007-2010 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 "viralloc.h" -# include "virfile.h" - -# define VIR_FROM_THIS VIR_FROM_STATS_LINUX - - -/*-------------------- 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(const char *path, - struct _virDomainInterfaceStats *stats) -{ - int path_len; - FILE *fp; - char line[256], *colon; - - fp = fopen("/proc/net/dev", "r"); - if (!fp) { - virReportSystemError(errno, "%s", - _("Could not open /proc/net/dev")); - 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; - VIR_FORCE_FCLOSE(fp); - - return 0; - } - } - VIR_FORCE_FCLOSE(fp); - - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("/proc/net/dev: Interface not found")); - return -1; -} - -#endif /* __linux__ */ diff --git a/src/util/stats_linux.h b/src/util/stats_linux.h deleted file mode 100644 index 5847177..0000000 --- a/src/util/stats_linux.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Linux block and network stats. - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Richard W.M. Jones <rjones@redhat.com> - */ - -#ifndef __STATS_LINUX_H__ -# define __STATS_LINUX_H__ - -# ifdef __linux__ - -# include "internal.h" - -extern int linuxDomainInterfaceStats(const char *path, - struct _virDomainInterfaceStats *stats); - -# endif /* __linux__ */ - -#endif /* __STATS_LINUX_H__ */ diff --git a/src/util/virstatslinux.c b/src/util/virstatslinux.c new file mode 100644 index 0000000..9359db9 --- /dev/null +++ b/src/util/virstatslinux.c @@ -0,0 +1,122 @@ +/* + * Linux block and network stats. + * + * Copyright (C) 2007-2010 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, see + * <http://www.gnu.org/licenses/>. + * + * 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 "virstatslinux.h" +# include "viralloc.h" +# include "virfile.h" + +# define VIR_FROM_THIS VIR_FROM_STATS_LINUX + + +/*-------------------- 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(const char *path, + struct _virDomainInterfaceStats *stats) +{ + int path_len; + FILE *fp; + char line[256], *colon; + + fp = fopen("/proc/net/dev", "r"); + if (!fp) { + virReportSystemError(errno, "%s", + _("Could not open /proc/net/dev")); + 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; + VIR_FORCE_FCLOSE(fp); + + return 0; + } + } + VIR_FORCE_FCLOSE(fp); + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("/proc/net/dev: Interface not found")); + return -1; +} + +#endif /* __linux__ */ diff --git a/src/util/virstatslinux.h b/src/util/virstatslinux.h new file mode 100644 index 0000000..5847177 --- /dev/null +++ b/src/util/virstatslinux.h @@ -0,0 +1,35 @@ +/* + * Linux block and network stats. + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Richard W.M. Jones <rjones@redhat.com> + */ + +#ifndef __STATS_LINUX_H__ +# define __STATS_LINUX_H__ + +# ifdef __linux__ + +# include "internal.h" + +extern int linuxDomainInterfaceStats(const char *path, + struct _virDomainInterfaceStats *stats); + +# endif /* __linux__ */ + +#endif /* __STATS_LINUX_H__ */ diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 598ec5e..b308605 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -71,7 +71,7 @@ #include "xen_driver.h" #include "xen_hypervisor.h" #include "xs_internal.h" -#include "stats_linux.h" +#include "virstatslinux.h" #include "block_stats.h" #include "xend_internal.h" #include "virbuffer.h" diff --git a/tests/statstest.c b/tests/statstest.c index ad71bf9..30f9ab0 100644 --- a/tests/statstest.c +++ b/tests/statstest.c @@ -5,7 +5,7 @@ #include <string.h> #include <sys/utsname.h> -#include "stats_linux.h" +#include "virstatslinux.h" #include "internal.h" #include "xen/block_stats.h" #include "testutils.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/libxl/libxl_conf.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_storage.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_domain.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_selinux.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_fs.c | 2 +- src/util/storage_file.c | 1397 ----------------------------------- src/util/storage_file.h | 109 --- src/util/util.c | 2 +- src/util/virstoragefile.c | 1397 +++++++++++++++++++++++++++++++++++ src/util/virstoragefile.h | 109 +++ src/vbox/vbox_tmpl.c | 2 +- src/xenxs/xen_sxpr.c | 2 +- src/xenxs/xen_xm.c | 2 +- 28 files changed, 1530 insertions(+), 1530 deletions(-) delete mode 100644 src/util/storage_file.c delete mode 100644 src/util/storage_file.h create mode 100644 src/util/virstoragefile.c create mode 100644 src/util/virstoragefile.h diff --git a/po/POTFILES.in b/po/POTFILES.in index ecb4498..417f128 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/storage_file.c src/util/sysinfo.c src/util/util.c src/util/viraudit.c @@ -174,6 +173,7 @@ src/util/virrandom.c src/util/virsexpr.c src/util/virsocketaddr.c src/util/virstatslinux.c +src/util/virstoragefile.c src/util/virterror.c src/util/virterror_internal.h src/util/virtime.c diff --git a/src/Makefile.am b/src/Makefile.am index feb4b77..911c041 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/storage_file.c util/storage_file.h \ util/sysinfo.c util/sysinfo.h \ util/threads.c util/threads.h \ util/threads-pthread.h \ @@ -86,6 +85,7 @@ UTIL_SOURCES = \ util/virprocess.c util/virprocess.h \ util/virsexpr.c util/virsexpr.h \ util/virstatslinux.c util/virstatslinux.h \ + util/virstoragefile.c util/virstoragefile.h \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f80f5f1..b3c3557 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -42,7 +42,7 @@ #include "virbuffer.h" #include "virlog.h" #include "nwfilter_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "virfile.h" #include "virbitmap.h" #include "count-one-bits.h" diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 26d2264..6bac92f 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -47,7 +47,7 @@ # include "virobject.h" # include "device_conf.h" # include "virbitmap.h" -# include "storage_file.h" +# include "virstoragefile.h" /* forward declarations of all device types, required by * virDomainDeviceDef diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 9c16a88..5c40e97 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -41,7 +41,7 @@ #include "nwfilter_conf.h" #include "secret_conf.h" #include "snapshot_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "util.h" #include "uuid.h" #include "virfile.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 0e00588..5cd2393 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -36,7 +36,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "storage_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "xml.h" #include "uuid.h" diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 9d481d2..5ad885a 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -33,7 +33,7 @@ #include "virlog.h" #include "uuid.h" #include "storage_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "esx_storage_backend_iscsi.h" #include "esx_private.h" #include "esx_vi.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index bca637b..4886fc3 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -36,7 +36,7 @@ #include "virlog.h" #include "uuid.h" #include "storage_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "esx_storage_backend_vmfs.h" #include "esx_private.h" #include "esx_vi.h" diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index ac55cf3..eb6738c 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -43,7 +43,7 @@ #include "libxl_driver.h" #include "libxl_conf.h" #include "libxl_utils.h" -#include "storage_file.h" +#include "virstoragefile.h" #define VIR_FROM_THIS VIR_FROM_LIBXL diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 2d3dc4a..07c1463 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -48,7 +48,7 @@ #include "virlog.h" #include "vircommand.h" #include "configmake.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "nodeinfo.h" #include "c-ctype.h" diff --git a/src/parallels/parallels_storage.c b/src/parallels/parallels_storage.c index f546d28..0e6c100 100644 --- a/src/parallels/parallels_storage.c +++ b/src/parallels/parallels_storage.c @@ -33,7 +33,7 @@ #include "datatypes.h" #include "viralloc.h" #include "configmake.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "virterror_internal.h" #include "parallels_utils.h" diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 8a57cb5..464288f 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -43,7 +43,7 @@ #include "virnetdevtap.h" #include "base64.h" #include "device_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include <sys/utsname.h> #include <sys/stat.h> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 8dcadbc..3e1081a 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -36,7 +36,7 @@ #include "virfile.h" #include "domain_event.h" #include "virtime.h" -#include "storage_file.h" +#include "virstoragefile.h" #include <sys/time.h> #include <fcntl.h> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index c5bd054..fd36dfc 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -81,7 +81,7 @@ #include "sysinfo.h" #include "domain_nwfilter.h" #include "virhooks.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "virfile.h" #include "fdstream.h" #include "configmake.h" diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e120988..e5b28da 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -45,7 +45,7 @@ #include "virnetdevbridge.h" #include "virnetdevtap.h" #include "device_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 3e9ff03..a77beb6 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -47,7 +47,7 @@ #include "virtime.h" #include "locking/domain_lock.h" #include "rpc/virnetsocket.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "viruri.h" #include "virhooks.h" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index e4f016a..f9752ef 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -30,7 +30,7 @@ #include "virlog.h" #include "virpci.h" #include "virusb.h" -#include "storage_file.h" +#include "virstoragefile.h" #define VIR_FROM_THIS VIR_FROM_SECURITY #define SECURITY_DAC_NAME "dac" diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 2adf5c9..8918257 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -39,7 +39,7 @@ #include "virlog.h" #include "virpci.h" #include "virusb.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "virfile.h" #include "virhash.h" #include "virrandom.h" diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index cdc5bda..9b98dbb 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -52,7 +52,7 @@ #include "internal.h" #include "secret_conf.h" #include "uuid.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "storage_backend.h" #include "virlog.h" #include "virfile.h" diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index f7b4656..b744fb4 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -44,7 +44,7 @@ #include "virterror_internal.h" #include "storage_backend_fs.h" #include "storage_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "vircommand.h" #include "viralloc.h" #include "xml.h" diff --git a/src/util/storage_file.c b/src/util/storage_file.c deleted file mode 100644 index a020bb2..0000000 --- a/src/util/storage_file.c +++ /dev/null @@ -1,1397 +0,0 @@ -/* - * storage_file.c: file utility functions for FS storage backend - * - * Copyright (C) 2007-2012 Red Hat, Inc. - * Copyright (C) 2007-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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel P. Berrange <berrange@redhat.com> - */ - -#include <config.h> -#include "storage_file.h" - -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdlib.h> -#ifdef __linux__ -# if HAVE_LINUX_MAGIC_H -# include <linux/magic.h> -# endif -# include <sys/statfs.h> -#endif -#include "dirname.h" -#include "viralloc.h" -#include "virterror_internal.h" -#include "virlog.h" -#include "virfile.h" -#include "c-ctype.h" -#include "vircommand.h" -#include "virhash.h" - -#define VIR_FROM_THIS VIR_FROM_STORAGE - -VIR_ENUM_IMPL(virStorageFileFormat, - VIR_STORAGE_FILE_LAST, - "none", - "raw", "dir", "bochs", - "cloop", "cow", "dmg", "iso", - "qcow", "qcow2", "qed", "vmdk", "vpc", - "fat", "vhd") - -enum lv_endian { - LV_LITTLE_ENDIAN = 1, /* 1234 */ - LV_BIG_ENDIAN /* 4321 */ -}; - -enum { - BACKING_STORE_OK, - BACKING_STORE_INVALID, - BACKING_STORE_ERROR, -}; - -/* Either 'magic' or 'extension' *must* be provided */ -struct FileTypeInfo { - const char *magic; /* Optional string of file magic - * to check at head of file */ - const char *extension; /* Optional file extension to check */ - enum lv_endian endian; /* Endianness of file format */ - int versionOffset; /* Byte offset from start of file - * where we find version number, - * -1 to skip version test */ - int versionNumber; /* Version number to validate */ - int sizeOffset; /* Byte offset from start of file - * where we find capacity info, - * -1 to use st_size as capacity */ - int sizeBytes; /* Number of bytes for size field */ - int sizeMultiplier; /* A scaling factor if size is not in bytes */ - /* Store a COW base image path (possibly relative), - * or NULL if there is no COW base image, to RES; - * return BACKING_STORE_* */ - int qcowCryptOffset; /* Byte offset from start of file - * where to find encryption mode, - * -1 if encryption is not used */ - int (*getBackingStore)(char **res, int *format, - const unsigned char *buf, size_t buf_size); -}; - -static int cowGetBackingStore(char **, int *, - const unsigned char *, size_t); -static int qcow1GetBackingStore(char **, int *, - const unsigned char *, size_t); -static int qcow2GetBackingStore(char **, int *, - const unsigned char *, size_t); -static int vmdk4GetBackingStore(char **, int *, - const unsigned char *, size_t); -static int -qedGetBackingStore(char **, int *, const unsigned char *, size_t); - -#define QCOWX_HDR_VERSION (4) -#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) -#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) -#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) - -#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1) -#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) - -#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8) -#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8) - -#define QCOW2_HDR_EXTENSION_END 0 -#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA - -#define QED_HDR_FEATURES_OFFSET (4+4+4+4) -#define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8+8) -#define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8) -#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4) -#define QED_F_BACKING_FILE 0x01 -#define QED_F_BACKING_FORMAT_NO_PROBE 0x04 - -/* VMDK needs at least this to find backing store, - * other formats need less */ -#define STORAGE_MAX_HEAD (20*512) - - -static struct FileTypeInfo const fileTypeInfo[] = { - [VIR_STORAGE_FILE_NONE] = { NULL, NULL, LV_LITTLE_ENDIAN, - -1, 0, 0, 0, 0, 0, NULL }, - [VIR_STORAGE_FILE_RAW] = { NULL, NULL, LV_LITTLE_ENDIAN, - -1, 0, 0, 0, 0, 0, NULL }, - [VIR_STORAGE_FILE_DIR] = { NULL, NULL, LV_LITTLE_ENDIAN, - -1, 0, 0, 0, 0, 0, NULL }, - [VIR_STORAGE_FILE_BOCHS] = { - /*"Bochs Virtual HD Image", */ /* Untested */ NULL, - NULL, - LV_LITTLE_ENDIAN, 64, 0x20000, - 32+16+16+4+4+4+4+4, 8, 1, -1, NULL - }, - [VIR_STORAGE_FILE_CLOOP] = { - /*"#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", */ /* Untested */ NULL, - NULL, - LV_LITTLE_ENDIAN, -1, 0, - -1, 0, 0, -1, NULL - }, - [VIR_STORAGE_FILE_COW] = { - "OOOM", NULL, - LV_BIG_ENDIAN, 4, 2, - 4+4+1024+4, 8, 1, -1, cowGetBackingStore - }, - [VIR_STORAGE_FILE_DMG] = { - NULL, /* XXX QEMU says there's no magic for dmg, but we should check... */ - ".dmg", - 0, -1, 0, - -1, 0, 0, -1, NULL - }, - [VIR_STORAGE_FILE_ISO] = { - NULL, /* XXX there's probably some magic for iso we can validate too... */ - ".iso", - 0, -1, 0, - -1, 0, 0, -1, NULL - }, - [VIR_STORAGE_FILE_QCOW] = { - "QFI", NULL, - LV_BIG_ENDIAN, 4, 1, - QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore, - }, - [VIR_STORAGE_FILE_QCOW2] = { - "QFI", NULL, - LV_BIG_ENDIAN, 4, 2, - QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore, - }, - [VIR_STORAGE_FILE_QED] = { - /* http://wiki.qemu.org/Features/QED */ - "QED", NULL, - LV_LITTLE_ENDIAN, -2, -1, - QED_HDR_IMAGE_SIZE, 8, 1, -1, qedGetBackingStore, - }, - [VIR_STORAGE_FILE_VMDK] = { - "KDMV", NULL, - LV_LITTLE_ENDIAN, 4, 1, - 4+4+4, 8, 512, -1, vmdk4GetBackingStore - }, - [VIR_STORAGE_FILE_VPC] = { - "conectix", NULL, - LV_BIG_ENDIAN, 12, 0x10000, - 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, NULL - }, - /* Not direct file formats, but used for various drivers */ - [VIR_STORAGE_FILE_FAT] = { NULL, NULL, LV_LITTLE_ENDIAN, - -1, 0, 0, 0, 0, 0, NULL }, - [VIR_STORAGE_FILE_VHD] = { NULL, NULL, LV_LITTLE_ENDIAN, - -1, 0, 0, 0, 0, 0, NULL }, -}; -verify(ARRAY_CARDINALITY(fileTypeInfo) == VIR_STORAGE_FILE_LAST); - -static int -cowGetBackingStore(char **res, - int *format, - const unsigned char *buf, - size_t buf_size) -{ -#define COW_FILENAME_MAXLEN 1024 - *res = NULL; - *format = VIR_STORAGE_FILE_AUTO; - - if (buf_size < 4+4+ COW_FILENAME_MAXLEN) - return BACKING_STORE_INVALID; - if (buf[4+4] == '\0') { /* cow_header_v2.backing_file[0] */ - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - - *res = strndup((const char*)buf + 4+4, COW_FILENAME_MAXLEN); - if (*res == NULL) { - virReportOOMError(); - return BACKING_STORE_ERROR; - } - return BACKING_STORE_OK; -} - - -static int -qcow2GetBackingStoreFormat(int *format, - const unsigned char *buf, - size_t buf_size, - size_t extension_start, - size_t extension_end) -{ - size_t offset = extension_start; - - /* - * The extensions take format of - * - * int32: magic - * int32: length - * byte[length]: payload - * - * Unknown extensions can be ignored by skipping - * over "length" bytes in the data stream. - */ - while (offset < (buf_size-8) && - offset < (extension_end-8)) { - unsigned int magic = - (buf[offset] << 24) + - (buf[offset+1] << 16) + - (buf[offset+2] << 8) + - (buf[offset+3]); - unsigned int len = - (buf[offset+4] << 24) + - (buf[offset+5] << 16) + - (buf[offset+6] << 8) + - (buf[offset+7]); - - offset += 8; - - if ((offset + len) < offset) - break; - - if ((offset + len) > buf_size) - break; - - switch (magic) { - case QCOW2_HDR_EXTENSION_END: - goto done; - - case QCOW2_HDR_EXTENSION_BACKING_FORMAT: - if (buf[offset+len] != '\0') - break; - *format = virStorageFileFormatTypeFromString( - ((const char *)buf)+offset); - if (*format <= VIR_STORAGE_FILE_NONE) - return -1; - } - - offset += len; - } - -done: - - return 0; -} - - -static int -qcowXGetBackingStore(char **res, - int *format, - const unsigned char *buf, - size_t buf_size, - bool isQCow2) -{ - unsigned long long offset; - unsigned int size; - - *res = NULL; - if (format) - *format = VIR_STORAGE_FILE_AUTO; - - if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4) - return BACKING_STORE_INVALID; - offset = (((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET] << 56) - | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+1] << 48) - | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+2] << 40) - | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+3] << 32) - | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+4] << 24) - | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+5] << 16) - | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+6] << 8) - | buf[QCOWX_HDR_BACKING_FILE_OFFSET+7]); /* QCowHeader.backing_file_offset */ - if (offset > buf_size) - return BACKING_STORE_INVALID; - size = ((buf[QCOWX_HDR_BACKING_FILE_SIZE] << 24) - | (buf[QCOWX_HDR_BACKING_FILE_SIZE+1] << 16) - | (buf[QCOWX_HDR_BACKING_FILE_SIZE+2] << 8) - | buf[QCOWX_HDR_BACKING_FILE_SIZE+3]); /* QCowHeader.backing_file_size */ - if (size == 0) { - if (format) - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - if (offset + size > buf_size || offset + size < offset) - return BACKING_STORE_INVALID; - if (size + 1 == 0) - return BACKING_STORE_INVALID; - if (VIR_ALLOC_N(*res, size + 1) < 0) { - virReportOOMError(); - return BACKING_STORE_ERROR; - } - memcpy(*res, buf + offset, size); - (*res)[size] = '\0'; - - /* - * Traditionally QCow2 files had a layout of - * - * [header] - * [backingStoreName] - * - * Although the backingStoreName typically followed - * the header immediately, this was not required by - * the format. By specifying a higher byte offset for - * the backing file offset in the header, it was - * possible to leave space between the header and - * start of backingStore. - * - * This hack is now used to store extensions to the - * qcow2 format: - * - * [header] - * [extensions] - * [backingStoreName] - * - * Thus the file region to search for extensions is - * between the end of the header (QCOW2_HDR_TOTAL_SIZE) - * and the start of the backingStoreName (offset) - */ - if (isQCow2 && format && - qcow2GetBackingStoreFormat(format, buf, buf_size, QCOW2_HDR_TOTAL_SIZE, - offset) < 0) - return BACKING_STORE_INVALID; - - return BACKING_STORE_OK; -} - - -static int -qcow1GetBackingStore(char **res, - int *format, - const unsigned char *buf, - size_t buf_size) -{ - int ret; - - /* QCow1 doesn't have the extensions capability - * used to store backing format */ - *format = VIR_STORAGE_FILE_AUTO; - ret = qcowXGetBackingStore(res, NULL, buf, buf_size, false); - if (ret == 0 && *buf == '\0') - *format = VIR_STORAGE_FILE_NONE; - return ret; -} - -static int -qcow2GetBackingStore(char **res, - int *format, - const unsigned char *buf, - size_t buf_size) -{ - return qcowXGetBackingStore(res, format, buf, buf_size, true); -} - - -static int -vmdk4GetBackingStore(char **res, - int *format, - const unsigned char *buf, - size_t buf_size) -{ - static const char prefix[] = "parentFileNameHint=\""; - char *desc, *start, *end; - size_t len; - int ret = BACKING_STORE_ERROR; - - if (VIR_ALLOC_N(desc, STORAGE_MAX_HEAD + 1) < 0) { - virReportOOMError(); - goto cleanup; - } - - *res = NULL; - /* - * Technically this should have been VMDK, since - * VMDK spec / VMWare impl only support VMDK backed - * by VMDK. QEMU isn't following this though and - * does probing on VMDK backing files, hence we set - * AUTO - */ - *format = VIR_STORAGE_FILE_AUTO; - - if (buf_size <= 0x200) { - ret = BACKING_STORE_INVALID; - goto cleanup; - } - len = buf_size - 0x200; - if (len > STORAGE_MAX_HEAD) - len = STORAGE_MAX_HEAD; - memcpy(desc, buf + 0x200, len); - desc[len] = '\0'; - start = strstr(desc, prefix); - if (start == NULL) { - *format = VIR_STORAGE_FILE_NONE; - ret = BACKING_STORE_OK; - goto cleanup; - } - start += strlen(prefix); - end = strchr(start, '"'); - if (end == NULL) { - ret = BACKING_STORE_INVALID; - goto cleanup; - } - if (end == start) { - *format = VIR_STORAGE_FILE_NONE; - ret = BACKING_STORE_OK; - goto cleanup; - } - *end = '\0'; - *res = strdup(start); - if (*res == NULL) { - virReportOOMError(); - goto cleanup; - } - - ret = BACKING_STORE_OK; - -cleanup: - VIR_FREE(desc); - return ret; -} - -static unsigned long -qedGetHeaderUL(const unsigned char *loc) -{ - return (((unsigned long)loc[3] << 24) | - ((unsigned long)loc[2] << 16) | - ((unsigned long)loc[1] << 8) | - ((unsigned long)loc[0] << 0)); -} - -static unsigned long long -qedGetHeaderULL(const unsigned char *loc) -{ - return (((unsigned long long)loc[7] << 56) | - ((unsigned long long)loc[6] << 48) | - ((unsigned long long)loc[5] << 40) | - ((unsigned long long)loc[4] << 32) | - ((unsigned long long)loc[3] << 24) | - ((unsigned long long)loc[2] << 16) | - ((unsigned long long)loc[1] << 8) | - ((unsigned long long)loc[0] << 0)); -} - -static int -qedGetBackingStore(char **res, - int *format, - const unsigned char *buf, - size_t buf_size) -{ - unsigned long long flags; - unsigned long offset, size; - - *res = NULL; - /* Check if this image has a backing file */ - if (buf_size < QED_HDR_FEATURES_OFFSET+8) - return BACKING_STORE_INVALID; - flags = qedGetHeaderULL(buf + QED_HDR_FEATURES_OFFSET); - if (!(flags & QED_F_BACKING_FILE)) { - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - - /* Parse the backing file */ - if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8) - return BACKING_STORE_INVALID; - offset = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_OFFSET); - if (offset > buf_size) - return BACKING_STORE_INVALID; - size = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_SIZE); - if (size == 0) - return BACKING_STORE_OK; - if (offset + size > buf_size || offset + size < offset) - return BACKING_STORE_INVALID; - if (VIR_ALLOC_N(*res, size + 1) < 0) { - virReportOOMError(); - return BACKING_STORE_ERROR; - } - memcpy(*res, buf + offset, size); - (*res)[size] = '\0'; - - if (flags & QED_F_BACKING_FORMAT_NO_PROBE) - *format = VIR_STORAGE_FILE_RAW; - else - *format = VIR_STORAGE_FILE_AUTO_SAFE; - - return BACKING_STORE_OK; -} - -/** - * Return an absolute path corresponding to PATH, which is absolute or relative - * to the directory containing BASE_FILE, or NULL on error - */ -static char * -absolutePathFromBaseFile(const char *base_file, const char *path) -{ - char *res = NULL; - char *tmp = NULL; - size_t d_len = dir_len(base_file); - - /* If path is already absolute, or if dirname(base_file) is ".", - just return a copy of path. */ - if (*path == '/' || d_len == 0) { - if (!(res = canonicalize_file_name(path))) - virReportSystemError(errno, - _("Can't canonicalize path '%s'"), path); - - goto cleanup; - } - - /* Ensure that the following cast-to-int is valid. */ - if (d_len > INT_MAX) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Directory name too long: '%s'"), base_file); - goto cleanup; - } - - if (virAsprintf(&tmp, "%.*s/%s", (int) d_len, base_file, path) < 0) { - virReportOOMError(); - goto cleanup; - } - - if (!(res = canonicalize_file_name(tmp))) - virReportSystemError(errno, _("Can't canonicalize path '%s'"), path); - -cleanup: - VIR_FREE(tmp); - return res; -} - - -static bool -virStorageFileMatchesMagic(int format, - unsigned char *buf, - size_t buflen) -{ - int mlen; - - if (fileTypeInfo[format].magic == NULL) - return false; - - /* Validate magic data */ - mlen = strlen(fileTypeInfo[format].magic); - if (mlen > buflen) - return false; - - if (memcmp(buf, fileTypeInfo[format].magic, mlen) != 0) - return false; - - return true; -} - - -static bool -virStorageFileMatchesExtension(int format, - const char *path) -{ - if (fileTypeInfo[format].extension == NULL) - return false; - - if (virFileHasSuffix(path, fileTypeInfo[format].extension)) - return true; - - return false; -} - - -static bool -virStorageFileMatchesVersion(int format, - unsigned char *buf, - size_t buflen) -{ - int version; - - /* Validate version number info */ - if (fileTypeInfo[format].versionOffset == -1) - return false; - - /* -2 == non-versioned file format, so trivially match */ - if (fileTypeInfo[format].versionOffset == -2) - return true; - - if ((fileTypeInfo[format].versionOffset + 4) > buflen) - return false; - - if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) { - version = - (buf[fileTypeInfo[format].versionOffset+3] << 24) | - (buf[fileTypeInfo[format].versionOffset+2] << 16) | - (buf[fileTypeInfo[format].versionOffset+1] << 8) | - (buf[fileTypeInfo[format].versionOffset]); - } else { - version = - (buf[fileTypeInfo[format].versionOffset] << 24) | - (buf[fileTypeInfo[format].versionOffset+1] << 16) | - (buf[fileTypeInfo[format].versionOffset+2] << 8) | - (buf[fileTypeInfo[format].versionOffset+3]); - } - - VIR_DEBUG("Compare detected version %d vs expected version %d", - version, fileTypeInfo[format].versionNumber); - if (version != fileTypeInfo[format].versionNumber) - return false; - - return true; -} - -static bool -virBackingStoreIsFile(const char *backing) -{ - /* Backing store is a network block device or Rados block device */ - if (STRPREFIX(backing, "nbd:") || STRPREFIX(backing, "rbd:")) - return false; - return true; -} - -static int -virStorageFileGetMetadataFromBuf(int format, - const char *path, - unsigned char *buf, - size_t buflen, - virStorageFileMetadata *meta) -{ - VIR_DEBUG("path=%s format=%d", path, format); - - /* XXX we should consider moving virStorageBackendUpdateVolInfo - * code into this method, for non-magic files - */ - if (format <= VIR_STORAGE_FILE_NONE || - format >= VIR_STORAGE_FILE_LAST || - !fileTypeInfo[format].magic) { - return 0; - } - - /* Optionally extract capacity from file */ - if (fileTypeInfo[format].sizeOffset != -1) { - if ((fileTypeInfo[format].sizeOffset + 8) > buflen) - return 1; - - if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) { - meta->capacity = - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7] << 56) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 48) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 40) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 32) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 24) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 16) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 8) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset]); - } else { - meta->capacity = - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset] << 56) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 48) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 40) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 32) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 24) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 16) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 8) | - ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7]); - } - /* Avoid unlikely, but theoretically possible overflow */ - if (meta->capacity > (ULLONG_MAX / fileTypeInfo[format].sizeMultiplier)) - return 1; - meta->capacity *= fileTypeInfo[format].sizeMultiplier; - } - - if (fileTypeInfo[format].qcowCryptOffset != -1) { - int crypt_format; - - crypt_format = - (buf[fileTypeInfo[format].qcowCryptOffset] << 24) | - (buf[fileTypeInfo[format].qcowCryptOffset+1] << 16) | - (buf[fileTypeInfo[format].qcowCryptOffset+2] << 8) | - (buf[fileTypeInfo[format].qcowCryptOffset+3]); - meta->encrypted = crypt_format != 0; - } - - if (fileTypeInfo[format].getBackingStore != NULL) { - char *backing; - int backingFormat; - int ret = fileTypeInfo[format].getBackingStore(&backing, - &backingFormat, - buf, buflen); - if (ret == BACKING_STORE_INVALID) - return 1; - - if (ret == BACKING_STORE_ERROR) - return -1; - - meta->backingStoreIsFile = false; - if (backing != NULL) { - meta->backingStore = strdup(backing); - if (meta->backingStore == NULL) { - virReportOOMError(); - VIR_FREE(backing); - return -1; - } - if (virBackingStoreIsFile(backing)) { - meta->backingStoreIsFile = true; - meta->backingStoreRaw = meta->backingStore; - meta->backingStore = absolutePathFromBaseFile(path, backing); - if (meta->backingStore == NULL) { - /* the backing file is (currently) unavailable, treat this - * file as standalone: - * backingStoreRaw is kept to mark broken image chains */ - meta->backingStoreIsFile = false; - backingFormat = VIR_STORAGE_FILE_NONE; - VIR_WARN("Backing file '%s' of image '%s' is missing.", - meta->backingStoreRaw, path); - - } - } - VIR_FREE(backing); - meta->backingStoreFormat = backingFormat; - } else { - meta->backingStore = NULL; - meta->backingStoreFormat = VIR_STORAGE_FILE_NONE; - } - } - - return 0; -} - - -static int -virStorageFileProbeFormatFromBuf(const char *path, - unsigned char *buf, - size_t buflen) -{ - int format = VIR_STORAGE_FILE_RAW; - int i; - int possibleFormat = VIR_STORAGE_FILE_RAW; - VIR_DEBUG("path=%s", path); - - /* First check file magic */ - for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) { - if (virStorageFileMatchesMagic(i, buf, buflen)) { - if (!virStorageFileMatchesVersion(i, buf, buflen)) { - possibleFormat = i; - continue; - } - format = i; - goto cleanup; - } - } - - if (possibleFormat != VIR_STORAGE_FILE_RAW) - VIR_WARN("File %s matches %s magic, but version is wrong. " - "Please report new version to libvir-list@redhat.com", - path, virStorageFileFormatTypeToString(possibleFormat)); - - /* No magic, so check file extension */ - for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) { - if (virStorageFileMatchesExtension(i, path)) { - format = i; - goto cleanup; - } - } - -cleanup: - VIR_DEBUG("format=%d", format); - return format; -} - - -/** - * virStorageFileProbeFormatFromFD: - * - * Probe for the format of 'fd' (which is an open file descriptor - * pointing to 'path'), returning the detected disk format. - * - * Callers are advised never to trust the returned 'format' - * unless it is listed as VIR_STORAGE_FILE_RAW, since a - * malicious guest can turn a file into any other non-raw - * format at will. - * - * Best option: Don't use this function - */ -int -virStorageFileProbeFormatFromFD(const char *path, int fd) -{ - unsigned char *head; - ssize_t len = STORAGE_MAX_HEAD; - int ret = -1; - struct stat sb; - - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, - _("cannot stat file '%s'"), - path); - return -1; - } - - /* No header to probe for directories */ - if (S_ISDIR(sb.st_mode)) { - return VIR_STORAGE_FILE_DIR; - } - - if (VIR_ALLOC_N(head, len) < 0) { - virReportOOMError(); - return -1; - } - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - virReportSystemError(errno, _("cannot set to start of '%s'"), path); - goto cleanup; - } - - if ((len = read(fd, head, len)) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), path); - goto cleanup; - } - - ret = virStorageFileProbeFormatFromBuf(path, head, len); - -cleanup: - VIR_FREE(head); - return ret; -} - - -/** - * virStorageFileProbeFormat: - * - * Probe for the format of 'path', returning the detected - * disk format. - * - * Callers are advised never to trust the returned 'format' - * unless it is listed as VIR_STORAGE_FILE_RAW, since a - * malicious guest can turn a raw file into any other non-raw - * format at will. - * - * Best option: Don't use this function - */ -int -virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid) -{ - int fd, ret; - - if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) { - virReportSystemError(errno, _("cannot open file '%s'"), path); - return -1; - } - - ret = virStorageFileProbeFormatFromFD(path, fd); - - VIR_FORCE_CLOSE(fd); - - return ret; -} - -/** - * virStorageFileGetMetadataFromFD: - * - * Extract metadata about the storage volume with the specified - * image format. If image format is VIR_STORAGE_FILE_AUTO, it - * will probe to automatically identify the format. Does not recurse. - * - * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a - * format, since a malicious guest can turn a raw file into any - * other non-raw format at will. - * - * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO - * it indicates the image didn't specify an explicit format for its - * backing store. Callers are advised against probing for the - * backing store format in this case. - * - * Caller MUST free the result after use via virStorageFileFreeMetadata. - */ -virStorageFileMetadataPtr -virStorageFileGetMetadataFromFD(const char *path, - int fd, - int format) -{ - virStorageFileMetadata *meta = NULL; - unsigned char *head = NULL; - ssize_t len = STORAGE_MAX_HEAD; - virStorageFileMetadata *ret = NULL; - struct stat sb; - - if (VIR_ALLOC(meta) < 0) { - virReportOOMError(); - return NULL; - } - - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, - _("cannot stat file '%s'"), - path); - goto cleanup; - } - - /* No header to probe for directories, but also no backing file */ - if (S_ISDIR(sb.st_mode)) - return meta; - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - virReportSystemError(errno, _("cannot seek to start of '%s'"), path); - goto cleanup; - } - - if (VIR_ALLOC_N(head, len) < 0) { - virReportOOMError(); - goto cleanup; - } - - if ((len = read(fd, head, len)) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), path); - goto cleanup; - } - - if (format == VIR_STORAGE_FILE_AUTO) - format = virStorageFileProbeFormatFromBuf(path, head, len); - - if (format <= VIR_STORAGE_FILE_NONE || - format >= VIR_STORAGE_FILE_LAST) { - virReportSystemError(EINVAL, _("unknown storage file format %d"), - format); - goto cleanup; - } - - if (virStorageFileGetMetadataFromBuf(format, path, head, len, meta) < 0) - goto cleanup; - ret = meta; - meta = NULL; - -cleanup: - virStorageFileFreeMetadata(meta); - VIR_FREE(head); - return ret; -} - -/* Recursive workhorse for virStorageFileGetMetadata. */ -static virStorageFileMetadataPtr -virStorageFileGetMetadataRecurse(const char *path, int format, - uid_t uid, gid_t gid, - bool allow_probe, virHashTablePtr cycle) -{ - int fd; - VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d", - path, format, (int)uid, (int)gid, allow_probe); - - virStorageFileMetadataPtr ret = NULL; - - if (virHashLookup(cycle, path)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("backing store for %s is self-referential"), - path); - return NULL; - } - if (virHashAddEntry(cycle, path, (void *)1) < 0) - return NULL; - - if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) { - virReportSystemError(-fd, _("cannot open file '%s'"), path); - return NULL; - } - - ret = virStorageFileGetMetadataFromFD(path, fd, format); - - if (VIR_CLOSE(fd) < 0) - VIR_WARN("could not close file %s", path); - - if (ret && ret->backingStoreIsFile) { - if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO && !allow_probe) - ret->backingStoreFormat = VIR_STORAGE_FILE_RAW; - else if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO_SAFE) - ret->backingStoreFormat = VIR_STORAGE_FILE_AUTO; - format = ret->backingStoreFormat; - ret->backingMeta = virStorageFileGetMetadataRecurse(ret->backingStore, - format, - uid, gid, - allow_probe, - cycle); - } - - return ret; -} - -/** - * virStorageFileGetMetadata: - * - * Extract metadata about the storage volume with the specified - * image format. If image format is VIR_STORAGE_FILE_AUTO, it - * will probe to automatically identify the format. Recurses through - * the entire chain. - * - * Open files using UID and GID (or pass -1 for the current user/group). - * Treat any backing files without explicit type as raw, unless ALLOW_PROBE. - * - * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a - * format, since a malicious guest can turn a raw file into any - * other non-raw format at will. - * - * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO - * it indicates the image didn't specify an explicit format for its - * backing store. Callers are advised against using ALLOW_PROBE, as - * it would probe the backing store format in this case. - * - * Caller MUST free result after use via virStorageFileFreeMetadata. - */ -virStorageFileMetadataPtr -virStorageFileGetMetadata(const char *path, int format, - uid_t uid, gid_t gid, - bool allow_probe) -{ - VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d", - path, format, (int)uid, (int)gid, allow_probe); - - virHashTablePtr cycle = virHashCreate(5, NULL); - virStorageFileMetadataPtr ret; - - if (!cycle) - return NULL; - - if (format <= VIR_STORAGE_FILE_NONE) - format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW; - ret = virStorageFileGetMetadataRecurse(path, format, uid, gid, - allow_probe, cycle); - virHashFree(cycle); - return ret; -} - -/** - * virStorageFileFreeMetadata: - * - * Free pointers in passed structure and structure itself. - */ -void -virStorageFileFreeMetadata(virStorageFileMetadata *meta) -{ - if (!meta) - return; - - virStorageFileFreeMetadata(meta->backingMeta); - VIR_FREE(meta->backingStore); - VIR_FREE(meta->backingStoreRaw); - VIR_FREE(meta); -} - -/** - * virStorageFileResize: - * - * Change the capacity of the raw storage file at 'path'. - */ -int -virStorageFileResize(const char *path, unsigned long long capacity) -{ - int fd = -1; - int ret = -1; - - if ((fd = open(path, O_RDWR)) < 0) { - virReportSystemError(errno, _("Unable to open '%s'"), path); - goto cleanup; - } - - if (ftruncate(fd, capacity) < 0) { - virReportSystemError(errno, _("Failed to truncate file '%s'"), path); - goto cleanup; - } - - if (VIR_CLOSE(fd) < 0) { - virReportSystemError(errno, _("Unable to save '%s'"), path); - goto cleanup; - } - - ret = 0; - -cleanup: - VIR_FORCE_CLOSE(fd); - return ret; -} - -#ifdef __linux__ - -# ifndef NFS_SUPER_MAGIC -# define NFS_SUPER_MAGIC 0x6969 -# endif -# ifndef OCFS2_SUPER_MAGIC -# define OCFS2_SUPER_MAGIC 0x7461636f -# endif -# ifndef GFS2_MAGIC -# define GFS2_MAGIC 0x01161970 -# endif -# ifndef AFS_FS_MAGIC -# define AFS_FS_MAGIC 0x6B414653 -# endif - - -int virStorageFileIsSharedFSType(const char *path, - int fstypes) -{ - char *dirpath, *p; - struct statfs sb; - int statfs_ret; - - if ((dirpath = strdup(path)) == NULL) { - virReportOOMError(); - return -1; - } - - do { - - /* Try less and less of the path until we get to a - * directory we can stat. Even if we don't have 'x' - * permission on any directory in the path on the NFS - * server (assuming it's NFS), we will be able to stat the - * mount point, and that will properly tell us if the - * fstype is NFS. - */ - - if ((p = strrchr(dirpath, '/')) == NULL) { - virReportSystemError(EINVAL, - _("Invalid relative path '%s'"), path); - VIR_FREE(dirpath); - return -1; - } - - if (p == dirpath) - *(p+1) = '\0'; - else - *p = '\0'; - - statfs_ret = statfs(dirpath, &sb); - - } while ((statfs_ret < 0) && (p != dirpath)); - - VIR_FREE(dirpath); - - if (statfs_ret < 0) { - virReportSystemError(errno, - _("cannot determine filesystem for '%s'"), - path); - return -1; - } - - VIR_DEBUG("Check if path %s with FS magic %lld is shared", - path, (long long int)sb.f_type); - - if ((fstypes & VIR_STORAGE_FILE_SHFS_NFS) && - (sb.f_type == NFS_SUPER_MAGIC)) - return 1; - - if ((fstypes & VIR_STORAGE_FILE_SHFS_GFS2) && - (sb.f_type == GFS2_MAGIC)) - return 1; - if ((fstypes & VIR_STORAGE_FILE_SHFS_OCFS) && - (sb.f_type == OCFS2_SUPER_MAGIC)) - return 1; - if ((fstypes & VIR_STORAGE_FILE_SHFS_AFS) && - (sb.f_type == AFS_FS_MAGIC)) - return 1; - - return 0; -} -#else -int virStorageFileIsSharedFSType(const char *path ATTRIBUTE_UNUSED, - int fstypes ATTRIBUTE_UNUSED) -{ - /* XXX implement me :-) */ - return 0; -} -#endif - -int virStorageFileIsSharedFS(const char *path) -{ - return virStorageFileIsSharedFSType(path, - VIR_STORAGE_FILE_SHFS_NFS | - VIR_STORAGE_FILE_SHFS_GFS2 | - VIR_STORAGE_FILE_SHFS_OCFS | - VIR_STORAGE_FILE_SHFS_AFS); -} - -int virStorageFileIsClusterFS(const char *path) -{ - /* These are coherent cluster filesystems known to be safe for - * migration with cache != none - */ - return virStorageFileIsSharedFSType(path, - VIR_STORAGE_FILE_SHFS_GFS2 | - VIR_STORAGE_FILE_SHFS_OCFS); -} - -#ifdef LVS -int virStorageFileGetLVMKey(const char *path, - char **key) -{ - /* - * # lvs --noheadings --unbuffered --nosuffix --options "uuid" LVNAME - * 06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky - */ - int status; - virCommandPtr cmd = virCommandNewArgList( - LVS, - "--noheadings", "--unbuffered", "--nosuffix", - "--options", "uuid", path, - NULL - ); - int ret = -1; - - *key = NULL; - - /* Run the program and capture its output */ - virCommandSetOutputBuffer(cmd, key); - if (virCommandRun(cmd, &status) < 0) - goto cleanup; - - /* Explicitly check status == 0, rather than passing NULL - * to virCommandRun because we don't want to raise an actual - * error in this scenario, just return a NULL key. - */ - - if (status == 0 && *key) { - char *nl; - char *tmp = *key; - - /* Find first non-space character */ - while (*tmp && c_isspace(*tmp)) { - tmp++; - } - /* Kill leading spaces */ - if (tmp != *key) - memmove(*key, tmp, strlen(tmp)+1); - - /* Kill trailing newline */ - if ((nl = strchr(*key, '\n'))) - *nl = '\0'; - } - - ret = 0; - -cleanup: - if (*key && STREQ(*key, "")) - VIR_FREE(*key); - - virCommandFree(cmd); - - return ret; -} -#else -int virStorageFileGetLVMKey(const char *path, - char **key ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, _("Unable to get LVM key for %s"), path); - return -1; -} -#endif - -#ifdef HAVE_UDEV -int virStorageFileGetSCSIKey(const char *path, - char **key) -{ - int status; - virCommandPtr cmd = virCommandNewArgList( - "/lib/udev/scsi_id", - "--replace-whitespace", - "--whitelisted", - "--device", path, - NULL - ); - int ret = -1; - - *key = NULL; - - /* Run the program and capture its output */ - virCommandSetOutputBuffer(cmd, key); - if (virCommandRun(cmd, &status) < 0) - goto cleanup; - - /* Explicitly check status == 0, rather than passing NULL - * to virCommandRun because we don't want to raise an actual - * error in this scenario, just return a NULL key. - */ - if (status == 0 && *key) { - char *nl = strchr(*key, '\n'); - if (nl) - *nl = '\0'; - } - - ret = 0; - -cleanup: - if (*key && STREQ(*key, "")) - VIR_FREE(*key); - - virCommandFree(cmd); - - return ret; -} -#else -int virStorageFileGetSCSIKey(const char *path, - char **key ATTRIBUTE_UNUSED) -{ - virReportSystemError(ENOSYS, _("Unable to get SCSI key for %s"), path); - return -1; -} -#endif - -/* Given a CHAIN that starts at the named file START, return a string - * pointing to either START or within CHAIN that gives the preferred - * name for the backing file NAME within that chain. Pass NULL for - * NAME to find the base of the chain. If META is not NULL, set *META - * to the point in the chain that describes NAME (or to NULL if the - * backing element is not a file). If PARENT is not NULL, set *PARENT - * to the preferred name of the parent (or to NULL if NAME matches - * START). Since the results point within CHAIN, they must not be - * independently freed. */ -const char * -virStorageFileChainLookup(virStorageFileMetadataPtr chain, const char *start, - const char *name, virStorageFileMetadataPtr *meta, - const char **parent) -{ - virStorageFileMetadataPtr owner; - const char *tmp; - - if (!parent) - parent = &tmp; - - *parent = NULL; - if (name ? STREQ(start, name) || virFileLinkPointsTo(start, name) : - !chain->backingStore) { - if (meta) - *meta = chain; - return start; - } - - owner = chain; - *parent = start; - while (owner) { - if (!owner->backingStore) - goto error; - if (!name) { - if (!owner->backingMeta || - !owner->backingMeta->backingStore) - break; - } else if (STREQ_NULLABLE(name, owner->backingStoreRaw) || - STREQ(name, owner->backingStore)) { - break; - } else if (owner->backingStoreIsFile) { - char *absName = absolutePathFromBaseFile(*parent, name); - if (absName && STREQ(absName, owner->backingStore)) { - VIR_FREE(absName); - break; - } - VIR_FREE(absName); - } - *parent = owner->backingStore; - owner = owner->backingMeta; - } - if (!owner) - goto error; - if (meta) - *meta = owner->backingMeta; - return owner->backingStore; - -error: - *parent = NULL; - if (meta) - *meta = NULL; - return NULL; -} diff --git a/src/util/storage_file.h b/src/util/storage_file.h deleted file mode 100644 index 6fbd275..0000000 --- a/src/util/storage_file.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * storage_file.c: file utility functions for FS storage backend - * - * Copyright (C) 2007-2009, 2012 Red Hat, Inc. - * Copyright (C) 2007-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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel P. Berrange <berrange@redhat.com> - */ - -#ifndef __VIR_STORAGE_FILE_H__ -# define __VIR_STORAGE_FILE_H__ - -# include "util.h" - -enum virStorageFileFormat { - VIR_STORAGE_FILE_AUTO_SAFE = -2, - VIR_STORAGE_FILE_AUTO = -1, - VIR_STORAGE_FILE_NONE = 0, - VIR_STORAGE_FILE_RAW, - VIR_STORAGE_FILE_DIR, - VIR_STORAGE_FILE_BOCHS, - VIR_STORAGE_FILE_CLOOP, - VIR_STORAGE_FILE_COW, - VIR_STORAGE_FILE_DMG, - VIR_STORAGE_FILE_ISO, - VIR_STORAGE_FILE_QCOW, - VIR_STORAGE_FILE_QCOW2, - VIR_STORAGE_FILE_QED, - VIR_STORAGE_FILE_VMDK, - VIR_STORAGE_FILE_VPC, - VIR_STORAGE_FILE_FAT, - VIR_STORAGE_FILE_VHD, - - VIR_STORAGE_FILE_LAST, -}; - -VIR_ENUM_DECL(virStorageFileFormat); - -typedef struct _virStorageFileMetadata virStorageFileMetadata; -typedef virStorageFileMetadata *virStorageFileMetadataPtr; -struct _virStorageFileMetadata { - char *backingStore; /* Canonical name (absolute file, or protocol) */ - char *backingStoreRaw; /* If file, original name, possibly relative */ - int backingStoreFormat; /* enum virStorageFileFormat */ - bool backingStoreIsFile; - virStorageFileMetadataPtr backingMeta; - unsigned long long capacity; - bool encrypted; -}; - -# ifndef DEV_BSIZE -# define DEV_BSIZE 512 -# endif - -int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid); -int virStorageFileProbeFormatFromFD(const char *path, - int fd); - -virStorageFileMetadataPtr virStorageFileGetMetadata(const char *path, - int format, - uid_t uid, gid_t gid, - bool allow_probe); -virStorageFileMetadataPtr virStorageFileGetMetadataFromFD(const char *path, - int fd, - int format); - -const char *virStorageFileChainLookup(virStorageFileMetadataPtr chain, - const char *start, - const char *name, - virStorageFileMetadataPtr *meta, - const char **parent) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); - -int virStorageFileResize(const char *path, unsigned long long capacity); - -enum { - VIR_STORAGE_FILE_SHFS_NFS = (1 << 0), - VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1), - VIR_STORAGE_FILE_SHFS_OCFS = (1 << 2), - VIR_STORAGE_FILE_SHFS_AFS = (1 << 3), -}; - -int virStorageFileIsSharedFS(const char *path); -int virStorageFileIsClusterFS(const char *path); -int virStorageFileIsSharedFSType(const char *path, - int fstypes); - -int virStorageFileGetLVMKey(const char *path, - char **key); -int virStorageFileGetSCSIKey(const char *path, - char **key); - -#endif /* __VIR_STORAGE_FILE_H__ */ diff --git a/src/util/util.c b/src/util/util.c index c070d94..5d32995 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -79,7 +79,7 @@ #include "virlog.h" #include "virbuffer.h" #include "util.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "viralloc.h" #include "threads.h" #include "verify.h" diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c new file mode 100644 index 0000000..f183f19 --- /dev/null +++ b/src/util/virstoragefile.c @@ -0,0 +1,1397 @@ +/* + * storage_file.c: file utility functions for FS storage backend + * + * Copyright (C) 2007-2012 Red Hat, Inc. + * Copyright (C) 2007-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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> +#include "virstoragefile.h" + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#ifdef __linux__ +# if HAVE_LINUX_MAGIC_H +# include <linux/magic.h> +# endif +# include <sys/statfs.h> +#endif +#include "dirname.h" +#include "viralloc.h" +#include "virterror_internal.h" +#include "virlog.h" +#include "virfile.h" +#include "c-ctype.h" +#include "vircommand.h" +#include "virhash.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_ENUM_IMPL(virStorageFileFormat, + VIR_STORAGE_FILE_LAST, + "none", + "raw", "dir", "bochs", + "cloop", "cow", "dmg", "iso", + "qcow", "qcow2", "qed", "vmdk", "vpc", + "fat", "vhd") + +enum lv_endian { + LV_LITTLE_ENDIAN = 1, /* 1234 */ + LV_BIG_ENDIAN /* 4321 */ +}; + +enum { + BACKING_STORE_OK, + BACKING_STORE_INVALID, + BACKING_STORE_ERROR, +}; + +/* Either 'magic' or 'extension' *must* be provided */ +struct FileTypeInfo { + const char *magic; /* Optional string of file magic + * to check at head of file */ + const char *extension; /* Optional file extension to check */ + enum lv_endian endian; /* Endianness of file format */ + int versionOffset; /* Byte offset from start of file + * where we find version number, + * -1 to skip version test */ + int versionNumber; /* Version number to validate */ + int sizeOffset; /* Byte offset from start of file + * where we find capacity info, + * -1 to use st_size as capacity */ + int sizeBytes; /* Number of bytes for size field */ + int sizeMultiplier; /* A scaling factor if size is not in bytes */ + /* Store a COW base image path (possibly relative), + * or NULL if there is no COW base image, to RES; + * return BACKING_STORE_* */ + int qcowCryptOffset; /* Byte offset from start of file + * where to find encryption mode, + * -1 if encryption is not used */ + int (*getBackingStore)(char **res, int *format, + const unsigned char *buf, size_t buf_size); +}; + +static int cowGetBackingStore(char **, int *, + const unsigned char *, size_t); +static int qcow1GetBackingStore(char **, int *, + const unsigned char *, size_t); +static int qcow2GetBackingStore(char **, int *, + const unsigned char *, size_t); +static int vmdk4GetBackingStore(char **, int *, + const unsigned char *, size_t); +static int +qedGetBackingStore(char **, int *, const unsigned char *, size_t); + +#define QCOWX_HDR_VERSION (4) +#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) +#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) +#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) + +#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1) +#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) + +#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8) +#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8) + +#define QCOW2_HDR_EXTENSION_END 0 +#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA + +#define QED_HDR_FEATURES_OFFSET (4+4+4+4) +#define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8+8) +#define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8) +#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4) +#define QED_F_BACKING_FILE 0x01 +#define QED_F_BACKING_FORMAT_NO_PROBE 0x04 + +/* VMDK needs at least this to find backing store, + * other formats need less */ +#define STORAGE_MAX_HEAD (20*512) + + +static struct FileTypeInfo const fileTypeInfo[] = { + [VIR_STORAGE_FILE_NONE] = { NULL, NULL, LV_LITTLE_ENDIAN, + -1, 0, 0, 0, 0, 0, NULL }, + [VIR_STORAGE_FILE_RAW] = { NULL, NULL, LV_LITTLE_ENDIAN, + -1, 0, 0, 0, 0, 0, NULL }, + [VIR_STORAGE_FILE_DIR] = { NULL, NULL, LV_LITTLE_ENDIAN, + -1, 0, 0, 0, 0, 0, NULL }, + [VIR_STORAGE_FILE_BOCHS] = { + /*"Bochs Virtual HD Image", */ /* Untested */ NULL, + NULL, + LV_LITTLE_ENDIAN, 64, 0x20000, + 32+16+16+4+4+4+4+4, 8, 1, -1, NULL + }, + [VIR_STORAGE_FILE_CLOOP] = { + /*"#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n", */ /* Untested */ NULL, + NULL, + LV_LITTLE_ENDIAN, -1, 0, + -1, 0, 0, -1, NULL + }, + [VIR_STORAGE_FILE_COW] = { + "OOOM", NULL, + LV_BIG_ENDIAN, 4, 2, + 4+4+1024+4, 8, 1, -1, cowGetBackingStore + }, + [VIR_STORAGE_FILE_DMG] = { + NULL, /* XXX QEMU says there's no magic for dmg, but we should check... */ + ".dmg", + 0, -1, 0, + -1, 0, 0, -1, NULL + }, + [VIR_STORAGE_FILE_ISO] = { + NULL, /* XXX there's probably some magic for iso we can validate too... */ + ".iso", + 0, -1, 0, + -1, 0, 0, -1, NULL + }, + [VIR_STORAGE_FILE_QCOW] = { + "QFI", NULL, + LV_BIG_ENDIAN, 4, 1, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW1_HDR_CRYPT, qcow1GetBackingStore, + }, + [VIR_STORAGE_FILE_QCOW2] = { + "QFI", NULL, + LV_BIG_ENDIAN, 4, 2, + QCOWX_HDR_IMAGE_SIZE, 8, 1, QCOW2_HDR_CRYPT, qcow2GetBackingStore, + }, + [VIR_STORAGE_FILE_QED] = { + /* http://wiki.qemu.org/Features/QED */ + "QED", NULL, + LV_LITTLE_ENDIAN, -2, -1, + QED_HDR_IMAGE_SIZE, 8, 1, -1, qedGetBackingStore, + }, + [VIR_STORAGE_FILE_VMDK] = { + "KDMV", NULL, + LV_LITTLE_ENDIAN, 4, 1, + 4+4+4, 8, 512, -1, vmdk4GetBackingStore + }, + [VIR_STORAGE_FILE_VPC] = { + "conectix", NULL, + LV_BIG_ENDIAN, 12, 0x10000, + 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, -1, NULL + }, + /* Not direct file formats, but used for various drivers */ + [VIR_STORAGE_FILE_FAT] = { NULL, NULL, LV_LITTLE_ENDIAN, + -1, 0, 0, 0, 0, 0, NULL }, + [VIR_STORAGE_FILE_VHD] = { NULL, NULL, LV_LITTLE_ENDIAN, + -1, 0, 0, 0, 0, 0, NULL }, +}; +verify(ARRAY_CARDINALITY(fileTypeInfo) == VIR_STORAGE_FILE_LAST); + +static int +cowGetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ +#define COW_FILENAME_MAXLEN 1024 + *res = NULL; + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size < 4+4+ COW_FILENAME_MAXLEN) + return BACKING_STORE_INVALID; + if (buf[4+4] == '\0') { /* cow_header_v2.backing_file[0] */ + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + + *res = strndup((const char*)buf + 4+4, COW_FILENAME_MAXLEN); + if (*res == NULL) { + virReportOOMError(); + return BACKING_STORE_ERROR; + } + return BACKING_STORE_OK; +} + + +static int +qcow2GetBackingStoreFormat(int *format, + const unsigned char *buf, + size_t buf_size, + size_t extension_start, + size_t extension_end) +{ + size_t offset = extension_start; + + /* + * The extensions take format of + * + * int32: magic + * int32: length + * byte[length]: payload + * + * Unknown extensions can be ignored by skipping + * over "length" bytes in the data stream. + */ + while (offset < (buf_size-8) && + offset < (extension_end-8)) { + unsigned int magic = + (buf[offset] << 24) + + (buf[offset+1] << 16) + + (buf[offset+2] << 8) + + (buf[offset+3]); + unsigned int len = + (buf[offset+4] << 24) + + (buf[offset+5] << 16) + + (buf[offset+6] << 8) + + (buf[offset+7]); + + offset += 8; + + if ((offset + len) < offset) + break; + + if ((offset + len) > buf_size) + break; + + switch (magic) { + case QCOW2_HDR_EXTENSION_END: + goto done; + + case QCOW2_HDR_EXTENSION_BACKING_FORMAT: + if (buf[offset+len] != '\0') + break; + *format = virStorageFileFormatTypeFromString( + ((const char *)buf)+offset); + if (*format <= VIR_STORAGE_FILE_NONE) + return -1; + } + + offset += len; + } + +done: + + return 0; +} + + +static int +qcowXGetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size, + bool isQCow2) +{ + unsigned long long offset; + unsigned int size; + + *res = NULL; + if (format) + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4) + return BACKING_STORE_INVALID; + offset = (((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET] << 56) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+1] << 48) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+2] << 40) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+3] << 32) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+4] << 24) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+5] << 16) + | ((unsigned long long)buf[QCOWX_HDR_BACKING_FILE_OFFSET+6] << 8) + | buf[QCOWX_HDR_BACKING_FILE_OFFSET+7]); /* QCowHeader.backing_file_offset */ + if (offset > buf_size) + return BACKING_STORE_INVALID; + size = ((buf[QCOWX_HDR_BACKING_FILE_SIZE] << 24) + | (buf[QCOWX_HDR_BACKING_FILE_SIZE+1] << 16) + | (buf[QCOWX_HDR_BACKING_FILE_SIZE+2] << 8) + | buf[QCOWX_HDR_BACKING_FILE_SIZE+3]); /* QCowHeader.backing_file_size */ + if (size == 0) { + if (format) + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + if (offset + size > buf_size || offset + size < offset) + return BACKING_STORE_INVALID; + if (size + 1 == 0) + return BACKING_STORE_INVALID; + if (VIR_ALLOC_N(*res, size + 1) < 0) { + virReportOOMError(); + return BACKING_STORE_ERROR; + } + memcpy(*res, buf + offset, size); + (*res)[size] = '\0'; + + /* + * Traditionally QCow2 files had a layout of + * + * [header] + * [backingStoreName] + * + * Although the backingStoreName typically followed + * the header immediately, this was not required by + * the format. By specifying a higher byte offset for + * the backing file offset in the header, it was + * possible to leave space between the header and + * start of backingStore. + * + * This hack is now used to store extensions to the + * qcow2 format: + * + * [header] + * [extensions] + * [backingStoreName] + * + * Thus the file region to search for extensions is + * between the end of the header (QCOW2_HDR_TOTAL_SIZE) + * and the start of the backingStoreName (offset) + */ + if (isQCow2 && format && + qcow2GetBackingStoreFormat(format, buf, buf_size, QCOW2_HDR_TOTAL_SIZE, + offset) < 0) + return BACKING_STORE_INVALID; + + return BACKING_STORE_OK; +} + + +static int +qcow1GetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + int ret; + + /* QCow1 doesn't have the extensions capability + * used to store backing format */ + *format = VIR_STORAGE_FILE_AUTO; + ret = qcowXGetBackingStore(res, NULL, buf, buf_size, false); + if (ret == 0 && *buf == '\0') + *format = VIR_STORAGE_FILE_NONE; + return ret; +} + +static int +qcow2GetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + return qcowXGetBackingStore(res, format, buf, buf_size, true); +} + + +static int +vmdk4GetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + static const char prefix[] = "parentFileNameHint=\""; + char *desc, *start, *end; + size_t len; + int ret = BACKING_STORE_ERROR; + + if (VIR_ALLOC_N(desc, STORAGE_MAX_HEAD + 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + *res = NULL; + /* + * Technically this should have been VMDK, since + * VMDK spec / VMWare impl only support VMDK backed + * by VMDK. QEMU isn't following this though and + * does probing on VMDK backing files, hence we set + * AUTO + */ + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size <= 0x200) { + ret = BACKING_STORE_INVALID; + goto cleanup; + } + len = buf_size - 0x200; + if (len > STORAGE_MAX_HEAD) + len = STORAGE_MAX_HEAD; + memcpy(desc, buf + 0x200, len); + desc[len] = '\0'; + start = strstr(desc, prefix); + if (start == NULL) { + *format = VIR_STORAGE_FILE_NONE; + ret = BACKING_STORE_OK; + goto cleanup; + } + start += strlen(prefix); + end = strchr(start, '"'); + if (end == NULL) { + ret = BACKING_STORE_INVALID; + goto cleanup; + } + if (end == start) { + *format = VIR_STORAGE_FILE_NONE; + ret = BACKING_STORE_OK; + goto cleanup; + } + *end = '\0'; + *res = strdup(start); + if (*res == NULL) { + virReportOOMError(); + goto cleanup; + } + + ret = BACKING_STORE_OK; + +cleanup: + VIR_FREE(desc); + return ret; +} + +static unsigned long +qedGetHeaderUL(const unsigned char *loc) +{ + return (((unsigned long)loc[3] << 24) | + ((unsigned long)loc[2] << 16) | + ((unsigned long)loc[1] << 8) | + ((unsigned long)loc[0] << 0)); +} + +static unsigned long long +qedGetHeaderULL(const unsigned char *loc) +{ + return (((unsigned long long)loc[7] << 56) | + ((unsigned long long)loc[6] << 48) | + ((unsigned long long)loc[5] << 40) | + ((unsigned long long)loc[4] << 32) | + ((unsigned long long)loc[3] << 24) | + ((unsigned long long)loc[2] << 16) | + ((unsigned long long)loc[1] << 8) | + ((unsigned long long)loc[0] << 0)); +} + +static int +qedGetBackingStore(char **res, + int *format, + const unsigned char *buf, + size_t buf_size) +{ + unsigned long long flags; + unsigned long offset, size; + + *res = NULL; + /* Check if this image has a backing file */ + if (buf_size < QED_HDR_FEATURES_OFFSET+8) + return BACKING_STORE_INVALID; + flags = qedGetHeaderULL(buf + QED_HDR_FEATURES_OFFSET); + if (!(flags & QED_F_BACKING_FILE)) { + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + + /* Parse the backing file */ + if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8) + return BACKING_STORE_INVALID; + offset = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_OFFSET); + if (offset > buf_size) + return BACKING_STORE_INVALID; + size = qedGetHeaderUL(buf + QED_HDR_BACKING_FILE_SIZE); + if (size == 0) + return BACKING_STORE_OK; + if (offset + size > buf_size || offset + size < offset) + return BACKING_STORE_INVALID; + if (VIR_ALLOC_N(*res, size + 1) < 0) { + virReportOOMError(); + return BACKING_STORE_ERROR; + } + memcpy(*res, buf + offset, size); + (*res)[size] = '\0'; + + if (flags & QED_F_BACKING_FORMAT_NO_PROBE) + *format = VIR_STORAGE_FILE_RAW; + else + *format = VIR_STORAGE_FILE_AUTO_SAFE; + + return BACKING_STORE_OK; +} + +/** + * Return an absolute path corresponding to PATH, which is absolute or relative + * to the directory containing BASE_FILE, or NULL on error + */ +static char * +absolutePathFromBaseFile(const char *base_file, const char *path) +{ + char *res = NULL; + char *tmp = NULL; + size_t d_len = dir_len(base_file); + + /* If path is already absolute, or if dirname(base_file) is ".", + just return a copy of path. */ + if (*path == '/' || d_len == 0) { + if (!(res = canonicalize_file_name(path))) + virReportSystemError(errno, + _("Can't canonicalize path '%s'"), path); + + goto cleanup; + } + + /* Ensure that the following cast-to-int is valid. */ + if (d_len > INT_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Directory name too long: '%s'"), base_file); + goto cleanup; + } + + if (virAsprintf(&tmp, "%.*s/%s", (int) d_len, base_file, path) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!(res = canonicalize_file_name(tmp))) + virReportSystemError(errno, _("Can't canonicalize path '%s'"), path); + +cleanup: + VIR_FREE(tmp); + return res; +} + + +static bool +virStorageFileMatchesMagic(int format, + unsigned char *buf, + size_t buflen) +{ + int mlen; + + if (fileTypeInfo[format].magic == NULL) + return false; + + /* Validate magic data */ + mlen = strlen(fileTypeInfo[format].magic); + if (mlen > buflen) + return false; + + if (memcmp(buf, fileTypeInfo[format].magic, mlen) != 0) + return false; + + return true; +} + + +static bool +virStorageFileMatchesExtension(int format, + const char *path) +{ + if (fileTypeInfo[format].extension == NULL) + return false; + + if (virFileHasSuffix(path, fileTypeInfo[format].extension)) + return true; + + return false; +} + + +static bool +virStorageFileMatchesVersion(int format, + unsigned char *buf, + size_t buflen) +{ + int version; + + /* Validate version number info */ + if (fileTypeInfo[format].versionOffset == -1) + return false; + + /* -2 == non-versioned file format, so trivially match */ + if (fileTypeInfo[format].versionOffset == -2) + return true; + + if ((fileTypeInfo[format].versionOffset + 4) > buflen) + return false; + + if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) { + version = + (buf[fileTypeInfo[format].versionOffset+3] << 24) | + (buf[fileTypeInfo[format].versionOffset+2] << 16) | + (buf[fileTypeInfo[format].versionOffset+1] << 8) | + (buf[fileTypeInfo[format].versionOffset]); + } else { + version = + (buf[fileTypeInfo[format].versionOffset] << 24) | + (buf[fileTypeInfo[format].versionOffset+1] << 16) | + (buf[fileTypeInfo[format].versionOffset+2] << 8) | + (buf[fileTypeInfo[format].versionOffset+3]); + } + + VIR_DEBUG("Compare detected version %d vs expected version %d", + version, fileTypeInfo[format].versionNumber); + if (version != fileTypeInfo[format].versionNumber) + return false; + + return true; +} + +static bool +virBackingStoreIsFile(const char *backing) +{ + /* Backing store is a network block device or Rados block device */ + if (STRPREFIX(backing, "nbd:") || STRPREFIX(backing, "rbd:")) + return false; + return true; +} + +static int +virStorageFileGetMetadataFromBuf(int format, + const char *path, + unsigned char *buf, + size_t buflen, + virStorageFileMetadata *meta) +{ + VIR_DEBUG("path=%s format=%d", path, format); + + /* XXX we should consider moving virStorageBackendUpdateVolInfo + * code into this method, for non-magic files + */ + if (format <= VIR_STORAGE_FILE_NONE || + format >= VIR_STORAGE_FILE_LAST || + !fileTypeInfo[format].magic) { + return 0; + } + + /* Optionally extract capacity from file */ + if (fileTypeInfo[format].sizeOffset != -1) { + if ((fileTypeInfo[format].sizeOffset + 8) > buflen) + return 1; + + if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) { + meta->capacity = + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7] << 56) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 48) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 40) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 32) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 24) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 16) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 8) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset]); + } else { + meta->capacity = + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset] << 56) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+1] << 48) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+2] << 40) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+3] << 32) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+4] << 24) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+5] << 16) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+6] << 8) | + ((unsigned long long)buf[fileTypeInfo[format].sizeOffset+7]); + } + /* Avoid unlikely, but theoretically possible overflow */ + if (meta->capacity > (ULLONG_MAX / fileTypeInfo[format].sizeMultiplier)) + return 1; + meta->capacity *= fileTypeInfo[format].sizeMultiplier; + } + + if (fileTypeInfo[format].qcowCryptOffset != -1) { + int crypt_format; + + crypt_format = + (buf[fileTypeInfo[format].qcowCryptOffset] << 24) | + (buf[fileTypeInfo[format].qcowCryptOffset+1] << 16) | + (buf[fileTypeInfo[format].qcowCryptOffset+2] << 8) | + (buf[fileTypeInfo[format].qcowCryptOffset+3]); + meta->encrypted = crypt_format != 0; + } + + if (fileTypeInfo[format].getBackingStore != NULL) { + char *backing; + int backingFormat; + int ret = fileTypeInfo[format].getBackingStore(&backing, + &backingFormat, + buf, buflen); + if (ret == BACKING_STORE_INVALID) + return 1; + + if (ret == BACKING_STORE_ERROR) + return -1; + + meta->backingStoreIsFile = false; + if (backing != NULL) { + meta->backingStore = strdup(backing); + if (meta->backingStore == NULL) { + virReportOOMError(); + VIR_FREE(backing); + return -1; + } + if (virBackingStoreIsFile(backing)) { + meta->backingStoreIsFile = true; + meta->backingStoreRaw = meta->backingStore; + meta->backingStore = absolutePathFromBaseFile(path, backing); + if (meta->backingStore == NULL) { + /* the backing file is (currently) unavailable, treat this + * file as standalone: + * backingStoreRaw is kept to mark broken image chains */ + meta->backingStoreIsFile = false; + backingFormat = VIR_STORAGE_FILE_NONE; + VIR_WARN("Backing file '%s' of image '%s' is missing.", + meta->backingStoreRaw, path); + + } + } + VIR_FREE(backing); + meta->backingStoreFormat = backingFormat; + } else { + meta->backingStore = NULL; + meta->backingStoreFormat = VIR_STORAGE_FILE_NONE; + } + } + + return 0; +} + + +static int +virStorageFileProbeFormatFromBuf(const char *path, + unsigned char *buf, + size_t buflen) +{ + int format = VIR_STORAGE_FILE_RAW; + int i; + int possibleFormat = VIR_STORAGE_FILE_RAW; + VIR_DEBUG("path=%s", path); + + /* First check file magic */ + for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) { + if (virStorageFileMatchesMagic(i, buf, buflen)) { + if (!virStorageFileMatchesVersion(i, buf, buflen)) { + possibleFormat = i; + continue; + } + format = i; + goto cleanup; + } + } + + if (possibleFormat != VIR_STORAGE_FILE_RAW) + VIR_WARN("File %s matches %s magic, but version is wrong. " + "Please report new version to libvir-list@redhat.com", + path, virStorageFileFormatTypeToString(possibleFormat)); + + /* No magic, so check file extension */ + for (i = 0 ; i < VIR_STORAGE_FILE_LAST ; i++) { + if (virStorageFileMatchesExtension(i, path)) { + format = i; + goto cleanup; + } + } + +cleanup: + VIR_DEBUG("format=%d", format); + return format; +} + + +/** + * virStorageFileProbeFormatFromFD: + * + * Probe for the format of 'fd' (which is an open file descriptor + * pointing to 'path'), returning the detected disk format. + * + * Callers are advised never to trust the returned 'format' + * unless it is listed as VIR_STORAGE_FILE_RAW, since a + * malicious guest can turn a file into any other non-raw + * format at will. + * + * Best option: Don't use this function + */ +int +virStorageFileProbeFormatFromFD(const char *path, int fd) +{ + unsigned char *head; + ssize_t len = STORAGE_MAX_HEAD; + int ret = -1; + struct stat sb; + + if (fstat(fd, &sb) < 0) { + virReportSystemError(errno, + _("cannot stat file '%s'"), + path); + return -1; + } + + /* No header to probe for directories */ + if (S_ISDIR(sb.st_mode)) { + return VIR_STORAGE_FILE_DIR; + } + + if (VIR_ALLOC_N(head, len) < 0) { + virReportOOMError(); + return -1; + } + + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(errno, _("cannot set to start of '%s'"), path); + goto cleanup; + } + + if ((len = read(fd, head, len)) < 0) { + virReportSystemError(errno, _("cannot read header '%s'"), path); + goto cleanup; + } + + ret = virStorageFileProbeFormatFromBuf(path, head, len); + +cleanup: + VIR_FREE(head); + return ret; +} + + +/** + * virStorageFileProbeFormat: + * + * Probe for the format of 'path', returning the detected + * disk format. + * + * Callers are advised never to trust the returned 'format' + * unless it is listed as VIR_STORAGE_FILE_RAW, since a + * malicious guest can turn a raw file into any other non-raw + * format at will. + * + * Best option: Don't use this function + */ +int +virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid) +{ + int fd, ret; + + if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) { + virReportSystemError(errno, _("cannot open file '%s'"), path); + return -1; + } + + ret = virStorageFileProbeFormatFromFD(path, fd); + + VIR_FORCE_CLOSE(fd); + + return ret; +} + +/** + * virStorageFileGetMetadataFromFD: + * + * Extract metadata about the storage volume with the specified + * image format. If image format is VIR_STORAGE_FILE_AUTO, it + * will probe to automatically identify the format. Does not recurse. + * + * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a + * format, since a malicious guest can turn a raw file into any + * other non-raw format at will. + * + * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO + * it indicates the image didn't specify an explicit format for its + * backing store. Callers are advised against probing for the + * backing store format in this case. + * + * Caller MUST free the result after use via virStorageFileFreeMetadata. + */ +virStorageFileMetadataPtr +virStorageFileGetMetadataFromFD(const char *path, + int fd, + int format) +{ + virStorageFileMetadata *meta = NULL; + unsigned char *head = NULL; + ssize_t len = STORAGE_MAX_HEAD; + virStorageFileMetadata *ret = NULL; + struct stat sb; + + if (VIR_ALLOC(meta) < 0) { + virReportOOMError(); + return NULL; + } + + if (fstat(fd, &sb) < 0) { + virReportSystemError(errno, + _("cannot stat file '%s'"), + path); + goto cleanup; + } + + /* No header to probe for directories, but also no backing file */ + if (S_ISDIR(sb.st_mode)) + return meta; + + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(errno, _("cannot seek to start of '%s'"), path); + goto cleanup; + } + + if (VIR_ALLOC_N(head, len) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((len = read(fd, head, len)) < 0) { + virReportSystemError(errno, _("cannot read header '%s'"), path); + goto cleanup; + } + + if (format == VIR_STORAGE_FILE_AUTO) + format = virStorageFileProbeFormatFromBuf(path, head, len); + + if (format <= VIR_STORAGE_FILE_NONE || + format >= VIR_STORAGE_FILE_LAST) { + virReportSystemError(EINVAL, _("unknown storage file format %d"), + format); + goto cleanup; + } + + if (virStorageFileGetMetadataFromBuf(format, path, head, len, meta) < 0) + goto cleanup; + ret = meta; + meta = NULL; + +cleanup: + virStorageFileFreeMetadata(meta); + VIR_FREE(head); + return ret; +} + +/* Recursive workhorse for virStorageFileGetMetadata. */ +static virStorageFileMetadataPtr +virStorageFileGetMetadataRecurse(const char *path, int format, + uid_t uid, gid_t gid, + bool allow_probe, virHashTablePtr cycle) +{ + int fd; + VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d", + path, format, (int)uid, (int)gid, allow_probe); + + virStorageFileMetadataPtr ret = NULL; + + if (virHashLookup(cycle, path)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("backing store for %s is self-referential"), + path); + return NULL; + } + if (virHashAddEntry(cycle, path, (void *)1) < 0) + return NULL; + + if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) { + virReportSystemError(-fd, _("cannot open file '%s'"), path); + return NULL; + } + + ret = virStorageFileGetMetadataFromFD(path, fd, format); + + if (VIR_CLOSE(fd) < 0) + VIR_WARN("could not close file %s", path); + + if (ret && ret->backingStoreIsFile) { + if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO && !allow_probe) + ret->backingStoreFormat = VIR_STORAGE_FILE_RAW; + else if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO_SAFE) + ret->backingStoreFormat = VIR_STORAGE_FILE_AUTO; + format = ret->backingStoreFormat; + ret->backingMeta = virStorageFileGetMetadataRecurse(ret->backingStore, + format, + uid, gid, + allow_probe, + cycle); + } + + return ret; +} + +/** + * virStorageFileGetMetadata: + * + * Extract metadata about the storage volume with the specified + * image format. If image format is VIR_STORAGE_FILE_AUTO, it + * will probe to automatically identify the format. Recurses through + * the entire chain. + * + * Open files using UID and GID (or pass -1 for the current user/group). + * Treat any backing files without explicit type as raw, unless ALLOW_PROBE. + * + * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a + * format, since a malicious guest can turn a raw file into any + * other non-raw format at will. + * + * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO + * it indicates the image didn't specify an explicit format for its + * backing store. Callers are advised against using ALLOW_PROBE, as + * it would probe the backing store format in this case. + * + * Caller MUST free result after use via virStorageFileFreeMetadata. + */ +virStorageFileMetadataPtr +virStorageFileGetMetadata(const char *path, int format, + uid_t uid, gid_t gid, + bool allow_probe) +{ + VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d", + path, format, (int)uid, (int)gid, allow_probe); + + virHashTablePtr cycle = virHashCreate(5, NULL); + virStorageFileMetadataPtr ret; + + if (!cycle) + return NULL; + + if (format <= VIR_STORAGE_FILE_NONE) + format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW; + ret = virStorageFileGetMetadataRecurse(path, format, uid, gid, + allow_probe, cycle); + virHashFree(cycle); + return ret; +} + +/** + * virStorageFileFreeMetadata: + * + * Free pointers in passed structure and structure itself. + */ +void +virStorageFileFreeMetadata(virStorageFileMetadata *meta) +{ + if (!meta) + return; + + virStorageFileFreeMetadata(meta->backingMeta); + VIR_FREE(meta->backingStore); + VIR_FREE(meta->backingStoreRaw); + VIR_FREE(meta); +} + +/** + * virStorageFileResize: + * + * Change the capacity of the raw storage file at 'path'. + */ +int +virStorageFileResize(const char *path, unsigned long long capacity) +{ + int fd = -1; + int ret = -1; + + if ((fd = open(path, O_RDWR)) < 0) { + virReportSystemError(errno, _("Unable to open '%s'"), path); + goto cleanup; + } + + if (ftruncate(fd, capacity) < 0) { + virReportSystemError(errno, _("Failed to truncate file '%s'"), path); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + virReportSystemError(errno, _("Unable to save '%s'"), path); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FORCE_CLOSE(fd); + return ret; +} + +#ifdef __linux__ + +# ifndef NFS_SUPER_MAGIC +# define NFS_SUPER_MAGIC 0x6969 +# endif +# ifndef OCFS2_SUPER_MAGIC +# define OCFS2_SUPER_MAGIC 0x7461636f +# endif +# ifndef GFS2_MAGIC +# define GFS2_MAGIC 0x01161970 +# endif +# ifndef AFS_FS_MAGIC +# define AFS_FS_MAGIC 0x6B414653 +# endif + + +int virStorageFileIsSharedFSType(const char *path, + int fstypes) +{ + char *dirpath, *p; + struct statfs sb; + int statfs_ret; + + if ((dirpath = strdup(path)) == NULL) { + virReportOOMError(); + return -1; + } + + do { + + /* Try less and less of the path until we get to a + * directory we can stat. Even if we don't have 'x' + * permission on any directory in the path on the NFS + * server (assuming it's NFS), we will be able to stat the + * mount point, and that will properly tell us if the + * fstype is NFS. + */ + + if ((p = strrchr(dirpath, '/')) == NULL) { + virReportSystemError(EINVAL, + _("Invalid relative path '%s'"), path); + VIR_FREE(dirpath); + return -1; + } + + if (p == dirpath) + *(p+1) = '\0'; + else + *p = '\0'; + + statfs_ret = statfs(dirpath, &sb); + + } while ((statfs_ret < 0) && (p != dirpath)); + + VIR_FREE(dirpath); + + if (statfs_ret < 0) { + virReportSystemError(errno, + _("cannot determine filesystem for '%s'"), + path); + return -1; + } + + VIR_DEBUG("Check if path %s with FS magic %lld is shared", + path, (long long int)sb.f_type); + + if ((fstypes & VIR_STORAGE_FILE_SHFS_NFS) && + (sb.f_type == NFS_SUPER_MAGIC)) + return 1; + + if ((fstypes & VIR_STORAGE_FILE_SHFS_GFS2) && + (sb.f_type == GFS2_MAGIC)) + return 1; + if ((fstypes & VIR_STORAGE_FILE_SHFS_OCFS) && + (sb.f_type == OCFS2_SUPER_MAGIC)) + return 1; + if ((fstypes & VIR_STORAGE_FILE_SHFS_AFS) && + (sb.f_type == AFS_FS_MAGIC)) + return 1; + + return 0; +} +#else +int virStorageFileIsSharedFSType(const char *path ATTRIBUTE_UNUSED, + int fstypes ATTRIBUTE_UNUSED) +{ + /* XXX implement me :-) */ + return 0; +} +#endif + +int virStorageFileIsSharedFS(const char *path) +{ + return virStorageFileIsSharedFSType(path, + VIR_STORAGE_FILE_SHFS_NFS | + VIR_STORAGE_FILE_SHFS_GFS2 | + VIR_STORAGE_FILE_SHFS_OCFS | + VIR_STORAGE_FILE_SHFS_AFS); +} + +int virStorageFileIsClusterFS(const char *path) +{ + /* These are coherent cluster filesystems known to be safe for + * migration with cache != none + */ + return virStorageFileIsSharedFSType(path, + VIR_STORAGE_FILE_SHFS_GFS2 | + VIR_STORAGE_FILE_SHFS_OCFS); +} + +#ifdef LVS +int virStorageFileGetLVMKey(const char *path, + char **key) +{ + /* + * # lvs --noheadings --unbuffered --nosuffix --options "uuid" LVNAME + * 06UgP5-2rhb-w3Bo-3mdR-WeoL-pytO-SAa2ky + */ + int status; + virCommandPtr cmd = virCommandNewArgList( + LVS, + "--noheadings", "--unbuffered", "--nosuffix", + "--options", "uuid", path, + NULL + ); + int ret = -1; + + *key = NULL; + + /* Run the program and capture its output */ + virCommandSetOutputBuffer(cmd, key); + if (virCommandRun(cmd, &status) < 0) + goto cleanup; + + /* Explicitly check status == 0, rather than passing NULL + * to virCommandRun because we don't want to raise an actual + * error in this scenario, just return a NULL key. + */ + + if (status == 0 && *key) { + char *nl; + char *tmp = *key; + + /* Find first non-space character */ + while (*tmp && c_isspace(*tmp)) { + tmp++; + } + /* Kill leading spaces */ + if (tmp != *key) + memmove(*key, tmp, strlen(tmp)+1); + + /* Kill trailing newline */ + if ((nl = strchr(*key, '\n'))) + *nl = '\0'; + } + + ret = 0; + +cleanup: + if (*key && STREQ(*key, "")) + VIR_FREE(*key); + + virCommandFree(cmd); + + return ret; +} +#else +int virStorageFileGetLVMKey(const char *path, + char **key ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, _("Unable to get LVM key for %s"), path); + return -1; +} +#endif + +#ifdef HAVE_UDEV +int virStorageFileGetSCSIKey(const char *path, + char **key) +{ + int status; + virCommandPtr cmd = virCommandNewArgList( + "/lib/udev/scsi_id", + "--replace-whitespace", + "--whitelisted", + "--device", path, + NULL + ); + int ret = -1; + + *key = NULL; + + /* Run the program and capture its output */ + virCommandSetOutputBuffer(cmd, key); + if (virCommandRun(cmd, &status) < 0) + goto cleanup; + + /* Explicitly check status == 0, rather than passing NULL + * to virCommandRun because we don't want to raise an actual + * error in this scenario, just return a NULL key. + */ + if (status == 0 && *key) { + char *nl = strchr(*key, '\n'); + if (nl) + *nl = '\0'; + } + + ret = 0; + +cleanup: + if (*key && STREQ(*key, "")) + VIR_FREE(*key); + + virCommandFree(cmd); + + return ret; +} +#else +int virStorageFileGetSCSIKey(const char *path, + char **key ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, _("Unable to get SCSI key for %s"), path); + return -1; +} +#endif + +/* Given a CHAIN that starts at the named file START, return a string + * pointing to either START or within CHAIN that gives the preferred + * name for the backing file NAME within that chain. Pass NULL for + * NAME to find the base of the chain. If META is not NULL, set *META + * to the point in the chain that describes NAME (or to NULL if the + * backing element is not a file). If PARENT is not NULL, set *PARENT + * to the preferred name of the parent (or to NULL if NAME matches + * START). Since the results point within CHAIN, they must not be + * independently freed. */ +const char * +virStorageFileChainLookup(virStorageFileMetadataPtr chain, const char *start, + const char *name, virStorageFileMetadataPtr *meta, + const char **parent) +{ + virStorageFileMetadataPtr owner; + const char *tmp; + + if (!parent) + parent = &tmp; + + *parent = NULL; + if (name ? STREQ(start, name) || virFileLinkPointsTo(start, name) : + !chain->backingStore) { + if (meta) + *meta = chain; + return start; + } + + owner = chain; + *parent = start; + while (owner) { + if (!owner->backingStore) + goto error; + if (!name) { + if (!owner->backingMeta || + !owner->backingMeta->backingStore) + break; + } else if (STREQ_NULLABLE(name, owner->backingStoreRaw) || + STREQ(name, owner->backingStore)) { + break; + } else if (owner->backingStoreIsFile) { + char *absName = absolutePathFromBaseFile(*parent, name); + if (absName && STREQ(absName, owner->backingStore)) { + VIR_FREE(absName); + break; + } + VIR_FREE(absName); + } + *parent = owner->backingStore; + owner = owner->backingMeta; + } + if (!owner) + goto error; + if (meta) + *meta = owner->backingMeta; + return owner->backingStore; + +error: + *parent = NULL; + if (meta) + *meta = NULL; + return NULL; +} diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h new file mode 100644 index 0000000..6fbd275 --- /dev/null +++ b/src/util/virstoragefile.h @@ -0,0 +1,109 @@ +/* + * storage_file.c: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009, 2012 Red Hat, Inc. + * Copyright (C) 2007-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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_STORAGE_FILE_H__ +# define __VIR_STORAGE_FILE_H__ + +# include "util.h" + +enum virStorageFileFormat { + VIR_STORAGE_FILE_AUTO_SAFE = -2, + VIR_STORAGE_FILE_AUTO = -1, + VIR_STORAGE_FILE_NONE = 0, + VIR_STORAGE_FILE_RAW, + VIR_STORAGE_FILE_DIR, + VIR_STORAGE_FILE_BOCHS, + VIR_STORAGE_FILE_CLOOP, + VIR_STORAGE_FILE_COW, + VIR_STORAGE_FILE_DMG, + VIR_STORAGE_FILE_ISO, + VIR_STORAGE_FILE_QCOW, + VIR_STORAGE_FILE_QCOW2, + VIR_STORAGE_FILE_QED, + VIR_STORAGE_FILE_VMDK, + VIR_STORAGE_FILE_VPC, + VIR_STORAGE_FILE_FAT, + VIR_STORAGE_FILE_VHD, + + VIR_STORAGE_FILE_LAST, +}; + +VIR_ENUM_DECL(virStorageFileFormat); + +typedef struct _virStorageFileMetadata virStorageFileMetadata; +typedef virStorageFileMetadata *virStorageFileMetadataPtr; +struct _virStorageFileMetadata { + char *backingStore; /* Canonical name (absolute file, or protocol) */ + char *backingStoreRaw; /* If file, original name, possibly relative */ + int backingStoreFormat; /* enum virStorageFileFormat */ + bool backingStoreIsFile; + virStorageFileMetadataPtr backingMeta; + unsigned long long capacity; + bool encrypted; +}; + +# ifndef DEV_BSIZE +# define DEV_BSIZE 512 +# endif + +int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid); +int virStorageFileProbeFormatFromFD(const char *path, + int fd); + +virStorageFileMetadataPtr virStorageFileGetMetadata(const char *path, + int format, + uid_t uid, gid_t gid, + bool allow_probe); +virStorageFileMetadataPtr virStorageFileGetMetadataFromFD(const char *path, + int fd, + int format); + +const char *virStorageFileChainLookup(virStorageFileMetadataPtr chain, + const char *start, + const char *name, + virStorageFileMetadataPtr *meta, + const char **parent) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); + +int virStorageFileResize(const char *path, unsigned long long capacity); + +enum { + VIR_STORAGE_FILE_SHFS_NFS = (1 << 0), + VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1), + VIR_STORAGE_FILE_SHFS_OCFS = (1 << 2), + VIR_STORAGE_FILE_SHFS_AFS = (1 << 3), +}; + +int virStorageFileIsSharedFS(const char *path); +int virStorageFileIsClusterFS(const char *path); +int virStorageFileIsSharedFSType(const char *path, + int fstypes); + +int virStorageFileGetLVMKey(const char *path, + char **key); +int virStorageFileGetSCSIKey(const char *path, + char **key); + +#endif /* __VIR_STORAGE_FILE_H__ */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index daa90bf..923ff04 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -48,7 +48,7 @@ #include "virterror_internal.h" #include "domain_event.h" #include "storage_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" #include "uuid.h" #include "viralloc.h" #include "nodeinfo.h" diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index 0cbc248..b28c538 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -36,7 +36,7 @@ #include "count-one-bits.h" #include "xenxs_private.h" #include "xen_sxpr.h" -#include "storage_file.h" +#include "virstoragefile.h" /* Get a domain id from a S-expression string */ int xenGetDomIdFromSxprString(const char *sexpr, int xendConfigVersion) diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index c29df1c..007036b 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -37,7 +37,7 @@ #include "xen_xm.h" #include "xen_sxpr.h" #include "domain_conf.h" -#include "storage_file.h" +#include "virstoragefile.h" /* Convenience method to grab a long int from the config file object */ static int xenXMConfigGetBool(virConfPtr conf, -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/conf/domain_conf.h | 2 +- src/qemu/qemu_driver.c | 2 +- src/util/sysinfo.c | 1045 ------------------------------------------------ src/util/sysinfo.h | 105 ----- src/util/virsysinfo.c | 1045 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virsysinfo.h | 105 +++++ 8 files changed, 1154 insertions(+), 1154 deletions(-) delete mode 100644 src/util/sysinfo.c delete mode 100644 src/util/sysinfo.h create mode 100644 src/util/virsysinfo.c create mode 100644 src/util/virsysinfo.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 417f128..c17c63c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/sysinfo.c src/util/util.c src/util/viraudit.c src/util/virauth.c @@ -174,6 +173,7 @@ src/util/virsexpr.c src/util/virsocketaddr.c src/util/virstatslinux.c src/util/virstoragefile.c +src/util/virsysinfo.c src/util/virterror.c src/util/virterror_internal.h src/util/virtime.c diff --git a/src/Makefile.am b/src/Makefile.am index 911c041..376c543 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/sysinfo.c util/sysinfo.h \ util/threads.c util/threads.h \ util/threads-pthread.h \ util/threads-win32.h \ @@ -86,6 +85,7 @@ UTIL_SOURCES = \ util/virsexpr.c util/virsexpr.h \ util/virstatslinux.c util/virstatslinux.h \ util/virstoragefile.c util/virstoragefile.h \ + util/virsysinfo.c util/virsysinfo.h \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 6bac92f..718c6a9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -39,7 +39,7 @@ # include "nwfilter_params.h" # include "nwfilter_conf.h" # include "virnetdevmacvlan.h" -# include "sysinfo.h" +# include "virsysinfo.h" # include "virnetdevvportprofile.h" # include "virnetdevopenvswitch.h" # include "virnetdevbandwidth.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index fd36dfc..0038d95 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -78,7 +78,7 @@ #include "libvirt_internal.h" #include "xml.h" #include "cpu/cpu.h" -#include "sysinfo.h" +#include "virsysinfo.h" #include "domain_nwfilter.h" #include "virhooks.h" #include "virstoragefile.h" diff --git a/src/util/sysinfo.c b/src/util/sysinfo.c deleted file mode 100644 index 667e6a2..0000000 --- a/src/util/sysinfo.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * sysinfo.c: get SMBIOS/sysinfo information from the host - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * Copyright (C) 2010 Daniel Veillard - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel Veillard <veillard@redhat.com> - */ - -#include <config.h> - -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> - -#include "virterror_internal.h" -#include "sysinfo.h" -#include "util.h" -#include "virlog.h" -#include "viralloc.h" -#include "vircommand.h" - -#define VIR_FROM_THIS VIR_FROM_SYSINFO - -#define SYSINFO_SMBIOS_DECODER "dmidecode" -#define SYSINFO "/proc/sysinfo" -#define CPUINFO "/proc/cpuinfo" - -VIR_ENUM_IMPL(virSysinfo, VIR_SYSINFO_LAST, - "smbios"); - -/** - * virSysinfoDefFree: - * @def: a sysinfo structure - * - * Free up the sysinfo structure - */ - -void virSysinfoDefFree(virSysinfoDefPtr def) -{ - int i; - - if (def == NULL) - return; - - VIR_FREE(def->bios_vendor); - VIR_FREE(def->bios_version); - VIR_FREE(def->bios_date); - VIR_FREE(def->bios_release); - - VIR_FREE(def->system_manufacturer); - VIR_FREE(def->system_product); - VIR_FREE(def->system_version); - VIR_FREE(def->system_serial); - VIR_FREE(def->system_uuid); - VIR_FREE(def->system_sku); - VIR_FREE(def->system_family); - - for (i = 0;i < def->nprocessor;i++) { - VIR_FREE(def->processor[i].processor_socket_destination); - VIR_FREE(def->processor[i].processor_type); - VIR_FREE(def->processor[i].processor_family); - VIR_FREE(def->processor[i].processor_manufacturer); - VIR_FREE(def->processor[i].processor_signature); - VIR_FREE(def->processor[i].processor_version); - VIR_FREE(def->processor[i].processor_external_clock); - VIR_FREE(def->processor[i].processor_max_speed); - VIR_FREE(def->processor[i].processor_status); - VIR_FREE(def->processor[i].processor_serial_number); - VIR_FREE(def->processor[i].processor_part_number); - } - VIR_FREE(def->processor); - for (i = 0;i < def->nmemory;i++) { - VIR_FREE(def->memory[i].memory_size); - VIR_FREE(def->memory[i].memory_form_factor); - VIR_FREE(def->memory[i].memory_locator); - VIR_FREE(def->memory[i].memory_bank_locator); - VIR_FREE(def->memory[i].memory_type); - VIR_FREE(def->memory[i].memory_type_detail); - VIR_FREE(def->memory[i].memory_speed); - VIR_FREE(def->memory[i].memory_manufacturer); - VIR_FREE(def->memory[i].memory_serial_number); - VIR_FREE(def->memory[i].memory_part_number); - } - VIR_FREE(def->memory); - - VIR_FREE(def); -} - -/** - * virSysinfoRead: - * - * Tries to read the SMBIOS information from the current host - * - * Returns: a filled up sysinfo structure or NULL in case of error - */ - -#if defined(__powerpc__) -static int -virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret) -{ - char *eol = NULL; - const char *cur; - - if ((cur = strstr(base, "platform")) == NULL) - return 0; - - base = cur; - /* Account for format 'platform : XXXX'*/ - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpaces(&cur); - if (eol && - ((ret->system_family = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - - if ((cur = strstr(base, "model")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpaces(&cur); - if (eol && ((ret->system_serial = strndup(cur, eol - cur)) - == NULL)) - goto no_memory; - } - - if ((cur = strstr(base, "machine")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpaces(&cur); - if (eol && ((ret->system_version = strndup(cur, eol - cur)) - == NULL)) - goto no_memory; - } - - return 0; - -no_memory: - return -1; -} - -static int -virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret) -{ - const char *cur; - char *eol, *tmp_base; - virSysinfoProcessorDefPtr processor; - - while ((tmp_base = strstr(base, "processor")) != NULL) { - base = tmp_base; - eol = strchr(base, '\n'); - cur = strchr(base, ':') + 1; - - if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) { - goto no_memory; - } - processor = &ret->processor[ret->nprocessor - 1]; - - virSkipSpaces(&cur); - if (eol && - ((processor->processor_socket_destination = strndup - (cur, eol - cur)) == NULL)) - goto no_memory; - - if ((cur = strstr(base, "cpu")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpaces(&cur); - if (eol && - ((processor->processor_type = strndup(cur, eol - cur)) - == NULL)) - goto no_memory; - } - - if ((cur = strstr(base, "revision")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpaces(&cur); - if (eol && - ((processor->processor_version = strndup(cur, eol - cur)) - == NULL)) - goto no_memory; - } - - base = cur; - } - - return 0; - -no_memory: - return -1; -} - -/* virSysinfoRead for PowerPC - * Gathers sysinfo data from /proc/cpuinfo */ -virSysinfoDefPtr -virSysinfoRead(void) { - virSysinfoDefPtr ret = NULL; - char *outbuf = NULL; - - if (VIR_ALLOC(ret) < 0) - goto no_memory; - - if (virFileReadAll(CPUINFO, 2048, &outbuf) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to open %s"), CPUINFO); - return NULL; - } - - ret->nprocessor = 0; - ret->processor = NULL; - if (virSysinfoParseProcessor(outbuf, ret) < 0) - goto no_memory; - - if (virSysinfoParseSystem(outbuf, ret) < 0) - goto no_memory; - - return ret; - -no_memory: - VIR_FREE(outbuf); - return NULL; -} - -#elif defined(__s390__) || defined(__s390x__) - -static int -virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret) -{ - char *cur, *eol = NULL; - const char *property; - - /* Return if Manufacturer field is not found */ - if ((cur = strstr(base, "Manufacturer")) == NULL) - return 0; - - base = cur; - if ((cur = strstr(base, "Manufacturer")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && ((property = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - virSkipSpaces(&property); - ret->system_manufacturer = (char *) property; - } - if ((cur = strstr(base, "Type")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && ((property = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - virSkipSpaces(&property); - ret->system_family = (char *) property; - } - if ((cur = strstr(base, "Sequence Code")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && ((property = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - virSkipSpaces(&property); - ret->system_serial = (char *) property; - } - - return 0; - -no_memory: - return -1; -} - -static int -virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret) -{ - char *cur, *eol, *tmp_base; - char *manufacturer; - const char *tmp; - virSysinfoProcessorDefPtr processor; - - if ((cur = strstr(base, "vendor_id")) != NULL) { - cur = strchr(cur, ':') + 1; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && ((tmp = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - virSkipSpaces(&tmp); - manufacturer = (char *) tmp; - } - - /* Find processor N: line and gather the processor manufacturer, version, - * serial number, and family */ - while ((tmp_base = strstr(base, "processor ")) != NULL) { - base = tmp_base; - eol = strchr(base, '\n'); - cur = strchr(base, ':') + 1; - - if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) { - goto no_memory; - } - - processor = &ret->processor[ret->nprocessor - 1]; - - /* Set the processor manufacturer */ - processor->processor_manufacturer = manufacturer; - - if ((cur = strstr(base, "version =")) != NULL) { - cur += sizeof("version ="); - eol = strchr(cur, ','); - if ((eol) && - ((processor->processor_version = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "identification =")) != NULL) { - cur += sizeof("identification ="); - eol = strchr(cur, ','); - if ((eol) && - ((processor->processor_serial_number = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "machine =")) != NULL) { - cur += sizeof("machine ="); - eol = strchr(cur, '\n'); - if ((eol) && - ((processor->processor_family = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - - base = cur; - } - - return 0; - -no_memory: - return -1; -} - -/* virSysinfoRead for s390x - * Gathers sysinfo data from /proc/sysinfo and /proc/cpuinfo */ -virSysinfoDefPtr -virSysinfoRead(void) { - virSysinfoDefPtr ret = NULL; - char *outbuf = NULL; - - if (VIR_ALLOC(ret) < 0) - goto no_memory; - - /* Gather info from /proc/cpuinfo */ - if (virFileReadAll(CPUINFO, 8192, &outbuf) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to open %s"), CPUINFO); - return NULL; - } - - ret->nprocessor = 0; - ret->processor = NULL; - if (virSysinfoParseProcessor(outbuf, ret) < 0) - goto no_memory; - - /* Free buffer before reading next file */ - VIR_FREE(outbuf); - - /* Gather info from /proc/sysinfo */ - if (virFileReadAll(SYSINFO, 8192, &outbuf) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to open %s"), SYSINFO); - return NULL; - } - - if (virSysinfoParseSystem(outbuf, ret) < 0) - goto no_memory; - - return ret; - -no_memory: - VIR_FREE(outbuf); - return NULL; -} - -#elif defined(WIN32) || \ - !(defined(__x86_64__) || \ - defined(__i386__) || \ - defined(__amd64__) || \ - defined(__powerpc__)) -virSysinfoDefPtr -virSysinfoRead(void) { - /* - * this can probably be extracted from Windows using API or registry - * http://www.microsoft.com/whdc/system/platform/firmware/SMBIOS.mspx - */ - virReportSystemError(ENOSYS, "%s", - _("Host sysinfo extraction not supported on this platform")); - return NULL; -} - -#else /* !WIN32 && x86 */ - -static int -virSysinfoParseBIOS(const char *base, virSysinfoDefPtr ret) -{ - const char *cur, *eol = NULL; - - if ((cur = strstr(base, "BIOS Information")) == NULL) - return 0; - - base = cur; - if ((cur = strstr(base, "Vendor: ")) != NULL) { - cur += 8; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->bios_vendor = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Version: ")) != NULL) { - cur += 9; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->bios_version = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Release Date: ")) != NULL) { - cur += 14; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->bios_date = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "BIOS Revision: ")) != NULL) { - cur += 15; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->bios_release = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - - return 0; - -no_memory: - return -1; -} - -static int -virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret) -{ - const char *cur, *eol = NULL; - - if ((cur = strstr(base, "System Information")) == NULL) - return 0; - - base = cur; - if ((cur = strstr(base, "Manufacturer: ")) != NULL) { - cur += 14; - eol = strchr(cur, '\n'); - if ((eol) && - ((ret->system_manufacturer = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Product Name: ")) != NULL) { - cur += 14; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->system_product = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Version: ")) != NULL) { - cur += 9; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->system_version = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Serial Number: ")) != NULL) { - cur += 15; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->system_serial = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "UUID: ")) != NULL) { - cur += 6; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->system_uuid = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "SKU Number: ")) != NULL) { - cur += 12; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->system_sku = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Family: ")) != NULL) { - cur += 8; - eol = strchr(cur, '\n'); - if ((eol) && ((ret->system_family = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - - return 0; - -no_memory: - return -1; -} - -static int -virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret) -{ - const char *cur, *tmp_base; - char *eol; - virSysinfoProcessorDefPtr processor; - - while ((tmp_base = strstr(base, "Processor Information")) != NULL) { - base = tmp_base; - eol = NULL; - - if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) { - goto no_memory; - } - processor = &ret->processor[ret->nprocessor - 1]; - - if ((cur = strstr(base, "Socket Designation: ")) != NULL) { - cur += 20; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_socket_destination - = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Type: ")) != NULL) { - cur += 6; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_type = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Family: ")) != NULL) { - cur += 8; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_family = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Manufacturer: ")) != NULL) { - cur += 14; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_manufacturer - = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Signature: ")) != NULL) { - cur += 11; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_signature - = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Version: ")) != NULL) { - cur += 9; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_version = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "External Clock: ")) != NULL) { - cur += 16; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_external_clock - = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Max Speed: ")) != NULL) { - cur += 11; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_max_speed - = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Status: ")) != NULL) { - cur += 8; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_status = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Serial Number: ")) != NULL) { - cur += 15; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_serial_number - = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Part Number: ")) != NULL) { - cur += 13; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((processor->processor_part_number - = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - - base += strlen("Processor Information"); - } - - return 0; - -no_memory: - return -1; -} - -static int -virSysinfoParseMemory(const char *base, virSysinfoDefPtr ret) -{ - const char *cur, *tmp_base; - char *eol; - virSysinfoMemoryDefPtr memory; - - while ((tmp_base = strstr(base, "Memory Device")) != NULL) { - base = tmp_base; - eol = NULL; - - if (VIR_EXPAND_N(ret->memory, ret->nmemory, 1) < 0) { - goto no_memory; - } - memory = &ret->memory[ret->nmemory - 1]; - - if ((cur = strstr(base, "Size: ")) != NULL) { - cur += 6; - eol = strchr(cur, '\n'); - if (STREQLEN(cur, "No Module Installed", eol - cur)) - goto next; - - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_size = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Form Factor: ")) != NULL) { - cur += 13; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_form_factor = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Locator: ")) != NULL) { - cur += 9; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_locator = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Bank Locator: ")) != NULL) { - cur += 14; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_bank_locator = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Type: ")) != NULL) { - cur += 6; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_type = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Type Detail: ")) != NULL) { - cur += 13; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_type_detail = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Speed: ")) != NULL) { - cur += 7; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_speed = strndup(cur, eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Manufacturer: ")) != NULL) { - cur += 14; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_manufacturer = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Serial Number: ")) != NULL) { - cur += 15; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_serial_number = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - if ((cur = strstr(base, "Part Number: ")) != NULL) { - cur += 13; - eol = strchr(cur, '\n'); - virSkipSpacesBackwards(cur, &eol); - if ((eol) && - ((memory->memory_part_number = strndup(cur, - eol - cur)) == NULL)) - goto no_memory; - } - - next: - base += strlen("Memory Device"); - } - - return 0; - -no_memory: - return -1; -} - -virSysinfoDefPtr -virSysinfoRead(void) { - char *path; - virSysinfoDefPtr ret = NULL; - char *outbuf = NULL; - virCommandPtr cmd; - - path = virFindFileInPath(SYSINFO_SMBIOS_DECODER); - if (path == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to find path for %s binary"), - SYSINFO_SMBIOS_DECODER); - return NULL; - } - - cmd = virCommandNewArgList(path, "-q", "-t", "0,1,4,17", NULL); - VIR_FREE(path); - virCommandSetOutputBuffer(cmd, &outbuf); - if (virCommandRun(cmd, NULL) < 0) - goto cleanup; - - if (VIR_ALLOC(ret) < 0) - goto no_memory; - - ret->type = VIR_SYSINFO_SMBIOS; - - if (virSysinfoParseBIOS(outbuf, ret) < 0) - goto no_memory; - - if (virSysinfoParseSystem(outbuf, ret) < 0) - goto no_memory; - - ret->nprocessor = 0; - ret->processor = NULL; - if (virSysinfoParseProcessor(outbuf, ret) < 0) - goto no_memory; - - ret->nmemory = 0; - ret->memory = NULL; - if (virSysinfoParseMemory(outbuf, ret) < 0) - goto no_memory; - -cleanup: - VIR_FREE(outbuf); - virCommandFree(cmd); - - return ret; - -no_memory: - virReportOOMError(); - - virSysinfoDefFree(ret); - ret = NULL; - goto cleanup; -} -#endif /* !WIN32 && x86 */ - -static void -virSysinfoBIOSFormat(virBufferPtr buf, virSysinfoDefPtr def) -{ - if (!def->bios_vendor && !def->bios_version && - !def->bios_date && !def->bios_release) - return; - - virBufferAddLit(buf, " <bios>\n"); - virBufferEscapeString(buf, " <entry name='vendor'>%s</entry>\n", - def->bios_vendor); - virBufferEscapeString(buf, " <entry name='version'>%s</entry>\n", - def->bios_version); - virBufferEscapeString(buf, " <entry name='date'>%s</entry>\n", - def->bios_date); - virBufferEscapeString(buf, " <entry name='release'>%s</entry>\n", - def->bios_release); - virBufferAddLit(buf, " </bios>\n"); -} - -static void -virSysinfoSystemFormat(virBufferPtr buf, virSysinfoDefPtr def) -{ - if (!def->system_manufacturer && !def->system_product && - !def->system_version && !def->system_serial && - !def->system_uuid && !def->system_sku && !def->system_family) - return; - - virBufferAddLit(buf, " <system>\n"); - virBufferEscapeString(buf, " <entry name='manufacturer'>%s</entry>\n", - def->system_manufacturer); - virBufferEscapeString(buf, " <entry name='product'>%s</entry>\n", - def->system_product); - virBufferEscapeString(buf, " <entry name='version'>%s</entry>\n", - def->system_version); - virBufferEscapeString(buf, " <entry name='serial'>%s</entry>\n", - def->system_serial); - virBufferEscapeString(buf, " <entry name='uuid'>%s</entry>\n", - def->system_uuid); - virBufferEscapeString(buf, " <entry name='sku'>%s</entry>\n", - def->system_sku); - virBufferEscapeString(buf, " <entry name='family'>%s</entry>\n", - def->system_family); - virBufferAddLit(buf, " </system>\n"); -} - -static void -virSysinfoProcessorFormat(virBufferPtr buf, virSysinfoDefPtr def) -{ - int i; - virSysinfoProcessorDefPtr processor; - - for (i = 0; i < def->nprocessor; i++) { - processor = &def->processor[i]; - - if (!processor->processor_socket_destination && - !processor->processor_type && - !processor->processor_family && - !processor->processor_manufacturer && - !processor->processor_signature && - !processor->processor_version && - !processor->processor_external_clock && - !processor->processor_max_speed && - !processor->processor_status && - !processor->processor_serial_number && - !processor->processor_part_number) - continue; - - virBufferAddLit(buf, " <processor>\n"); - virBufferAdjustIndent(buf, 4); - virBufferEscapeString(buf, - "<entry name='socket_destination'>%s</entry>\n", - processor->processor_socket_destination); - virBufferEscapeString(buf, "<entry name='type'>%s</entry>\n", - processor->processor_type); - virBufferEscapeString(buf, "<entry name='family'>%s</entry>\n", - processor->processor_family); - virBufferEscapeString(buf, "<entry name='manufacturer'>%s</entry>\n", - processor->processor_manufacturer); - virBufferEscapeString(buf, "<entry name='signature'>%s</entry>\n", - processor->processor_signature); - virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n", - processor->processor_version); - virBufferEscapeString(buf, "<entry name='external_clock'>%s</entry>\n", - processor->processor_external_clock); - virBufferEscapeString(buf, "<entry name='max_speed'>%s</entry>\n", - processor->processor_max_speed); - virBufferEscapeString(buf, "<entry name='status'>%s</entry>\n", - processor->processor_status); - virBufferEscapeString(buf, "<entry name='serial_number'>%s</entry>\n", - processor->processor_serial_number); - virBufferEscapeString(buf, "<entry name='part_number'>%s</entry>\n", - processor->processor_part_number); - virBufferAdjustIndent(buf, -4); - virBufferAddLit(buf, " </processor>\n"); - } -} - -static void -virSysinfoMemoryFormat(virBufferPtr buf, virSysinfoDefPtr def) -{ - int i; - virSysinfoMemoryDefPtr memory; - - for (i = 0; i < def->nmemory; i++) { - memory = &def->memory[i]; - - if (!memory->memory_size && - !memory->memory_form_factor && - !memory->memory_locator && - !memory->memory_bank_locator && - !memory->memory_type && - !memory->memory_type_detail && - !memory->memory_speed && - !memory->memory_manufacturer && - !memory->memory_serial_number && - !memory->memory_part_number) - continue; - - virBufferAddLit(buf, " <memory_device>\n"); - virBufferEscapeString(buf, " <entry name='size'>%s</entry>\n", - memory->memory_size); - virBufferEscapeString(buf, - " <entry name='form_factor'>%s</entry>\n", - memory->memory_form_factor); - virBufferEscapeString(buf, " <entry name='locator'>%s</entry>\n", - memory->memory_locator); - virBufferEscapeString(buf, - " <entry name='bank_locator'>%s</entry>\n", - memory->memory_bank_locator); - virBufferEscapeString(buf, " <entry name='type'>%s</entry>\n", - memory->memory_type); - virBufferEscapeString(buf, - " <entry name='type_detail'>%s</entry>\n", - memory->memory_type_detail); - virBufferEscapeString(buf, " <entry name='speed'>%s</entry>\n", - memory->memory_speed); - virBufferEscapeString(buf, - " <entry name='manufacturer'>%s</entry>\n", - memory->memory_manufacturer); - virBufferEscapeString(buf, - " <entry name='serial_number'>%s</entry>\n", - memory->memory_serial_number); - virBufferEscapeString(buf, - " <entry name='part_number'>%s</entry>\n", - memory->memory_part_number); - virBufferAddLit(buf, " </memory_device>\n"); - } -} - -/** - * virSysinfoFormat: - * @buf: buffer to append output to (may use auto-indentation) - * @def: structure to convert to xml string - * - * Returns 0 on success, -1 on failure after generating an error message. - */ -int -virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) -{ - const char *type = virSysinfoTypeToString(def->type); - - if (!type) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unexpected sysinfo type model %d"), - def->type); - virBufferFreeAndReset(buf); - return -1; - } - - virBufferAsprintf(buf, "<sysinfo type='%s'>\n", type); - - virSysinfoBIOSFormat(buf, def); - virSysinfoSystemFormat(buf, def); - virSysinfoProcessorFormat(buf, def); - virSysinfoMemoryFormat(buf, def); - - virBufferAddLit(buf, "</sysinfo>\n"); - - if (virBufferError(buf)) { - virReportOOMError(); - return -1; - } - - return 0; -} - -bool virSysinfoIsEqual(virSysinfoDefPtr src, - virSysinfoDefPtr dst) -{ - bool identical = false; - - if (!src && !dst) - return true; - - if ((src && !dst) || (!src && dst)) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Target sysinfo does not match source")); - goto cleanup; - } - - if (src->type != dst->type) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Target sysinfo %s does not match source %s"), - virSysinfoTypeToString(dst->type), - virSysinfoTypeToString(src->type)); - goto cleanup; - } - -#define CHECK_FIELD(name, desc) \ - do { \ - if (STRNEQ_NULLABLE(src->name, dst->name)) { \ - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \ - _("Target sysinfo %s %s does not match source %s"), \ - desc, NULLSTR(src->name), NULLSTR(dst->name)); \ - } \ - } while (0) - - CHECK_FIELD(bios_vendor, "BIOS vendor"); - CHECK_FIELD(bios_version, "BIOS version"); - CHECK_FIELD(bios_date, "BIOS date"); - CHECK_FIELD(bios_release, "BIOS release"); - - CHECK_FIELD(system_manufacturer, "system vendor"); - CHECK_FIELD(system_product, "system product"); - CHECK_FIELD(system_version, "system version"); - CHECK_FIELD(system_serial, "system serial"); - CHECK_FIELD(system_uuid, "system uuid"); - CHECK_FIELD(system_sku, "system sku"); - CHECK_FIELD(system_family, "system family"); - -#undef CHECK_FIELD - - identical = true; - -cleanup: - return identical; -} diff --git a/src/util/sysinfo.h b/src/util/sysinfo.h deleted file mode 100644 index 0b1f000..0000000 --- a/src/util/sysinfo.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * sysinfo.h: structure and entry points for sysinfo support - * - * Copyright (C) 2010-2011 Red Hat, Inc. - * Copyright (C) 2010 Daniel Veillard - * - * 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: Daniel Veillard <veillard@redhat.com> - */ - -#ifndef __VIR_SYSINFOS_H__ -# define __VIR_SYSINFOS_H__ - -# include "internal.h" -# include "util.h" -# include "virbuffer.h" - -enum virSysinfoType { - VIR_SYSINFO_SMBIOS, - - VIR_SYSINFO_LAST -}; - -typedef struct _virSysinfoProcessorDef virSysinfoProcessorDef; -typedef virSysinfoProcessorDef *virSysinfoProcessorDefPtr; -struct _virSysinfoProcessorDef { - char *processor_socket_destination; - char *processor_type; - char *processor_family; - char *processor_manufacturer; - char *processor_signature; - char *processor_version; - char *processor_external_clock; - char *processor_max_speed; - char *processor_status; - char *processor_serial_number; - char *processor_part_number; -}; - -typedef struct _virSysinfoMemoryDef virSysinfoMemoryDef; -typedef virSysinfoMemoryDef *virSysinfoMemoryDefPtr; -struct _virSysinfoMemoryDef { - char *memory_size; - char *memory_form_factor; - char *memory_locator; - char *memory_bank_locator; - char *memory_type; - char *memory_type_detail; - char *memory_speed; - char *memory_manufacturer; - char *memory_serial_number; - char *memory_part_number; -}; - -typedef struct _virSysinfoDef virSysinfoDef; -typedef virSysinfoDef *virSysinfoDefPtr; -struct _virSysinfoDef { - int type; - - char *bios_vendor; - char *bios_version; - char *bios_date; - char *bios_release; - - char *system_manufacturer; - char *system_product; - char *system_version; - char *system_serial; - char *system_uuid; - char *system_sku; - char *system_family; - - size_t nprocessor; - virSysinfoProcessorDefPtr processor; - - size_t nmemory; - virSysinfoMemoryDefPtr memory; -}; - -virSysinfoDefPtr virSysinfoRead(void); - -void virSysinfoDefFree(virSysinfoDefPtr def); - -int virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -bool virSysinfoIsEqual(virSysinfoDefPtr src, - virSysinfoDefPtr dst); - -VIR_ENUM_DECL(virSysinfo) - -#endif /* __VIR_SYSINFOS_H__ */ diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c new file mode 100644 index 0000000..13d3c22 --- /dev/null +++ b/src/util/virsysinfo.c @@ -0,0 +1,1045 @@ +/* + * sysinfo.c: get SMBIOS/sysinfo information from the host + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * Copyright (C) 2010 Daniel Veillard + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#include "virterror_internal.h" +#include "virsysinfo.h" +#include "util.h" +#include "virlog.h" +#include "viralloc.h" +#include "vircommand.h" + +#define VIR_FROM_THIS VIR_FROM_SYSINFO + +#define SYSINFO_SMBIOS_DECODER "dmidecode" +#define SYSINFO "/proc/sysinfo" +#define CPUINFO "/proc/cpuinfo" + +VIR_ENUM_IMPL(virSysinfo, VIR_SYSINFO_LAST, + "smbios"); + +/** + * virSysinfoDefFree: + * @def: a sysinfo structure + * + * Free up the sysinfo structure + */ + +void virSysinfoDefFree(virSysinfoDefPtr def) +{ + int i; + + if (def == NULL) + return; + + VIR_FREE(def->bios_vendor); + VIR_FREE(def->bios_version); + VIR_FREE(def->bios_date); + VIR_FREE(def->bios_release); + + VIR_FREE(def->system_manufacturer); + VIR_FREE(def->system_product); + VIR_FREE(def->system_version); + VIR_FREE(def->system_serial); + VIR_FREE(def->system_uuid); + VIR_FREE(def->system_sku); + VIR_FREE(def->system_family); + + for (i = 0;i < def->nprocessor;i++) { + VIR_FREE(def->processor[i].processor_socket_destination); + VIR_FREE(def->processor[i].processor_type); + VIR_FREE(def->processor[i].processor_family); + VIR_FREE(def->processor[i].processor_manufacturer); + VIR_FREE(def->processor[i].processor_signature); + VIR_FREE(def->processor[i].processor_version); + VIR_FREE(def->processor[i].processor_external_clock); + VIR_FREE(def->processor[i].processor_max_speed); + VIR_FREE(def->processor[i].processor_status); + VIR_FREE(def->processor[i].processor_serial_number); + VIR_FREE(def->processor[i].processor_part_number); + } + VIR_FREE(def->processor); + for (i = 0;i < def->nmemory;i++) { + VIR_FREE(def->memory[i].memory_size); + VIR_FREE(def->memory[i].memory_form_factor); + VIR_FREE(def->memory[i].memory_locator); + VIR_FREE(def->memory[i].memory_bank_locator); + VIR_FREE(def->memory[i].memory_type); + VIR_FREE(def->memory[i].memory_type_detail); + VIR_FREE(def->memory[i].memory_speed); + VIR_FREE(def->memory[i].memory_manufacturer); + VIR_FREE(def->memory[i].memory_serial_number); + VIR_FREE(def->memory[i].memory_part_number); + } + VIR_FREE(def->memory); + + VIR_FREE(def); +} + +/** + * virSysinfoRead: + * + * Tries to read the SMBIOS information from the current host + * + * Returns: a filled up sysinfo structure or NULL in case of error + */ + +#if defined(__powerpc__) +static int +virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret) +{ + char *eol = NULL; + const char *cur; + + if ((cur = strstr(base, "platform")) == NULL) + return 0; + + base = cur; + /* Account for format 'platform : XXXX'*/ + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpaces(&cur); + if (eol && + ((ret->system_family = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + + if ((cur = strstr(base, "model")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpaces(&cur); + if (eol && ((ret->system_serial = strndup(cur, eol - cur)) + == NULL)) + goto no_memory; + } + + if ((cur = strstr(base, "machine")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpaces(&cur); + if (eol && ((ret->system_version = strndup(cur, eol - cur)) + == NULL)) + goto no_memory; + } + + return 0; + +no_memory: + return -1; +} + +static int +virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret) +{ + const char *cur; + char *eol, *tmp_base; + virSysinfoProcessorDefPtr processor; + + while ((tmp_base = strstr(base, "processor")) != NULL) { + base = tmp_base; + eol = strchr(base, '\n'); + cur = strchr(base, ':') + 1; + + if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) { + goto no_memory; + } + processor = &ret->processor[ret->nprocessor - 1]; + + virSkipSpaces(&cur); + if (eol && + ((processor->processor_socket_destination = strndup + (cur, eol - cur)) == NULL)) + goto no_memory; + + if ((cur = strstr(base, "cpu")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpaces(&cur); + if (eol && + ((processor->processor_type = strndup(cur, eol - cur)) + == NULL)) + goto no_memory; + } + + if ((cur = strstr(base, "revision")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpaces(&cur); + if (eol && + ((processor->processor_version = strndup(cur, eol - cur)) + == NULL)) + goto no_memory; + } + + base = cur; + } + + return 0; + +no_memory: + return -1; +} + +/* virSysinfoRead for PowerPC + * Gathers sysinfo data from /proc/cpuinfo */ +virSysinfoDefPtr +virSysinfoRead(void) { + virSysinfoDefPtr ret = NULL; + char *outbuf = NULL; + + if (VIR_ALLOC(ret) < 0) + goto no_memory; + + if (virFileReadAll(CPUINFO, 2048, &outbuf) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open %s"), CPUINFO); + return NULL; + } + + ret->nprocessor = 0; + ret->processor = NULL; + if (virSysinfoParseProcessor(outbuf, ret) < 0) + goto no_memory; + + if (virSysinfoParseSystem(outbuf, ret) < 0) + goto no_memory; + + return ret; + +no_memory: + VIR_FREE(outbuf); + return NULL; +} + +#elif defined(__s390__) || defined(__s390x__) + +static int +virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret) +{ + char *cur, *eol = NULL; + const char *property; + + /* Return if Manufacturer field is not found */ + if ((cur = strstr(base, "Manufacturer")) == NULL) + return 0; + + base = cur; + if ((cur = strstr(base, "Manufacturer")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && ((property = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + virSkipSpaces(&property); + ret->system_manufacturer = (char *) property; + } + if ((cur = strstr(base, "Type")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && ((property = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + virSkipSpaces(&property); + ret->system_family = (char *) property; + } + if ((cur = strstr(base, "Sequence Code")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && ((property = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + virSkipSpaces(&property); + ret->system_serial = (char *) property; + } + + return 0; + +no_memory: + return -1; +} + +static int +virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret) +{ + char *cur, *eol, *tmp_base; + char *manufacturer; + const char *tmp; + virSysinfoProcessorDefPtr processor; + + if ((cur = strstr(base, "vendor_id")) != NULL) { + cur = strchr(cur, ':') + 1; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && ((tmp = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + virSkipSpaces(&tmp); + manufacturer = (char *) tmp; + } + + /* Find processor N: line and gather the processor manufacturer, version, + * serial number, and family */ + while ((tmp_base = strstr(base, "processor ")) != NULL) { + base = tmp_base; + eol = strchr(base, '\n'); + cur = strchr(base, ':') + 1; + + if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) { + goto no_memory; + } + + processor = &ret->processor[ret->nprocessor - 1]; + + /* Set the processor manufacturer */ + processor->processor_manufacturer = manufacturer; + + if ((cur = strstr(base, "version =")) != NULL) { + cur += sizeof("version ="); + eol = strchr(cur, ','); + if ((eol) && + ((processor->processor_version = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "identification =")) != NULL) { + cur += sizeof("identification ="); + eol = strchr(cur, ','); + if ((eol) && + ((processor->processor_serial_number = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "machine =")) != NULL) { + cur += sizeof("machine ="); + eol = strchr(cur, '\n'); + if ((eol) && + ((processor->processor_family = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + + base = cur; + } + + return 0; + +no_memory: + return -1; +} + +/* virSysinfoRead for s390x + * Gathers sysinfo data from /proc/sysinfo and /proc/cpuinfo */ +virSysinfoDefPtr +virSysinfoRead(void) { + virSysinfoDefPtr ret = NULL; + char *outbuf = NULL; + + if (VIR_ALLOC(ret) < 0) + goto no_memory; + + /* Gather info from /proc/cpuinfo */ + if (virFileReadAll(CPUINFO, 8192, &outbuf) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open %s"), CPUINFO); + return NULL; + } + + ret->nprocessor = 0; + ret->processor = NULL; + if (virSysinfoParseProcessor(outbuf, ret) < 0) + goto no_memory; + + /* Free buffer before reading next file */ + VIR_FREE(outbuf); + + /* Gather info from /proc/sysinfo */ + if (virFileReadAll(SYSINFO, 8192, &outbuf) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to open %s"), SYSINFO); + return NULL; + } + + if (virSysinfoParseSystem(outbuf, ret) < 0) + goto no_memory; + + return ret; + +no_memory: + VIR_FREE(outbuf); + return NULL; +} + +#elif defined(WIN32) || \ + !(defined(__x86_64__) || \ + defined(__i386__) || \ + defined(__amd64__) || \ + defined(__powerpc__)) +virSysinfoDefPtr +virSysinfoRead(void) { + /* + * this can probably be extracted from Windows using API or registry + * http://www.microsoft.com/whdc/system/platform/firmware/SMBIOS.mspx + */ + virReportSystemError(ENOSYS, "%s", + _("Host sysinfo extraction not supported on this platform")); + return NULL; +} + +#else /* !WIN32 && x86 */ + +static int +virSysinfoParseBIOS(const char *base, virSysinfoDefPtr ret) +{ + const char *cur, *eol = NULL; + + if ((cur = strstr(base, "BIOS Information")) == NULL) + return 0; + + base = cur; + if ((cur = strstr(base, "Vendor: ")) != NULL) { + cur += 8; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->bios_vendor = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Version: ")) != NULL) { + cur += 9; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->bios_version = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Release Date: ")) != NULL) { + cur += 14; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->bios_date = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "BIOS Revision: ")) != NULL) { + cur += 15; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->bios_release = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + + return 0; + +no_memory: + return -1; +} + +static int +virSysinfoParseSystem(const char *base, virSysinfoDefPtr ret) +{ + const char *cur, *eol = NULL; + + if ((cur = strstr(base, "System Information")) == NULL) + return 0; + + base = cur; + if ((cur = strstr(base, "Manufacturer: ")) != NULL) { + cur += 14; + eol = strchr(cur, '\n'); + if ((eol) && + ((ret->system_manufacturer = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Product Name: ")) != NULL) { + cur += 14; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->system_product = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Version: ")) != NULL) { + cur += 9; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->system_version = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Serial Number: ")) != NULL) { + cur += 15; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->system_serial = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "UUID: ")) != NULL) { + cur += 6; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->system_uuid = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "SKU Number: ")) != NULL) { + cur += 12; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->system_sku = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Family: ")) != NULL) { + cur += 8; + eol = strchr(cur, '\n'); + if ((eol) && ((ret->system_family = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + + return 0; + +no_memory: + return -1; +} + +static int +virSysinfoParseProcessor(const char *base, virSysinfoDefPtr ret) +{ + const char *cur, *tmp_base; + char *eol; + virSysinfoProcessorDefPtr processor; + + while ((tmp_base = strstr(base, "Processor Information")) != NULL) { + base = tmp_base; + eol = NULL; + + if (VIR_EXPAND_N(ret->processor, ret->nprocessor, 1) < 0) { + goto no_memory; + } + processor = &ret->processor[ret->nprocessor - 1]; + + if ((cur = strstr(base, "Socket Designation: ")) != NULL) { + cur += 20; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_socket_destination + = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Type: ")) != NULL) { + cur += 6; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_type = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Family: ")) != NULL) { + cur += 8; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_family = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Manufacturer: ")) != NULL) { + cur += 14; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_manufacturer + = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Signature: ")) != NULL) { + cur += 11; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_signature + = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Version: ")) != NULL) { + cur += 9; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_version = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "External Clock: ")) != NULL) { + cur += 16; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_external_clock + = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Max Speed: ")) != NULL) { + cur += 11; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_max_speed + = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Status: ")) != NULL) { + cur += 8; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_status = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Serial Number: ")) != NULL) { + cur += 15; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_serial_number + = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Part Number: ")) != NULL) { + cur += 13; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((processor->processor_part_number + = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + + base += strlen("Processor Information"); + } + + return 0; + +no_memory: + return -1; +} + +static int +virSysinfoParseMemory(const char *base, virSysinfoDefPtr ret) +{ + const char *cur, *tmp_base; + char *eol; + virSysinfoMemoryDefPtr memory; + + while ((tmp_base = strstr(base, "Memory Device")) != NULL) { + base = tmp_base; + eol = NULL; + + if (VIR_EXPAND_N(ret->memory, ret->nmemory, 1) < 0) { + goto no_memory; + } + memory = &ret->memory[ret->nmemory - 1]; + + if ((cur = strstr(base, "Size: ")) != NULL) { + cur += 6; + eol = strchr(cur, '\n'); + if (STREQLEN(cur, "No Module Installed", eol - cur)) + goto next; + + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_size = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Form Factor: ")) != NULL) { + cur += 13; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_form_factor = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Locator: ")) != NULL) { + cur += 9; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_locator = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Bank Locator: ")) != NULL) { + cur += 14; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_bank_locator = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Type: ")) != NULL) { + cur += 6; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_type = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Type Detail: ")) != NULL) { + cur += 13; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_type_detail = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Speed: ")) != NULL) { + cur += 7; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_speed = strndup(cur, eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Manufacturer: ")) != NULL) { + cur += 14; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_manufacturer = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Serial Number: ")) != NULL) { + cur += 15; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_serial_number = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + if ((cur = strstr(base, "Part Number: ")) != NULL) { + cur += 13; + eol = strchr(cur, '\n'); + virSkipSpacesBackwards(cur, &eol); + if ((eol) && + ((memory->memory_part_number = strndup(cur, + eol - cur)) == NULL)) + goto no_memory; + } + + next: + base += strlen("Memory Device"); + } + + return 0; + +no_memory: + return -1; +} + +virSysinfoDefPtr +virSysinfoRead(void) { + char *path; + virSysinfoDefPtr ret = NULL; + char *outbuf = NULL; + virCommandPtr cmd; + + path = virFindFileInPath(SYSINFO_SMBIOS_DECODER); + if (path == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to find path for %s binary"), + SYSINFO_SMBIOS_DECODER); + return NULL; + } + + cmd = virCommandNewArgList(path, "-q", "-t", "0,1,4,17", NULL); + VIR_FREE(path); + virCommandSetOutputBuffer(cmd, &outbuf); + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + + if (VIR_ALLOC(ret) < 0) + goto no_memory; + + ret->type = VIR_SYSINFO_SMBIOS; + + if (virSysinfoParseBIOS(outbuf, ret) < 0) + goto no_memory; + + if (virSysinfoParseSystem(outbuf, ret) < 0) + goto no_memory; + + ret->nprocessor = 0; + ret->processor = NULL; + if (virSysinfoParseProcessor(outbuf, ret) < 0) + goto no_memory; + + ret->nmemory = 0; + ret->memory = NULL; + if (virSysinfoParseMemory(outbuf, ret) < 0) + goto no_memory; + +cleanup: + VIR_FREE(outbuf); + virCommandFree(cmd); + + return ret; + +no_memory: + virReportOOMError(); + + virSysinfoDefFree(ret); + ret = NULL; + goto cleanup; +} +#endif /* !WIN32 && x86 */ + +static void +virSysinfoBIOSFormat(virBufferPtr buf, virSysinfoDefPtr def) +{ + if (!def->bios_vendor && !def->bios_version && + !def->bios_date && !def->bios_release) + return; + + virBufferAddLit(buf, " <bios>\n"); + virBufferEscapeString(buf, " <entry name='vendor'>%s</entry>\n", + def->bios_vendor); + virBufferEscapeString(buf, " <entry name='version'>%s</entry>\n", + def->bios_version); + virBufferEscapeString(buf, " <entry name='date'>%s</entry>\n", + def->bios_date); + virBufferEscapeString(buf, " <entry name='release'>%s</entry>\n", + def->bios_release); + virBufferAddLit(buf, " </bios>\n"); +} + +static void +virSysinfoSystemFormat(virBufferPtr buf, virSysinfoDefPtr def) +{ + if (!def->system_manufacturer && !def->system_product && + !def->system_version && !def->system_serial && + !def->system_uuid && !def->system_sku && !def->system_family) + return; + + virBufferAddLit(buf, " <system>\n"); + virBufferEscapeString(buf, " <entry name='manufacturer'>%s</entry>\n", + def->system_manufacturer); + virBufferEscapeString(buf, " <entry name='product'>%s</entry>\n", + def->system_product); + virBufferEscapeString(buf, " <entry name='version'>%s</entry>\n", + def->system_version); + virBufferEscapeString(buf, " <entry name='serial'>%s</entry>\n", + def->system_serial); + virBufferEscapeString(buf, " <entry name='uuid'>%s</entry>\n", + def->system_uuid); + virBufferEscapeString(buf, " <entry name='sku'>%s</entry>\n", + def->system_sku); + virBufferEscapeString(buf, " <entry name='family'>%s</entry>\n", + def->system_family); + virBufferAddLit(buf, " </system>\n"); +} + +static void +virSysinfoProcessorFormat(virBufferPtr buf, virSysinfoDefPtr def) +{ + int i; + virSysinfoProcessorDefPtr processor; + + for (i = 0; i < def->nprocessor; i++) { + processor = &def->processor[i]; + + if (!processor->processor_socket_destination && + !processor->processor_type && + !processor->processor_family && + !processor->processor_manufacturer && + !processor->processor_signature && + !processor->processor_version && + !processor->processor_external_clock && + !processor->processor_max_speed && + !processor->processor_status && + !processor->processor_serial_number && + !processor->processor_part_number) + continue; + + virBufferAddLit(buf, " <processor>\n"); + virBufferAdjustIndent(buf, 4); + virBufferEscapeString(buf, + "<entry name='socket_destination'>%s</entry>\n", + processor->processor_socket_destination); + virBufferEscapeString(buf, "<entry name='type'>%s</entry>\n", + processor->processor_type); + virBufferEscapeString(buf, "<entry name='family'>%s</entry>\n", + processor->processor_family); + virBufferEscapeString(buf, "<entry name='manufacturer'>%s</entry>\n", + processor->processor_manufacturer); + virBufferEscapeString(buf, "<entry name='signature'>%s</entry>\n", + processor->processor_signature); + virBufferEscapeString(buf, "<entry name='version'>%s</entry>\n", + processor->processor_version); + virBufferEscapeString(buf, "<entry name='external_clock'>%s</entry>\n", + processor->processor_external_clock); + virBufferEscapeString(buf, "<entry name='max_speed'>%s</entry>\n", + processor->processor_max_speed); + virBufferEscapeString(buf, "<entry name='status'>%s</entry>\n", + processor->processor_status); + virBufferEscapeString(buf, "<entry name='serial_number'>%s</entry>\n", + processor->processor_serial_number); + virBufferEscapeString(buf, "<entry name='part_number'>%s</entry>\n", + processor->processor_part_number); + virBufferAdjustIndent(buf, -4); + virBufferAddLit(buf, " </processor>\n"); + } +} + +static void +virSysinfoMemoryFormat(virBufferPtr buf, virSysinfoDefPtr def) +{ + int i; + virSysinfoMemoryDefPtr memory; + + for (i = 0; i < def->nmemory; i++) { + memory = &def->memory[i]; + + if (!memory->memory_size && + !memory->memory_form_factor && + !memory->memory_locator && + !memory->memory_bank_locator && + !memory->memory_type && + !memory->memory_type_detail && + !memory->memory_speed && + !memory->memory_manufacturer && + !memory->memory_serial_number && + !memory->memory_part_number) + continue; + + virBufferAddLit(buf, " <memory_device>\n"); + virBufferEscapeString(buf, " <entry name='size'>%s</entry>\n", + memory->memory_size); + virBufferEscapeString(buf, + " <entry name='form_factor'>%s</entry>\n", + memory->memory_form_factor); + virBufferEscapeString(buf, " <entry name='locator'>%s</entry>\n", + memory->memory_locator); + virBufferEscapeString(buf, + " <entry name='bank_locator'>%s</entry>\n", + memory->memory_bank_locator); + virBufferEscapeString(buf, " <entry name='type'>%s</entry>\n", + memory->memory_type); + virBufferEscapeString(buf, + " <entry name='type_detail'>%s</entry>\n", + memory->memory_type_detail); + virBufferEscapeString(buf, " <entry name='speed'>%s</entry>\n", + memory->memory_speed); + virBufferEscapeString(buf, + " <entry name='manufacturer'>%s</entry>\n", + memory->memory_manufacturer); + virBufferEscapeString(buf, + " <entry name='serial_number'>%s</entry>\n", + memory->memory_serial_number); + virBufferEscapeString(buf, + " <entry name='part_number'>%s</entry>\n", + memory->memory_part_number); + virBufferAddLit(buf, " </memory_device>\n"); + } +} + +/** + * virSysinfoFormat: + * @buf: buffer to append output to (may use auto-indentation) + * @def: structure to convert to xml string + * + * Returns 0 on success, -1 on failure after generating an error message. + */ +int +virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) +{ + const char *type = virSysinfoTypeToString(def->type); + + if (!type) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected sysinfo type model %d"), + def->type); + virBufferFreeAndReset(buf); + return -1; + } + + virBufferAsprintf(buf, "<sysinfo type='%s'>\n", type); + + virSysinfoBIOSFormat(buf, def); + virSysinfoSystemFormat(buf, def); + virSysinfoProcessorFormat(buf, def); + virSysinfoMemoryFormat(buf, def); + + virBufferAddLit(buf, "</sysinfo>\n"); + + if (virBufferError(buf)) { + virReportOOMError(); + return -1; + } + + return 0; +} + +bool virSysinfoIsEqual(virSysinfoDefPtr src, + virSysinfoDefPtr dst) +{ + bool identical = false; + + if (!src && !dst) + return true; + + if ((src && !dst) || (!src && dst)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Target sysinfo does not match source")); + goto cleanup; + } + + if (src->type != dst->type) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Target sysinfo %s does not match source %s"), + virSysinfoTypeToString(dst->type), + virSysinfoTypeToString(src->type)); + goto cleanup; + } + +#define CHECK_FIELD(name, desc) \ + do { \ + if (STRNEQ_NULLABLE(src->name, dst->name)) { \ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \ + _("Target sysinfo %s %s does not match source %s"), \ + desc, NULLSTR(src->name), NULLSTR(dst->name)); \ + } \ + } while (0) + + CHECK_FIELD(bios_vendor, "BIOS vendor"); + CHECK_FIELD(bios_version, "BIOS version"); + CHECK_FIELD(bios_date, "BIOS date"); + CHECK_FIELD(bios_release, "BIOS release"); + + CHECK_FIELD(system_manufacturer, "system vendor"); + CHECK_FIELD(system_product, "system product"); + CHECK_FIELD(system_version, "system version"); + CHECK_FIELD(system_serial, "system serial"); + CHECK_FIELD(system_uuid, "system uuid"); + CHECK_FIELD(system_sku, "system sku"); + CHECK_FIELD(system_family, "system family"); + +#undef CHECK_FIELD + + identical = true; + +cleanup: + return identical; +} diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h new file mode 100644 index 0000000..0b1f000 --- /dev/null +++ b/src/util/virsysinfo.h @@ -0,0 +1,105 @@ +/* + * sysinfo.h: structure and entry points for sysinfo support + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2010 Daniel Veillard + * + * 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + +#ifndef __VIR_SYSINFOS_H__ +# define __VIR_SYSINFOS_H__ + +# include "internal.h" +# include "util.h" +# include "virbuffer.h" + +enum virSysinfoType { + VIR_SYSINFO_SMBIOS, + + VIR_SYSINFO_LAST +}; + +typedef struct _virSysinfoProcessorDef virSysinfoProcessorDef; +typedef virSysinfoProcessorDef *virSysinfoProcessorDefPtr; +struct _virSysinfoProcessorDef { + char *processor_socket_destination; + char *processor_type; + char *processor_family; + char *processor_manufacturer; + char *processor_signature; + char *processor_version; + char *processor_external_clock; + char *processor_max_speed; + char *processor_status; + char *processor_serial_number; + char *processor_part_number; +}; + +typedef struct _virSysinfoMemoryDef virSysinfoMemoryDef; +typedef virSysinfoMemoryDef *virSysinfoMemoryDefPtr; +struct _virSysinfoMemoryDef { + char *memory_size; + char *memory_form_factor; + char *memory_locator; + char *memory_bank_locator; + char *memory_type; + char *memory_type_detail; + char *memory_speed; + char *memory_manufacturer; + char *memory_serial_number; + char *memory_part_number; +}; + +typedef struct _virSysinfoDef virSysinfoDef; +typedef virSysinfoDef *virSysinfoDefPtr; +struct _virSysinfoDef { + int type; + + char *bios_vendor; + char *bios_version; + char *bios_date; + char *bios_release; + + char *system_manufacturer; + char *system_product; + char *system_version; + char *system_serial; + char *system_uuid; + char *system_sku; + char *system_family; + + size_t nprocessor; + virSysinfoProcessorDefPtr processor; + + size_t nmemory; + virSysinfoMemoryDefPtr memory; +}; + +virSysinfoDefPtr virSysinfoRead(void); + +void virSysinfoDefFree(virSysinfoDefPtr def); + +int virSysinfoFormat(virBufferPtr buf, virSysinfoDefPtr def) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +bool virSysinfoIsEqual(virSysinfoDefPtr src, + virSysinfoDefPtr dst); + +VIR_ENUM_DECL(virSysinfo) + +#endif /* __VIR_SYSINFOS_H__ */ -- 1.7.11.7

On 12/17/2012 03:57 PM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
--- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/conf/domain_conf.h | 2 +- src/qemu/qemu_driver.c | 2 +- src/util/sysinfo.c | 1045 ------------------------------------------------ src/util/sysinfo.h | 105 ----- src/util/virsysinfo.c | 1045 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virsysinfo.h | 105 +++++ 8 files changed, 1154 insertions(+), 1154 deletions(-) delete mode 100644 src/util/sysinfo.c delete mode 100644 src/util/sysinfo.h create mode 100644 src/util/virsysinfo.c create mode 100644 src/util/virsysinfo.h
Since I have patches for sysinfo pending, could they be considered before the rename (at least 1/3 and 2/3, I could resend the tests with the new names later)? -- Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On Mon, Dec 17, 2012 at 04:45:04PM +0100, Viktor Mihajlovski wrote:
On 12/17/2012 03:57 PM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
--- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/conf/domain_conf.h | 2 +- src/qemu/qemu_driver.c | 2 +- src/util/sysinfo.c | 1045 ------------------------------------------------ src/util/sysinfo.h | 105 ----- src/util/virsysinfo.c | 1045 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virsysinfo.h | 105 +++++ 8 files changed, 1154 insertions(+), 1154 deletions(-) delete mode 100644 src/util/sysinfo.c delete mode 100644 src/util/sysinfo.h create mode 100644 src/util/virsysinfo.c create mode 100644 src/util/virsysinfo.h
Since I have patches for sysinfo pending, could they be considered before the rename (at least 1/3 and 2/3, I could resend the tests with the new names later)?
Sure, I'll look at them now. FWIW, git rebase usually copes with renamed files without trouble, so this rename shouldn't be as painful as it might appear Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

From: "Daniel P. Berrange" <berrange@redhat.com> --- src/Makefile.am | 2 +- src/nwfilter/nwfilter_dhcpsnoop.c | 2 +- src/qemu/qemu_conf.h | 2 +- src/qemu/qemu_driver.c | 2 +- src/rpc/virnetserver.c | 2 +- src/util/threadpool.c | 371 -------------------------------------- src/util/threadpool.h | 53 ------ src/util/virthreadpool.c | 371 ++++++++++++++++++++++++++++++++++++++ src/util/virthreadpool.h | 53 ++++++ 9 files changed, 429 insertions(+), 429 deletions(-) delete mode 100644 src/util/threadpool.c delete mode 100644 src/util/threadpool.h create mode 100644 src/util/virthreadpool.c create mode 100644 src/util/virthreadpool.h diff --git a/src/Makefile.am b/src/Makefile.am index 376c543..e74a3a3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,7 +56,6 @@ UTIL_SOURCES = \ util/threads.c util/threads.h \ util/threads-pthread.h \ util/threads-win32.h \ - util/threadpool.c util/threadpool.h \ util/uuid.c util/uuid.h \ util/util.c util/util.h \ util/viralloc.c util/viralloc.h \ @@ -86,6 +85,7 @@ UTIL_SOURCES = \ util/virstatslinux.c util/virstatslinux.h \ util/virstoragefile.c util/virstoragefile.h \ util/virsysinfo.c util/virsysinfo.h \ + util/virthreadpool.c util/virthreadpool.h \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c index a798e95..c1ab622 100644 --- a/src/nwfilter/nwfilter_dhcpsnoop.c +++ b/src/nwfilter/nwfilter_dhcpsnoop.c @@ -65,7 +65,7 @@ #include "virnetdev.h" #include "virfile.h" #include "viratomic.h" -#include "threadpool.h" +#include "virthreadpool.h" #include "configmake.h" #include "virtime.h" diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index f928c29..0d4816e 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -41,7 +41,7 @@ # include "driver.h" # include "virbitmap.h" # include "vircommand.h" -# include "threadpool.h" +# include "virthreadpool.h" # include "locking/lock_manager.h" # include "qemu_capabilities.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0038d95..170f15d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -85,7 +85,7 @@ #include "virfile.h" #include "fdstream.h" #include "configmake.h" -#include "threadpool.h" +#include "virthreadpool.h" #include "locking/lock_manager.h" #include "locking/domain_lock.h" #include "virkeycode.h" diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 67cd4b5..26ceb0c 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -32,7 +32,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "threads.h" -#include "threadpool.h" +#include "virthreadpool.h" #include "util.h" #include "virfile.h" #include "virnetservermdns.h" diff --git a/src/util/threadpool.c b/src/util/threadpool.c deleted file mode 100644 index 9d3d5d2..0000000 --- a/src/util/threadpool.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * threadpool.c: a generic thread pool implementation - * - * Copyright (C) 2010 Hu Tao - * Copyright (C) 2010 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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Hu Tao <hutao@cn.fujitsu.com> - * Daniel P. Berrange <berrange@redhat.com> - */ - -#include <config.h> - -#include "threadpool.h" -#include "viralloc.h" -#include "threads.h" -#include "virterror_internal.h" - -#define VIR_FROM_THIS VIR_FROM_NONE - -typedef struct _virThreadPoolJob virThreadPoolJob; -typedef virThreadPoolJob *virThreadPoolJobPtr; - -struct _virThreadPoolJob { - virThreadPoolJobPtr prev; - virThreadPoolJobPtr next; - unsigned int priority; - - void *data; -}; - -typedef struct _virThreadPoolJobList virThreadPoolJobList; -typedef virThreadPoolJobList *virThreadPoolJobListPtr; - -struct _virThreadPoolJobList { - virThreadPoolJobPtr head; - virThreadPoolJobPtr tail; - virThreadPoolJobPtr firstPrio; -}; - - -struct _virThreadPool { - bool quit; - - virThreadPoolJobFunc jobFunc; - void *jobOpaque; - virThreadPoolJobList jobList; - size_t jobQueueDepth; - - virMutex mutex; - virCond cond; - virCond quit_cond; - - size_t maxWorkers; - size_t minWorkers; - size_t freeWorkers; - size_t nWorkers; - virThreadPtr workers; - - size_t nPrioWorkers; - virThreadPtr prioWorkers; - virCond prioCond; -}; - -struct virThreadPoolWorkerData { - virThreadPoolPtr pool; - virCondPtr cond; - bool priority; -}; - -static void virThreadPoolWorker(void *opaque) -{ - struct virThreadPoolWorkerData *data = opaque; - virThreadPoolPtr pool = data->pool; - virCondPtr cond = data->cond; - bool priority = data->priority; - virThreadPoolJobPtr job = NULL; - - VIR_FREE(data); - - virMutexLock(&pool->mutex); - - while (1) { - while (!pool->quit && - ((!priority && !pool->jobList.head) || - (priority && !pool->jobList.firstPrio))) { - if (!priority) - pool->freeWorkers++; - if (virCondWait(cond, &pool->mutex) < 0) { - if (!priority) - pool->freeWorkers--; - goto out; - } - if (!priority) - pool->freeWorkers--; - } - - if (pool->quit) - break; - - if (priority) { - job = pool->jobList.firstPrio; - } else { - job = pool->jobList.head; - } - - if (job == pool->jobList.firstPrio) { - virThreadPoolJobPtr tmp = job->next; - while (tmp) { - if (tmp->priority) { - break; - } - tmp = tmp->next; - } - pool->jobList.firstPrio = tmp; - } - - if (job->prev) - job->prev->next = job->next; - else - pool->jobList.head = job->next; - if (job->next) - job->next->prev = job->prev; - else - pool->jobList.tail = job->prev; - - pool->jobQueueDepth--; - - virMutexUnlock(&pool->mutex); - (pool->jobFunc)(job->data, pool->jobOpaque); - VIR_FREE(job); - virMutexLock(&pool->mutex); - } - -out: - if (priority) - pool->nPrioWorkers--; - else - pool->nWorkers--; - if (pool->nWorkers == 0 && pool->nPrioWorkers==0) - virCondSignal(&pool->quit_cond); - virMutexUnlock(&pool->mutex); -} - -virThreadPoolPtr virThreadPoolNew(size_t minWorkers, - size_t maxWorkers, - size_t prioWorkers, - virThreadPoolJobFunc func, - void *opaque) -{ - virThreadPoolPtr pool; - size_t i; - struct virThreadPoolWorkerData *data = NULL; - - if (minWorkers > maxWorkers) - minWorkers = maxWorkers; - - if (VIR_ALLOC(pool) < 0) { - virReportOOMError(); - return NULL; - } - - pool->jobList.tail = pool->jobList.head = NULL; - - pool->jobFunc = func; - pool->jobOpaque = opaque; - - if (virMutexInit(&pool->mutex) < 0) - goto error; - if (virCondInit(&pool->cond) < 0) - goto error; - if (virCondInit(&pool->quit_cond) < 0) - goto error; - - if (VIR_ALLOC_N(pool->workers, minWorkers) < 0) - goto error; - - pool->minWorkers = minWorkers; - pool->maxWorkers = maxWorkers; - - for (i = 0; i < minWorkers; i++) { - if (VIR_ALLOC(data) < 0) { - virReportOOMError(); - goto error; - } - data->pool = pool; - data->cond = &pool->cond; - - if (virThreadCreate(&pool->workers[i], - true, - virThreadPoolWorker, - data) < 0) { - goto error; - } - pool->nWorkers++; - } - - if (prioWorkers) { - if (virCondInit(&pool->prioCond) < 0) - goto error; - if (VIR_ALLOC_N(pool->prioWorkers, prioWorkers) < 0) - goto error; - - for (i = 0; i < prioWorkers; i++) { - if (VIR_ALLOC(data) < 0) { - virReportOOMError(); - goto error; - } - data->pool = pool; - data->cond = &pool->prioCond; - data->priority = true; - - if (virThreadCreate(&pool->prioWorkers[i], - true, - virThreadPoolWorker, - data) < 0) { - goto error; - } - pool->nPrioWorkers++; - } - } - - return pool; - -error: - VIR_FREE(data); - virThreadPoolFree(pool); - return NULL; - -} - -void virThreadPoolFree(virThreadPoolPtr pool) -{ - virThreadPoolJobPtr job; - bool priority = false; - - if (!pool) - return; - - virMutexLock(&pool->mutex); - pool->quit = true; - if (pool->nWorkers > 0) - virCondBroadcast(&pool->cond); - if (pool->nPrioWorkers > 0) { - priority = true; - virCondBroadcast(&pool->prioCond); - } - - while (pool->nWorkers > 0 || pool->nPrioWorkers > 0) - ignore_value(virCondWait(&pool->quit_cond, &pool->mutex)); - - while ((job = pool->jobList.head)) { - pool->jobList.head = pool->jobList.head->next; - VIR_FREE(job); - } - - VIR_FREE(pool->workers); - virMutexUnlock(&pool->mutex); - virMutexDestroy(&pool->mutex); - ignore_value(virCondDestroy(&pool->quit_cond)); - ignore_value(virCondDestroy(&pool->cond)); - if (priority) { - VIR_FREE(pool->prioWorkers); - ignore_value(virCondDestroy(&pool->prioCond)); - } - VIR_FREE(pool); -} - - -size_t virThreadPoolGetMinWorkers(virThreadPoolPtr pool) -{ - return pool->minWorkers; -} - -size_t virThreadPoolGetMaxWorkers(virThreadPoolPtr pool) -{ - return pool->maxWorkers; -} - -size_t virThreadPoolGetPriorityWorkers(virThreadPoolPtr pool) -{ - return pool->nPrioWorkers; -} - -/* - * @priority - job priority - * Return: 0 on success, -1 otherwise - */ -int virThreadPoolSendJob(virThreadPoolPtr pool, - unsigned int priority, - void *jobData) -{ - virThreadPoolJobPtr job; - struct virThreadPoolWorkerData *data = NULL; - - virMutexLock(&pool->mutex); - if (pool->quit) - goto error; - - if (pool->freeWorkers - pool->jobQueueDepth <= 0 && - pool->nWorkers < pool->maxWorkers) { - if (VIR_EXPAND_N(pool->workers, pool->nWorkers, 1) < 0) { - virReportOOMError(); - goto error; - } - - if (VIR_ALLOC(data) < 0) { - pool->nWorkers--; - virReportOOMError(); - goto error; - } - - data->pool = pool; - data->cond = &pool->cond; - - if (virThreadCreate(&pool->workers[pool->nWorkers - 1], - true, - virThreadPoolWorker, - data) < 0) { - VIR_FREE(data); - pool->nWorkers--; - goto error; - } - } - - if (VIR_ALLOC(job) < 0) { - virReportOOMError(); - goto error; - } - - job->data = jobData; - job->priority = priority; - - job->prev = pool->jobList.tail; - if (pool->jobList.tail) - pool->jobList.tail->next = job; - pool->jobList.tail = job; - - if (!pool->jobList.head) - pool->jobList.head = job; - - if (priority && !pool->jobList.firstPrio) - pool->jobList.firstPrio = job; - - pool->jobQueueDepth++; - - virCondSignal(&pool->cond); - if (priority) - virCondSignal(&pool->prioCond); - - virMutexUnlock(&pool->mutex); - return 0; - -error: - virMutexUnlock(&pool->mutex); - return -1; -} diff --git a/src/util/threadpool.h b/src/util/threadpool.h deleted file mode 100644 index 4479647..0000000 --- a/src/util/threadpool.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * threadpool.h: a generic thread pool implementation - * - * Copyright (C) 2010 Hu Tao - * Copyright (C) 2010 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, see - * <http://www.gnu.org/licenses/>. - * - * Author: - * Hu Tao <hutao@cn.fujitsu.com> - * Daniel P. Berrange <berrange@redhat.com> - */ - -#ifndef __VIR_THREADPOOL_H__ -# define __VIR_THREADPOOL_H__ - -# include "internal.h" - -typedef struct _virThreadPool virThreadPool; -typedef virThreadPool *virThreadPoolPtr; - -typedef void (*virThreadPoolJobFunc)(void *jobdata, void *opaque); - -virThreadPoolPtr virThreadPoolNew(size_t minWorkers, - size_t maxWorkers, - size_t prioWorkers, - virThreadPoolJobFunc func, - void *opaque) ATTRIBUTE_NONNULL(4); - -size_t virThreadPoolGetMinWorkers(virThreadPoolPtr pool); -size_t virThreadPoolGetMaxWorkers(virThreadPoolPtr pool); -size_t virThreadPoolGetPriorityWorkers(virThreadPoolPtr pool); - -void virThreadPoolFree(virThreadPoolPtr pool); - -int virThreadPoolSendJob(virThreadPoolPtr pool, - unsigned int priority, - void *jobdata) ATTRIBUTE_NONNULL(1) - ATTRIBUTE_RETURN_CHECK; - -#endif diff --git a/src/util/virthreadpool.c b/src/util/virthreadpool.c new file mode 100644 index 0000000..c13b078 --- /dev/null +++ b/src/util/virthreadpool.c @@ -0,0 +1,371 @@ +/* + * threadpool.c: a generic thread pool implementation + * + * Copyright (C) 2010 Hu Tao + * Copyright (C) 2010 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Hu Tao <hutao@cn.fujitsu.com> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include "virthreadpool.h" +#include "viralloc.h" +#include "threads.h" +#include "virterror_internal.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +typedef struct _virThreadPoolJob virThreadPoolJob; +typedef virThreadPoolJob *virThreadPoolJobPtr; + +struct _virThreadPoolJob { + virThreadPoolJobPtr prev; + virThreadPoolJobPtr next; + unsigned int priority; + + void *data; +}; + +typedef struct _virThreadPoolJobList virThreadPoolJobList; +typedef virThreadPoolJobList *virThreadPoolJobListPtr; + +struct _virThreadPoolJobList { + virThreadPoolJobPtr head; + virThreadPoolJobPtr tail; + virThreadPoolJobPtr firstPrio; +}; + + +struct _virThreadPool { + bool quit; + + virThreadPoolJobFunc jobFunc; + void *jobOpaque; + virThreadPoolJobList jobList; + size_t jobQueueDepth; + + virMutex mutex; + virCond cond; + virCond quit_cond; + + size_t maxWorkers; + size_t minWorkers; + size_t freeWorkers; + size_t nWorkers; + virThreadPtr workers; + + size_t nPrioWorkers; + virThreadPtr prioWorkers; + virCond prioCond; +}; + +struct virThreadPoolWorkerData { + virThreadPoolPtr pool; + virCondPtr cond; + bool priority; +}; + +static void virThreadPoolWorker(void *opaque) +{ + struct virThreadPoolWorkerData *data = opaque; + virThreadPoolPtr pool = data->pool; + virCondPtr cond = data->cond; + bool priority = data->priority; + virThreadPoolJobPtr job = NULL; + + VIR_FREE(data); + + virMutexLock(&pool->mutex); + + while (1) { + while (!pool->quit && + ((!priority && !pool->jobList.head) || + (priority && !pool->jobList.firstPrio))) { + if (!priority) + pool->freeWorkers++; + if (virCondWait(cond, &pool->mutex) < 0) { + if (!priority) + pool->freeWorkers--; + goto out; + } + if (!priority) + pool->freeWorkers--; + } + + if (pool->quit) + break; + + if (priority) { + job = pool->jobList.firstPrio; + } else { + job = pool->jobList.head; + } + + if (job == pool->jobList.firstPrio) { + virThreadPoolJobPtr tmp = job->next; + while (tmp) { + if (tmp->priority) { + break; + } + tmp = tmp->next; + } + pool->jobList.firstPrio = tmp; + } + + if (job->prev) + job->prev->next = job->next; + else + pool->jobList.head = job->next; + if (job->next) + job->next->prev = job->prev; + else + pool->jobList.tail = job->prev; + + pool->jobQueueDepth--; + + virMutexUnlock(&pool->mutex); + (pool->jobFunc)(job->data, pool->jobOpaque); + VIR_FREE(job); + virMutexLock(&pool->mutex); + } + +out: + if (priority) + pool->nPrioWorkers--; + else + pool->nWorkers--; + if (pool->nWorkers == 0 && pool->nPrioWorkers==0) + virCondSignal(&pool->quit_cond); + virMutexUnlock(&pool->mutex); +} + +virThreadPoolPtr virThreadPoolNew(size_t minWorkers, + size_t maxWorkers, + size_t prioWorkers, + virThreadPoolJobFunc func, + void *opaque) +{ + virThreadPoolPtr pool; + size_t i; + struct virThreadPoolWorkerData *data = NULL; + + if (minWorkers > maxWorkers) + minWorkers = maxWorkers; + + if (VIR_ALLOC(pool) < 0) { + virReportOOMError(); + return NULL; + } + + pool->jobList.tail = pool->jobList.head = NULL; + + pool->jobFunc = func; + pool->jobOpaque = opaque; + + if (virMutexInit(&pool->mutex) < 0) + goto error; + if (virCondInit(&pool->cond) < 0) + goto error; + if (virCondInit(&pool->quit_cond) < 0) + goto error; + + if (VIR_ALLOC_N(pool->workers, minWorkers) < 0) + goto error; + + pool->minWorkers = minWorkers; + pool->maxWorkers = maxWorkers; + + for (i = 0; i < minWorkers; i++) { + if (VIR_ALLOC(data) < 0) { + virReportOOMError(); + goto error; + } + data->pool = pool; + data->cond = &pool->cond; + + if (virThreadCreate(&pool->workers[i], + true, + virThreadPoolWorker, + data) < 0) { + goto error; + } + pool->nWorkers++; + } + + if (prioWorkers) { + if (virCondInit(&pool->prioCond) < 0) + goto error; + if (VIR_ALLOC_N(pool->prioWorkers, prioWorkers) < 0) + goto error; + + for (i = 0; i < prioWorkers; i++) { + if (VIR_ALLOC(data) < 0) { + virReportOOMError(); + goto error; + } + data->pool = pool; + data->cond = &pool->prioCond; + data->priority = true; + + if (virThreadCreate(&pool->prioWorkers[i], + true, + virThreadPoolWorker, + data) < 0) { + goto error; + } + pool->nPrioWorkers++; + } + } + + return pool; + +error: + VIR_FREE(data); + virThreadPoolFree(pool); + return NULL; + +} + +void virThreadPoolFree(virThreadPoolPtr pool) +{ + virThreadPoolJobPtr job; + bool priority = false; + + if (!pool) + return; + + virMutexLock(&pool->mutex); + pool->quit = true; + if (pool->nWorkers > 0) + virCondBroadcast(&pool->cond); + if (pool->nPrioWorkers > 0) { + priority = true; + virCondBroadcast(&pool->prioCond); + } + + while (pool->nWorkers > 0 || pool->nPrioWorkers > 0) + ignore_value(virCondWait(&pool->quit_cond, &pool->mutex)); + + while ((job = pool->jobList.head)) { + pool->jobList.head = pool->jobList.head->next; + VIR_FREE(job); + } + + VIR_FREE(pool->workers); + virMutexUnlock(&pool->mutex); + virMutexDestroy(&pool->mutex); + ignore_value(virCondDestroy(&pool->quit_cond)); + ignore_value(virCondDestroy(&pool->cond)); + if (priority) { + VIR_FREE(pool->prioWorkers); + ignore_value(virCondDestroy(&pool->prioCond)); + } + VIR_FREE(pool); +} + + +size_t virThreadPoolGetMinWorkers(virThreadPoolPtr pool) +{ + return pool->minWorkers; +} + +size_t virThreadPoolGetMaxWorkers(virThreadPoolPtr pool) +{ + return pool->maxWorkers; +} + +size_t virThreadPoolGetPriorityWorkers(virThreadPoolPtr pool) +{ + return pool->nPrioWorkers; +} + +/* + * @priority - job priority + * Return: 0 on success, -1 otherwise + */ +int virThreadPoolSendJob(virThreadPoolPtr pool, + unsigned int priority, + void *jobData) +{ + virThreadPoolJobPtr job; + struct virThreadPoolWorkerData *data = NULL; + + virMutexLock(&pool->mutex); + if (pool->quit) + goto error; + + if (pool->freeWorkers - pool->jobQueueDepth <= 0 && + pool->nWorkers < pool->maxWorkers) { + if (VIR_EXPAND_N(pool->workers, pool->nWorkers, 1) < 0) { + virReportOOMError(); + goto error; + } + + if (VIR_ALLOC(data) < 0) { + pool->nWorkers--; + virReportOOMError(); + goto error; + } + + data->pool = pool; + data->cond = &pool->cond; + + if (virThreadCreate(&pool->workers[pool->nWorkers - 1], + true, + virThreadPoolWorker, + data) < 0) { + VIR_FREE(data); + pool->nWorkers--; + goto error; + } + } + + if (VIR_ALLOC(job) < 0) { + virReportOOMError(); + goto error; + } + + job->data = jobData; + job->priority = priority; + + job->prev = pool->jobList.tail; + if (pool->jobList.tail) + pool->jobList.tail->next = job; + pool->jobList.tail = job; + + if (!pool->jobList.head) + pool->jobList.head = job; + + if (priority && !pool->jobList.firstPrio) + pool->jobList.firstPrio = job; + + pool->jobQueueDepth++; + + virCondSignal(&pool->cond); + if (priority) + virCondSignal(&pool->prioCond); + + virMutexUnlock(&pool->mutex); + return 0; + +error: + virMutexUnlock(&pool->mutex); + return -1; +} diff --git a/src/util/virthreadpool.h b/src/util/virthreadpool.h new file mode 100644 index 0000000..4479647 --- /dev/null +++ b/src/util/virthreadpool.h @@ -0,0 +1,53 @@ +/* + * threadpool.h: a generic thread pool implementation + * + * Copyright (C) 2010 Hu Tao + * Copyright (C) 2010 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: + * Hu Tao <hutao@cn.fujitsu.com> + * Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_THREADPOOL_H__ +# define __VIR_THREADPOOL_H__ + +# include "internal.h" + +typedef struct _virThreadPool virThreadPool; +typedef virThreadPool *virThreadPoolPtr; + +typedef void (*virThreadPoolJobFunc)(void *jobdata, void *opaque); + +virThreadPoolPtr virThreadPoolNew(size_t minWorkers, + size_t maxWorkers, + size_t prioWorkers, + virThreadPoolJobFunc func, + void *opaque) ATTRIBUTE_NONNULL(4); + +size_t virThreadPoolGetMinWorkers(virThreadPoolPtr pool); +size_t virThreadPoolGetMaxWorkers(virThreadPoolPtr pool); +size_t virThreadPoolGetPriorityWorkers(virThreadPoolPtr pool); + +void virThreadPoolFree(virThreadPoolPtr pool); + +int virThreadPoolSendJob(virThreadPoolPtr pool, + unsigned int priority, + void *jobdata) ATTRIBUTE_NONNULL(1) + ATTRIBUTE_RETURN_CHECK; + +#endif -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- daemon/libvirtd.c | 1 - daemon/libvirtd.h | 2 +- src/Makefile.am | 8 +- src/conf/device_conf.h | 2 +- src/conf/domain_conf.h | 2 +- src/conf/interface_conf.h | 2 +- src/conf/network_conf.h | 2 +- src/conf/node_device_conf.h | 2 +- src/conf/storage_conf.h | 2 +- src/conf/virconsole.c | 2 +- src/datatypes.h | 2 +- src/libvirt.c | 2 +- src/locking/lock_daemon.h | 2 +- src/lxc/lxc_conf.h | 2 +- src/lxc/lxc_monitor.c | 2 +- src/nwfilter/nwfilter_learnipaddr.c | 2 +- src/openvz/openvz_conf.h | 2 +- src/parallels/parallels_utils.h | 2 +- src/qemu/qemu_conf.h | 2 +- src/qemu/qemu_domain.h | 2 +- src/rpc/virkeepalive.c | 2 +- src/rpc/virnetclient.c | 2 +- src/rpc/virnetclientprogram.c | 2 +- src/rpc/virnetclientstream.c | 2 +- src/rpc/virnetsaslcontext.c | 2 +- src/rpc/virnetserver.c | 2 +- src/rpc/virnetserverclient.c | 2 +- src/rpc/virnetserverprogram.c | 2 +- src/rpc/virnetserverservice.c | 2 +- src/rpc/virnetsocket.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/rpc/virnettlscontext.c | 2 +- src/secret/secret_driver.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.h | 2 +- src/util/iohelper.c | 2 +- src/util/threads-pthread.c | 263 ------------------------ src/util/threads-pthread.h | 49 ----- src/util/threads-win32.c | 392 ------------------------------------ src/util/threads-win32.h | 53 ----- src/util/threads.c | 34 ---- src/util/threads.h | 166 --------------- src/util/util.c | 2 +- src/util/virdbus.c | 2 +- src/util/virebtables.c | 2 +- src/util/vireventpoll.c | 2 +- src/util/viriptables.c | 2 +- src/util/virlockspace.c | 2 +- src/util/virlog.c | 2 +- src/util/virnetlink.c | 2 +- src/util/virnodesuspend.c | 2 +- src/util/virobject.c | 2 +- src/util/virrandom.c | 2 +- src/util/virterror.c | 2 +- src/util/virthread.c | 34 ++++ src/util/virthread.h | 166 +++++++++++++++ src/util/virthreadpool.c | 2 +- src/util/virthreadpthread.c | 263 ++++++++++++++++++++++++ src/util/virthreadpthread.h | 49 +++++ src/util/virthreadwin32.c | 392 ++++++++++++++++++++++++++++++++++++ src/util/virthreadwin32.h | 53 +++++ src/vmware/vmware_conf.h | 2 +- src/xen/xen_hypervisor.c | 2 +- tests/eventtest.c | 2 +- tests/nwfilterxml2xmltest.c | 2 +- tests/qemumonitorjsontest.c | 2 +- tests/qemumonitortestutils.c | 2 +- tests/testutils.c | 2 +- tests/viratomictest.c | 2 +- tools/console.c | 2 +- tools/virsh.c | 2 +- tools/virsh.h | 2 +- 72 files changed, 1019 insertions(+), 1020 deletions(-) delete mode 100644 src/util/threads-pthread.c delete mode 100644 src/util/threads-pthread.h delete mode 100644 src/util/threads-win32.c delete mode 100644 src/util/threads-win32.h delete mode 100644 src/util/threads.c delete mode 100644 src/util/threads.h create mode 100644 src/util/virthread.c create mode 100644 src/util/virthread.h create mode 100644 src/util/virthreadpthread.c create mode 100644 src/util/virthreadpthread.h create mode 100644 src/util/virthreadwin32.c create mode 100644 src/util/virthreadwin32.h diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 903f8c2..dc1d2c5 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -50,7 +50,6 @@ #include "virconf.h" #include "virnetlink.h" #include "virnetserver.h" -#include "threads.h" #include "remote.h" #include "remote_driver.h" #include "virhooks.h" diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index b04cc71..69a77ea 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -34,7 +34,7 @@ # include "remote_protocol.h" # include "qemu_protocol.h" # include "virlog.h" -# include "threads.h" +# include "virthread.h" # if HAVE_SASL # include "virnetsaslcontext.h" # endif diff --git a/src/Makefile.am b/src/Makefile.am index e74a3a3..d8d96f8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,9 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - 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/viralloc.c util/viralloc.h \ @@ -85,6 +82,9 @@ UTIL_SOURCES = \ util/virstatslinux.c util/virstatslinux.h \ util/virstoragefile.c util/virstoragefile.h \ util/virsysinfo.c util/virsysinfo.h \ + util/virthread.c util/virthread.h \ + util/virthreadpthread.h \ + util/virthreadwin32.h \ util/virthreadpool.c util/virthreadpool.h \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ @@ -125,7 +125,7 @@ $(srcdir)/util/virkeymaps.h: $(srcdir)/util/keymaps.csv \ $(srcdir)/util/virkeycode-mapgen.py $(AM_V_GEN)$(PYTHON) $(srcdir)/util/virkeycode-mapgen.py <$(srcdir)/util/keymaps.csv >$@ -EXTRA_DIST += util/threads-pthread.c util/threads-win32.c +EXTRA_DIST += util/virthreadpthread.c util/virthreadwin32.c # Internal generic driver infrastructure NODE_INFO_SOURCES = nodeinfo.h nodeinfo.c diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 09d6be9..c1bf096 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -29,7 +29,7 @@ # include "internal.h" # include "util.h" -# include "threads.h" +# include "virthread.h" # include "virbuffer.h" enum virDeviceAddressPciMulti { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 718c6a9..56aece2 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -33,7 +33,7 @@ # include "storage_encryption_conf.h" # include "cpu_conf.h" # include "util.h" -# include "threads.h" +# include "virthread.h" # include "virhash.h" # include "virsocketaddr.h" # include "nwfilter_params.h" diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h index 1749629..d6f98f1 100644 --- a/src/conf/interface_conf.h +++ b/src/conf/interface_conf.h @@ -30,7 +30,7 @@ # include "internal.h" # include "util.h" -# include "threads.h" +# include "virthread.h" /* There is currently 3 types of interfaces */ diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 4d70fe6..4c634ed 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -31,7 +31,7 @@ # include <libxml/xpath.h> # include "internal.h" -# include "threads.h" +# include "virthread.h" # include "virsocketaddr.h" # include "virnetdevbandwidth.h" # include "virnetdevvportprofile.h" diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index e394042..9860f67 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -27,7 +27,7 @@ # include "internal.h" # include "util.h" -# include "threads.h" +# include "virthread.h" # include <libxml/tree.h> diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 743b768..573c3db 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -27,7 +27,7 @@ # include "internal.h" # include "util.h" # include "storage_encryption_conf.h" -# include "threads.h" +# include "virthread.h" # include <libxml/tree.h> diff --git a/src/conf/virconsole.c b/src/conf/virconsole.c index 757573d..515c5fa 100644 --- a/src/conf/virconsole.c +++ b/src/conf/virconsole.c @@ -31,7 +31,7 @@ #include "virhash.h" #include "fdstream.h" #include "internal.h" -#include "threads.h" +#include "virthread.h" #include "viralloc.h" #include "virpidfile.h" #include "virlog.h" diff --git a/src/datatypes.h b/src/datatypes.h index 55f97ed..a1dfc1e 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -25,7 +25,7 @@ # include "internal.h" # include "driver.h" -# include "threads.h" +# include "virthread.h" # include "virobject.h" extern virClassPtr virConnectClass; diff --git a/src/libvirt.c b/src/libvirt.c index ed7dcae..5654d53 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -59,7 +59,7 @@ #include "vircommand.h" #include "virrandom.h" #include "viruri.h" -#include "threads.h" +#include "virthread.h" #ifdef WITH_TEST # include "test/test_driver.h" diff --git a/src/locking/lock_daemon.h b/src/locking/lock_daemon.h index 619f8f2..da62edc 100644 --- a/src/locking/lock_daemon.h +++ b/src/locking/lock_daemon.h @@ -24,7 +24,7 @@ # define __VIR_LOCK_DAEMON_H__ # include "virlockspace.h" -# include "threads.h" +# include "virthread.h" typedef struct _virLockDaemon virLockDaemon; typedef virLockDaemon *virLockDaemonPtr; diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index c02966f..b0b7711 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -31,7 +31,7 @@ # include "domain_conf.h" # include "domain_event.h" # include "capabilities.h" -# include "threads.h" +# include "virthread.h" # include "vircgroup.h" # include "security/security_manager.h" # include "configmake.h" diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c index 90637eb..b0da21f 100644 --- a/src/lxc/lxc_monitor.c +++ b/src/lxc/lxc_monitor.c @@ -29,7 +29,7 @@ #include "virterror_internal.h" #include "virlog.h" -#include "threads.h" +#include "virthread.h" #include "rpc/virnetclient.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c index 8c4bbcf..442cc83 100644 --- a/src/nwfilter/nwfilter_learnipaddr.c +++ b/src/nwfilter/nwfilter_learnipaddr.c @@ -47,7 +47,7 @@ #include "datatypes.h" #include "virnetdev.h" #include "virterror_internal.h" -#include "threads.h" +#include "virthread.h" #include "conf/nwfilter_params.h" #include "conf/domain_conf.h" #include "nwfilter_gentech_driver.h" diff --git a/src/openvz/openvz_conf.h b/src/openvz/openvz_conf.h index 3eb2b3e..c1007f0 100644 --- a/src/openvz/openvz_conf.h +++ b/src/openvz/openvz_conf.h @@ -31,7 +31,7 @@ # include "internal.h" # include "domain_conf.h" -# include "threads.h" +# include "virthread.h" /* OpenVZ commands - Replace with wrapper scripts later? */ diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index 7c31707..cf006e8 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -24,11 +24,11 @@ # define PARALLELS_UTILS_H # include "driver.h" -# include "util/threads.h" # include "conf/domain_conf.h" # include "conf/storage_conf.h" # include "conf/domain_event.h" # include "conf/network_conf.h" +# include "virthread.h" # include "virjson.h" # define parallelsParseError() \ diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index 0d4816e..1aa56cc 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -32,7 +32,7 @@ # include "network_conf.h" # include "domain_conf.h" # include "domain_event.h" -# include "threads.h" +# include "virthread.h" # include "security/security_manager.h" # include "vircgroup.h" # include "virpci.h" diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 11670b9..00648cf 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -24,7 +24,7 @@ #ifndef __QEMU_DOMAIN_H__ # define __QEMU_DOMAIN_H__ -# include "threads.h" +# include "virthread.h" # include "domain_conf.h" # include "snapshot_conf.h" # include "qemu_monitor.h" diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index 91af315..5c14e14 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -23,7 +23,7 @@ #include <config.h> #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "virfile.h" #include "virlog.h" #include "util.h" diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index b4fe4d9..85787f0 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -31,7 +31,7 @@ #include "virnetsocket.h" #include "virkeepalive.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "virfile.h" #include "virlog.h" #include "util.h" diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c index 7396971..00948e0 100644 --- a/src/rpc/virnetclientprogram.c +++ b/src/rpc/virnetclientprogram.c @@ -33,7 +33,7 @@ #include "virlog.h" #include "util.h" #include "virfile.h" -#include "threads.h" +#include "virthread.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c index 4877b0c..7e1f9c7 100644 --- a/src/rpc/virnetclientstream.c +++ b/src/rpc/virnetclientstream.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "threads.h" +#include "virthread.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c index adc4f1e..cd30f4d 100644 --- a/src/rpc/virnetsaslcontext.c +++ b/src/rpc/virnetsaslcontext.c @@ -27,7 +27,7 @@ #include "virterror_internal.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 26ceb0c..b48af5e 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -31,7 +31,7 @@ #include "virlog.h" #include "viralloc.h" #include "virterror_internal.h" -#include "threads.h" +#include "virthread.h" #include "virthreadpool.h" #include "util.h" #include "virfile.h" diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 7f028b8..f1eb69b 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -32,7 +32,7 @@ #include "virlog.h" #include "virterror_internal.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "virkeepalive.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c index 287282e..a8f875c 100644 --- a/src/rpc/virnetserverprogram.c +++ b/src/rpc/virnetserverprogram.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" -#include "threads.h" +#include "virthread.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c index 92b5cef..9992983 100644 --- a/src/rpc/virnetserverservice.c +++ b/src/rpc/virnetserverservice.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virterror_internal.h" -#include "threads.h" +#include "virthread.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 8c62a2a..442850a 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -46,7 +46,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" -#include "threads.h" +#include "virthread.h" #include "virprocess.h" #include "passfd.h" diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index 8a7d5f9..663b7cd 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -30,7 +30,7 @@ #include "viralloc.h" #include "virlog.h" #include "configmake.h" -#include "threads.h" +#include "virthread.h" #include "util.h" #include "virterror_internal.h" #include "virobject.h" diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index d9354e0..1ff40cf 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -34,7 +34,7 @@ #include "virterror_internal.h" #include "util.h" #include "virlog.h" -#include "threads.h" +#include "virthread.h" #include "configmake.h" #define DH_BITS 1024 diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index fb2024b..672ff54 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -36,7 +36,7 @@ #include "viralloc.h" #include "secret_conf.h" #include "secret_driver.h" -#include "threads.h" +#include "virthread.h" #include "util.h" #include "uuid.h" #include "virterror_internal.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 3abd289..185bb3b 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -47,7 +47,7 @@ #include "storage_conf.h" #include "node_device_conf.h" #include "xml.h" -#include "threads.h" +#include "virthread.h" #include "virlog.h" #include "virfile.h" #include "virtypedparam.h" diff --git a/src/uml/uml_conf.h b/src/uml/uml_conf.h index 09a0305..dfa168e 100644 --- a/src/uml/uml_conf.h +++ b/src/uml/uml_conf.h @@ -30,7 +30,7 @@ # include "domain_conf.h" # include "domain_event.h" # include "virterror_internal.h" -# include "threads.h" +# include "virthread.h" # include "vircommand.h" # include "virhash.h" diff --git a/src/util/iohelper.c b/src/util/iohelper.c index 1b16d5c..dcb5c14 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -34,7 +34,7 @@ #include <stdlib.h> #include "util.h" -#include "threads.h" +#include "virthread.h" #include "virfile.h" #include "viralloc.h" #include "virterror_internal.h" diff --git a/src/util/threads-pthread.c b/src/util/threads-pthread.c deleted file mode 100644 index 37d8902..0000000 --- a/src/util/threads-pthread.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * threads-pthread.c: basic thread synchronization primitives - * - * Copyright (C) 2009-2011 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <config.h> - -#include <unistd.h> -#include <inttypes.h> -#if HAVE_SYS_SYSCALL_H -# include <sys/syscall.h> -#endif - -#include "viralloc.h" - - -/* Nothing special required for pthreads */ -int virThreadInitialize(void) -{ - return 0; -} - -void virThreadOnExit(void) -{ -} - -int virOnce(virOnceControlPtr once, virOnceFunc init) -{ - return pthread_once(&once->once, init); -} - - -int virMutexInit(virMutexPtr m) -{ - int ret; - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); - ret = pthread_mutex_init(&m->lock, &attr); - pthread_mutexattr_destroy(&attr); - if (ret != 0) { - errno = ret; - return -1; - } - return 0; -} - -int virMutexInitRecursive(virMutexPtr m) -{ - int ret; - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - ret = pthread_mutex_init(&m->lock, &attr); - pthread_mutexattr_destroy(&attr); - if (ret != 0) { - errno = ret; - 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) -{ - int ret; - if ((ret = pthread_cond_init(&c->cond, NULL)) != 0) { - errno = ret; - return -1; - } - return 0; -} - -int virCondDestroy(virCondPtr c) -{ - int ret; - if ((ret = pthread_cond_destroy(&c->cond)) != 0) { - errno = ret; - return -1; - } - return 0; -} - -int virCondWait(virCondPtr c, virMutexPtr m) -{ - int ret; - if ((ret = pthread_cond_wait(&c->cond, &m->lock)) != 0) { - errno = ret; - return -1; - } - return 0; -} - -int virCondWaitUntil(virCondPtr c, virMutexPtr m, unsigned long long whenms) -{ - int ret; - struct timespec ts; - - ts.tv_sec = whenms / 1000; - ts.tv_nsec = (whenms % 1000) * 1000; - - if ((ret = pthread_cond_timedwait(&c->cond, &m->lock, &ts)) != 0) { - errno = ret; - return -1; - } - return 0; -} - -void virCondSignal(virCondPtr c) -{ - pthread_cond_signal(&c->cond); -} - -void virCondBroadcast(virCondPtr c) -{ - pthread_cond_broadcast(&c->cond); -} - -struct virThreadArgs { - virThreadFunc func; - void *opaque; -}; - -static void *virThreadHelper(void *data) -{ - struct virThreadArgs *args = data; - struct virThreadArgs local = *args; - - /* Free args early, rather than tying it up during the entire thread. */ - VIR_FREE(args); - local.func(local.opaque); - return NULL; -} - -int virThreadCreate(virThreadPtr thread, - bool joinable, - virThreadFunc func, - void *opaque) -{ - struct virThreadArgs *args; - pthread_attr_t attr; - int ret = -1; - int err; - - if ((err = pthread_attr_init(&attr)) != 0) - goto cleanup; - if (VIR_ALLOC(args) < 0) { - err = ENOMEM; - goto cleanup; - } - - args->func = func; - args->opaque = opaque; - - if (!joinable) - pthread_attr_setdetachstate(&attr, 1); - - err = pthread_create(&thread->thread, &attr, virThreadHelper, args); - if (err != 0) { - VIR_FREE(args); - goto cleanup; - } - /* New thread owns 'args' in success case, so don't free */ - - ret = 0; -cleanup: - pthread_attr_destroy(&attr); - if (ret < 0) - errno = err; - return ret; -} - -void virThreadSelf(virThreadPtr thread) -{ - thread->thread = pthread_self(); -} - -bool virThreadIsSelf(virThreadPtr thread) -{ - return pthread_equal(pthread_self(), thread->thread) ? true : false; -} - -/* For debugging use only; this result is not guaranteed unique on BSD - * systems when pthread_t is a 64-bit pointer. */ -int virThreadSelfID(void) -{ -#if defined(HAVE_SYS_SYSCALL_H) && defined(SYS_gettid) - pid_t tid; - tid = syscall(SYS_gettid); - return (int)tid; -#else - return (int)(intptr_t)(void *)pthread_self(); -#endif -} - -/* For debugging use only; this result is not guaranteed unique on BSD - * systems when pthread_t is a 64-bit pointer, nor does it match the - * thread id of virThreadSelfID on Linux. */ -int virThreadID(virThreadPtr thread) -{ - return (int)(uintptr_t)thread->thread; -} - -void virThreadJoin(virThreadPtr thread) -{ - pthread_join(thread->thread, NULL); -} - -int virThreadLocalInit(virThreadLocalPtr l, - virThreadLocalCleanup c) -{ - int ret; - if ((ret = pthread_key_create(&l->key, c)) != 0) { - errno = ret; - return -1; - } - return 0; -} - -void *virThreadLocalGet(virThreadLocalPtr l) -{ - return pthread_getspecific(l->key); -} - -int virThreadLocalSet(virThreadLocalPtr l, void *val) -{ - int err = pthread_setspecific(l->key, val); - if (err) { - errno = err; - return -1; - } - return 0; -} diff --git a/src/util/threads-pthread.h b/src/util/threads-pthread.h deleted file mode 100644 index ddaedb7..0000000 --- a/src/util/threads-pthread.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * threads.c: basic thread synchronization primitives - * - * Copyright (C) 2009, 2011 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "internal.h" - -#include <pthread.h> - -struct virMutex { - pthread_mutex_t lock; -}; - -struct virCond { - pthread_cond_t cond; -}; - -struct virThread { - pthread_t thread; -}; - -struct virThreadLocal { - pthread_key_t key; -}; - -struct virOnceControl { - pthread_once_t once; -}; - -#define VIR_ONCE_CONTROL_INITIALIZER \ -{ \ - .once = PTHREAD_ONCE_INIT \ -} diff --git a/src/util/threads-win32.c b/src/util/threads-win32.c deleted file mode 100644 index c9f16c1..0000000 --- a/src/util/threads-win32.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * threads-win32.c: basic thread synchronization primitives - * - * Copyright (C) 2009-2011 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <config.h> - -#include <process.h> - -#include "viralloc.h" - -struct virThreadLocalData { - DWORD key; - virThreadLocalCleanup cleanup; -}; -typedef struct virThreadLocalData virThreadLocalData; -typedef virThreadLocalData *virThreadLocalDataPtr; - -virMutex virThreadLocalLock; -unsigned int virThreadLocalCount = 0; -virThreadLocalDataPtr virThreadLocalList = NULL; -DWORD selfkey; - -virThreadLocal virCondEvent; - -void virCondEventCleanup(void *data); - -int virThreadInitialize(void) -{ - if (virMutexInit(&virThreadLocalLock) < 0) - return -1; - if (virThreadLocalInit(&virCondEvent, virCondEventCleanup) < 0) - return -1; - if ((selfkey = TlsAlloc()) == TLS_OUT_OF_INDEXES) - 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 virOnce(virOnceControlPtr once, virOnceFunc func) -{ - if (!once->complete) { - if (InterlockedIncrement(&once->init) == 1) { - /* We're the first thread. */ - func(); - once->complete = 1; - } else { - /* We're a later thread. Decrement the init counter back - * to avoid overflow, then yield until the first thread - * marks that the function is complete. It is rare that - * multiple threads will be waiting here, and since each - * thread is yielding except the first, we should get out - * soon enough. */ - InterlockedDecrement(&once->init); - while (!once->complete) - Sleep(0); - } - } - return 0; -} - -int virMutexInit(virMutexPtr m) -{ - return virMutexInitRecursive(m); -} - -int virMutexInitRecursive(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; - } - if (virThreadLocalSet(&virCondEvent, event) < 0) { - CloseHandle(event); - return -1; - } - } - - 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; -} - -int virCondWaitUntil(virCondPtr c ATTRIBUTE_UNUSED, - virMutexPtr m ATTRIBUTE_UNUSED, - unsigned long long whenms ATTRIBUTE_UNUSED) -{ - /* FIXME: this function is currently only used by the QEMU driver that - * is not compiled on Windows, so it's okay for now to just - * miss an implementation */ - return -1; -} - -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); -} - - -struct virThreadArgs { - virThreadFunc func; - void *opaque; -}; - -static void virThreadHelperDaemon(void *data) -{ - struct virThreadArgs *args = data; - virThread self; - HANDLE handle = GetCurrentThread(); - HANDLE process = GetCurrentProcess(); - - self.joinable = false; - DuplicateHandle(process, handle, process, - &self.thread, 0, FALSE, - DUPLICATE_SAME_ACCESS); - TlsSetValue(selfkey, &self); - - args->func(args->opaque); - - TlsSetValue(selfkey, NULL); - CloseHandle(self.thread); - - VIR_FREE(args); -} - -static unsigned int __stdcall virThreadHelperJoinable(void *data) -{ - struct virThreadArgs *args = data; - virThread self; - HANDLE handle = GetCurrentThread(); - HANDLE process = GetCurrentProcess(); - - self.joinable = true; - DuplicateHandle(process, handle, process, - &self.thread, 0, FALSE, - DUPLICATE_SAME_ACCESS); - TlsSetValue(selfkey, &self); - - args->func(args->opaque); - - TlsSetValue(selfkey, NULL); - CloseHandle(self.thread); - - VIR_FREE(args); - return 0; -} - -int virThreadCreate(virThreadPtr thread, - bool joinable, - virThreadFunc func, - void *opaque) -{ - struct virThreadArgs *args; - uintptr_t ret; - - if (VIR_ALLOC(args) < 0) - return -1; - - args->func = func; - args->opaque = opaque; - - thread->joinable = joinable; - if (joinable) { - ret = _beginthreadex(NULL, 0, - virThreadHelperJoinable, - args, 0, NULL); - if (ret == 0) - return -1; - } else { - ret = _beginthread(virThreadHelperDaemon, - 0, args); - if (ret == -1L) - return -1; - } - - thread->thread = (HANDLE)ret; - - return 0; -} - -void virThreadSelf(virThreadPtr thread) -{ - virThreadPtr self = TlsGetValue(selfkey); - - if (self == NULL) { - /* called on a thread not created by virThreadCreate, e.g. the main thread */ - thread->thread = 0; - thread->joinable = false; - } else { - thread->thread = self->thread; - thread->joinable = self->joinable; - } -} - -bool virThreadIsSelf(virThreadPtr thread) -{ - virThread self; - virThreadSelf(&self); - return self.thread == thread->thread ? true : false; -} - -/* For debugging use only; see comments in threads-pthread.c. */ -int virThreadSelfID(void) -{ - return (int)GetCurrentThreadId(); -} - -/* For debugging use only; see comments in threads-pthread.c. */ -int virThreadID(virThreadPtr thread) -{ - return (intptr_t)thread->thread; -} - - -void virThreadJoin(virThreadPtr thread) -{ - if (thread->joinable) { - WaitForSingleObject(thread->thread, INFINITE); - CloseHandle(thread->thread); - thread->thread = 0; - thread->joinable = false; - } -} - - -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); -} - -int virThreadLocalSet(virThreadLocalPtr l, void *val) -{ - return TlsSetValue(l->key, val) == 0 ? -1 : 0; -} diff --git a/src/util/threads-win32.h b/src/util/threads-win32.h deleted file mode 100644 index 07a1bf5..0000000 --- a/src/util/threads-win32.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * threads-win32.h basic thread synchronization primitives - * - * Copyright (C) 2009, 2011-2012 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include "internal.h" - -#ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -#endif -#include <windows.h> - -struct virMutex { - HANDLE lock; -}; - -struct virCond { - virMutex lock; - unsigned int nwaiters; - HANDLE *waiters; -}; - -struct virThread { - HANDLE thread; - bool joinable; -}; - -struct virThreadLocal { - DWORD key; -}; - -struct virOnceControl { - volatile long init; /* 0 at startup, > 0 if init has started */ - volatile long complete; /* 0 until first thread completes callback */ -}; - -#define VIR_ONCE_CONTROL_INITIALIZER { 0, 0 } diff --git a/src/util/threads.c b/src/util/threads.c deleted file mode 100644 index d0d5b83..0000000 --- a/src/util/threads.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * threads.c: basic thread synchronization primitives - * - * Copyright (C) 2009-2010 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#include <config.h> - -#include "threads.h" - -/* On mingw, we prefer native threading over the sometimes-broken - * pthreads-win32 library wrapper. */ -#ifdef WIN32 -# include "threads-win32.c" -#elif defined HAVE_PTHREAD_MUTEXATTR_INIT -# include "threads-pthread.c" -#else -# error "Either pthreads or Win32 threads are required" -#endif diff --git a/src/util/threads.h b/src/util/threads.h deleted file mode 100644 index 9761764..0000000 --- a/src/util/threads.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * threads.h: basic thread synchronization primitives - * - * Copyright (C) 2009-2011 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#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; - -typedef struct virThread virThread; -typedef virThread *virThreadPtr; - -typedef struct virOnceControl virOnceControl; -typedef virOnceControl *virOnceControlPtr; - -typedef void (*virOnceFunc)(void); - -int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK; -void virThreadOnExit(void); - -typedef void (*virThreadFunc)(void *opaque); - -int virThreadCreate(virThreadPtr thread, - bool joinable, - virThreadFunc func, - void *opaque) ATTRIBUTE_RETURN_CHECK; -void virThreadSelf(virThreadPtr thread); -bool virThreadIsSelf(virThreadPtr thread); -void virThreadJoin(virThreadPtr thread); - -/* These next two functions are for debugging only, since they are not - * guaranteed to give unique values for distinct threads on all - * architectures, nor are the two functions guaranteed to give the same - * value for the same thread. */ -int virThreadSelfID(void); -int virThreadID(virThreadPtr thread); - -/* Static initialization of mutexes is not possible, so we instead - * provide for guaranteed one-time initialization via a callback - * function. Usage: - * static virOnceControl once = VIR_ONCE_CONTROL_INITIALIZER; - * static void initializer(void) { ... } - * void myfunc() - * { - * if (virOnce(&once, initializer) < 0) - * goto error; - * ...now guaranteed that initializer has completed exactly once - * } - */ -int virOnce(virOnceControlPtr once, virOnceFunc init) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; - -int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK; -int virMutexInitRecursive(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; - -/* virCondWait, virCondWaitUntil: - * These functions can return without the associated predicate - * changing value. Therefore in nearly all cases they - * should be enclosed in a while loop that checks the predicate. - */ -int virCondWait(virCondPtr c, virMutexPtr m) ATTRIBUTE_RETURN_CHECK; -int virCondWaitUntil(virCondPtr c, virMutexPtr m, unsigned long long whenms) 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); -int virThreadLocalSet(virThreadLocalPtr l, void*) ATTRIBUTE_RETURN_CHECK; - -# ifdef WIN32 -# include "threads-win32.h" -# elif defined HAVE_PTHREAD_MUTEXATTR_INIT -# include "threads-pthread.h" -# else -# error "Either pthreads or Win32 threads are required" -# endif - - -/** - * VIR_ONCE_GLOBAL_INIT: - * classname: base classname - * - * This macro simplifies the setup of a one-time only - * global file initializer. - * - * Assuming a class called "virMyObject", and a method - * implemented like: - * - * int virMyObjectOnceInit(void) { - * ...do init tasks... - * } - * - * Then invoking the macro: - * - * VIR_ONCE_GLOBAL_INIT(virMyObject) - * - * Will create a method - * - * int virMyObjectInitialize(void); - * - * Which will ensure that 'virMyObjectOnceInit' is - * guaranteed to be invoked exactly once. - */ -# define VIR_ONCE_GLOBAL_INIT(classname) \ - static virOnceControl classname ## OnceControl = VIR_ONCE_CONTROL_INITIALIZER; \ - static virErrorPtr classname ## OnceError = NULL; \ - \ - static void classname ## Once(void) \ - { \ - if (classname ## OnceInit() < 0) \ - classname ## OnceError = virSaveLastError(); \ - } \ - \ - static int classname ## Initialize(void) \ - { \ - if (virOnce(&classname ## OnceControl, classname ## Once) < 0) \ - return -1; \ - \ - if (classname ## OnceError) { \ - virSetError(classname ## OnceError); \ - return -1; \ - } \ - \ - return 0; \ - } - -#endif diff --git a/src/util/util.c b/src/util/util.c index 5d32995..c7d4aa5 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -81,7 +81,7 @@ #include "util.h" #include "virstoragefile.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "verify.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/util/virdbus.c b/src/util/virdbus.c index 34c46b2..f45074c 100644 --- a/src/util/virdbus.c +++ b/src/util/virdbus.c @@ -25,7 +25,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "threads.h" +#include "virthread.h" #define VIR_FROM_THIS VIR_FROM_DBUS diff --git a/src/util/virebtables.c b/src/util/virebtables.c index 1beb085..edf4956 100644 --- a/src/util/virebtables.c +++ b/src/util/virebtables.c @@ -45,7 +45,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "threads.h" +#include "virthread.h" #if HAVE_FIREWALLD static char *firewall_cmd_path = NULL; diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index cf4dc41..1180fda 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -31,7 +31,7 @@ #include <unistd.h> #include <fcntl.h> -#include "threads.h" +#include "virthread.h" #include "virlog.h" #include "vireventpoll.h" #include "viralloc.h" diff --git a/src/util/viriptables.c b/src/util/viriptables.c index 178580d..eb8acf5 100644 --- a/src/util/viriptables.c +++ b/src/util/viriptables.c @@ -43,7 +43,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "threads.h" +#include "virthread.h" #if HAVE_FIREWALLD static char *firewall_cmd_path = NULL; diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c index 509b162..961e171 100644 --- a/src/util/virlockspace.c +++ b/src/util/virlockspace.c @@ -28,7 +28,7 @@ #include "util.h" #include "virfile.h" #include "virhash.h" -#include "threads.h" +#include "virthread.h" #include <fcntl.h> #include <unistd.h> diff --git a/src/util/virlog.c b/src/util/virlog.c index cb15a22..0c6c13a 100644 --- a/src/util/virlog.c +++ b/src/util/virlog.c @@ -45,7 +45,7 @@ #include "viralloc.h" #include "util.h" #include "virbuffer.h" -#include "threads.h" +#include "virthread.h" #include "virfile.h" #include "virtime.h" #include "intprops.h" diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index b132d9a..fdd4c0d 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -38,7 +38,7 @@ #include "virnetlink.h" #include "virlog.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "virmacaddr.h" #include "virterror_internal.h" diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c index 1528cf1..878be1d 100644 --- a/src/util/virnodesuspend.c +++ b/src/util/virnodesuspend.c @@ -23,7 +23,7 @@ #include "virnodesuspend.h" #include "vircommand.h" -#include "threads.h" +#include "virthread.h" #include "datatypes.h" #include "viralloc.h" diff --git a/src/util/virobject.c b/src/util/virobject.c index 5cdd2e8..aca6182 100644 --- a/src/util/virobject.c +++ b/src/util/virobject.c @@ -22,7 +22,7 @@ #include <config.h> #include "virobject.h" -#include "threads.h" +#include "virthread.h" #include "viralloc.h" #include "viratomic.h" #include "virterror_internal.h" diff --git a/src/util/virrandom.c b/src/util/virrandom.c index c24bf3b..1dd96cf 100644 --- a/src/util/virrandom.c +++ b/src/util/virrandom.c @@ -27,7 +27,7 @@ #include <strings.h> #include "virrandom.h" -#include "threads.h" +#include "virthread.h" #include "count-one-bits.h" #include "util.h" #include "virterror_internal.h" diff --git a/src/util/virterror.c b/src/util/virterror.c index ce2d837..6c773d3 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -31,7 +31,7 @@ #include "datatypes.h" #include "virlog.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "util.h" virThreadLocal virLastErr; diff --git a/src/util/virthread.c b/src/util/virthread.c new file mode 100644 index 0000000..a062fd6 --- /dev/null +++ b/src/util/virthread.c @@ -0,0 +1,34 @@ +/* + * threads.c: basic thread synchronization primitives + * + * Copyright (C) 2009-2010 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include "virthread.h" + +/* On mingw, we prefer native threading over the sometimes-broken + * pthreads-win32 library wrapper. */ +#ifdef WIN32 +# include "virthreadwin32.c" +#elif defined HAVE_PTHREAD_MUTEXATTR_INIT +# include "virthreadpthread.c" +#else +# error "Either pthreads or Win32 threads are required" +#endif diff --git a/src/util/virthread.h b/src/util/virthread.h new file mode 100644 index 0000000..90aa5ce --- /dev/null +++ b/src/util/virthread.h @@ -0,0 +1,166 @@ +/* + * threads.h: basic thread synchronization primitives + * + * Copyright (C) 2009-2011 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#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; + +typedef struct virThread virThread; +typedef virThread *virThreadPtr; + +typedef struct virOnceControl virOnceControl; +typedef virOnceControl *virOnceControlPtr; + +typedef void (*virOnceFunc)(void); + +int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK; +void virThreadOnExit(void); + +typedef void (*virThreadFunc)(void *opaque); + +int virThreadCreate(virThreadPtr thread, + bool joinable, + virThreadFunc func, + void *opaque) ATTRIBUTE_RETURN_CHECK; +void virThreadSelf(virThreadPtr thread); +bool virThreadIsSelf(virThreadPtr thread); +void virThreadJoin(virThreadPtr thread); + +/* These next two functions are for debugging only, since they are not + * guaranteed to give unique values for distinct threads on all + * architectures, nor are the two functions guaranteed to give the same + * value for the same thread. */ +int virThreadSelfID(void); +int virThreadID(virThreadPtr thread); + +/* Static initialization of mutexes is not possible, so we instead + * provide for guaranteed one-time initialization via a callback + * function. Usage: + * static virOnceControl once = VIR_ONCE_CONTROL_INITIALIZER; + * static void initializer(void) { ... } + * void myfunc() + * { + * if (virOnce(&once, initializer) < 0) + * goto error; + * ...now guaranteed that initializer has completed exactly once + * } + */ +int virOnce(virOnceControlPtr once, virOnceFunc init) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK; +int virMutexInitRecursive(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; + +/* virCondWait, virCondWaitUntil: + * These functions can return without the associated predicate + * changing value. Therefore in nearly all cases they + * should be enclosed in a while loop that checks the predicate. + */ +int virCondWait(virCondPtr c, virMutexPtr m) ATTRIBUTE_RETURN_CHECK; +int virCondWaitUntil(virCondPtr c, virMutexPtr m, unsigned long long whenms) 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); +int virThreadLocalSet(virThreadLocalPtr l, void*) ATTRIBUTE_RETURN_CHECK; + +# ifdef WIN32 +# include "virthreadwin32.h" +# elif defined HAVE_PTHREAD_MUTEXATTR_INIT +# include "virthreadpthread.h" +# else +# error "Either pthreads or Win32 threads are required" +# endif + + +/** + * VIR_ONCE_GLOBAL_INIT: + * classname: base classname + * + * This macro simplifies the setup of a one-time only + * global file initializer. + * + * Assuming a class called "virMyObject", and a method + * implemented like: + * + * int virMyObjectOnceInit(void) { + * ...do init tasks... + * } + * + * Then invoking the macro: + * + * VIR_ONCE_GLOBAL_INIT(virMyObject) + * + * Will create a method + * + * int virMyObjectInitialize(void); + * + * Which will ensure that 'virMyObjectOnceInit' is + * guaranteed to be invoked exactly once. + */ +# define VIR_ONCE_GLOBAL_INIT(classname) \ + static virOnceControl classname ## OnceControl = VIR_ONCE_CONTROL_INITIALIZER; \ + static virErrorPtr classname ## OnceError = NULL; \ + \ + static void classname ## Once(void) \ + { \ + if (classname ## OnceInit() < 0) \ + classname ## OnceError = virSaveLastError(); \ + } \ + \ + static int classname ## Initialize(void) \ + { \ + if (virOnce(&classname ## OnceControl, classname ## Once) < 0) \ + return -1; \ + \ + if (classname ## OnceError) { \ + virSetError(classname ## OnceError); \ + return -1; \ + } \ + \ + return 0; \ + } + +#endif diff --git a/src/util/virthreadpool.c b/src/util/virthreadpool.c index c13b078..307cefb 100644 --- a/src/util/virthreadpool.c +++ b/src/util/virthreadpool.c @@ -27,7 +27,7 @@ #include "virthreadpool.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virthreadpthread.c b/src/util/virthreadpthread.c new file mode 100644 index 0000000..37d8902 --- /dev/null +++ b/src/util/virthreadpthread.c @@ -0,0 +1,263 @@ +/* + * threads-pthread.c: basic thread synchronization primitives + * + * Copyright (C) 2009-2011 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <unistd.h> +#include <inttypes.h> +#if HAVE_SYS_SYSCALL_H +# include <sys/syscall.h> +#endif + +#include "viralloc.h" + + +/* Nothing special required for pthreads */ +int virThreadInitialize(void) +{ + return 0; +} + +void virThreadOnExit(void) +{ +} + +int virOnce(virOnceControlPtr once, virOnceFunc init) +{ + return pthread_once(&once->once, init); +} + + +int virMutexInit(virMutexPtr m) +{ + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); + ret = pthread_mutex_init(&m->lock, &attr); + pthread_mutexattr_destroy(&attr); + if (ret != 0) { + errno = ret; + return -1; + } + return 0; +} + +int virMutexInitRecursive(virMutexPtr m) +{ + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + ret = pthread_mutex_init(&m->lock, &attr); + pthread_mutexattr_destroy(&attr); + if (ret != 0) { + errno = ret; + 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) +{ + int ret; + if ((ret = pthread_cond_init(&c->cond, NULL)) != 0) { + errno = ret; + return -1; + } + return 0; +} + +int virCondDestroy(virCondPtr c) +{ + int ret; + if ((ret = pthread_cond_destroy(&c->cond)) != 0) { + errno = ret; + return -1; + } + return 0; +} + +int virCondWait(virCondPtr c, virMutexPtr m) +{ + int ret; + if ((ret = pthread_cond_wait(&c->cond, &m->lock)) != 0) { + errno = ret; + return -1; + } + return 0; +} + +int virCondWaitUntil(virCondPtr c, virMutexPtr m, unsigned long long whenms) +{ + int ret; + struct timespec ts; + + ts.tv_sec = whenms / 1000; + ts.tv_nsec = (whenms % 1000) * 1000; + + if ((ret = pthread_cond_timedwait(&c->cond, &m->lock, &ts)) != 0) { + errno = ret; + return -1; + } + return 0; +} + +void virCondSignal(virCondPtr c) +{ + pthread_cond_signal(&c->cond); +} + +void virCondBroadcast(virCondPtr c) +{ + pthread_cond_broadcast(&c->cond); +} + +struct virThreadArgs { + virThreadFunc func; + void *opaque; +}; + +static void *virThreadHelper(void *data) +{ + struct virThreadArgs *args = data; + struct virThreadArgs local = *args; + + /* Free args early, rather than tying it up during the entire thread. */ + VIR_FREE(args); + local.func(local.opaque); + return NULL; +} + +int virThreadCreate(virThreadPtr thread, + bool joinable, + virThreadFunc func, + void *opaque) +{ + struct virThreadArgs *args; + pthread_attr_t attr; + int ret = -1; + int err; + + if ((err = pthread_attr_init(&attr)) != 0) + goto cleanup; + if (VIR_ALLOC(args) < 0) { + err = ENOMEM; + goto cleanup; + } + + args->func = func; + args->opaque = opaque; + + if (!joinable) + pthread_attr_setdetachstate(&attr, 1); + + err = pthread_create(&thread->thread, &attr, virThreadHelper, args); + if (err != 0) { + VIR_FREE(args); + goto cleanup; + } + /* New thread owns 'args' in success case, so don't free */ + + ret = 0; +cleanup: + pthread_attr_destroy(&attr); + if (ret < 0) + errno = err; + return ret; +} + +void virThreadSelf(virThreadPtr thread) +{ + thread->thread = pthread_self(); +} + +bool virThreadIsSelf(virThreadPtr thread) +{ + return pthread_equal(pthread_self(), thread->thread) ? true : false; +} + +/* For debugging use only; this result is not guaranteed unique on BSD + * systems when pthread_t is a 64-bit pointer. */ +int virThreadSelfID(void) +{ +#if defined(HAVE_SYS_SYSCALL_H) && defined(SYS_gettid) + pid_t tid; + tid = syscall(SYS_gettid); + return (int)tid; +#else + return (int)(intptr_t)(void *)pthread_self(); +#endif +} + +/* For debugging use only; this result is not guaranteed unique on BSD + * systems when pthread_t is a 64-bit pointer, nor does it match the + * thread id of virThreadSelfID on Linux. */ +int virThreadID(virThreadPtr thread) +{ + return (int)(uintptr_t)thread->thread; +} + +void virThreadJoin(virThreadPtr thread) +{ + pthread_join(thread->thread, NULL); +} + +int virThreadLocalInit(virThreadLocalPtr l, + virThreadLocalCleanup c) +{ + int ret; + if ((ret = pthread_key_create(&l->key, c)) != 0) { + errno = ret; + return -1; + } + return 0; +} + +void *virThreadLocalGet(virThreadLocalPtr l) +{ + return pthread_getspecific(l->key); +} + +int virThreadLocalSet(virThreadLocalPtr l, void *val) +{ + int err = pthread_setspecific(l->key, val); + if (err) { + errno = err; + return -1; + } + return 0; +} diff --git a/src/util/virthreadpthread.h b/src/util/virthreadpthread.h new file mode 100644 index 0000000..ddaedb7 --- /dev/null +++ b/src/util/virthreadpthread.h @@ -0,0 +1,49 @@ +/* + * threads.c: basic thread synchronization primitives + * + * Copyright (C) 2009, 2011 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "internal.h" + +#include <pthread.h> + +struct virMutex { + pthread_mutex_t lock; +}; + +struct virCond { + pthread_cond_t cond; +}; + +struct virThread { + pthread_t thread; +}; + +struct virThreadLocal { + pthread_key_t key; +}; + +struct virOnceControl { + pthread_once_t once; +}; + +#define VIR_ONCE_CONTROL_INITIALIZER \ +{ \ + .once = PTHREAD_ONCE_INIT \ +} diff --git a/src/util/virthreadwin32.c b/src/util/virthreadwin32.c new file mode 100644 index 0000000..c9f16c1 --- /dev/null +++ b/src/util/virthreadwin32.c @@ -0,0 +1,392 @@ +/* + * threads-win32.c: basic thread synchronization primitives + * + * Copyright (C) 2009-2011 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include <process.h> + +#include "viralloc.h" + +struct virThreadLocalData { + DWORD key; + virThreadLocalCleanup cleanup; +}; +typedef struct virThreadLocalData virThreadLocalData; +typedef virThreadLocalData *virThreadLocalDataPtr; + +virMutex virThreadLocalLock; +unsigned int virThreadLocalCount = 0; +virThreadLocalDataPtr virThreadLocalList = NULL; +DWORD selfkey; + +virThreadLocal virCondEvent; + +void virCondEventCleanup(void *data); + +int virThreadInitialize(void) +{ + if (virMutexInit(&virThreadLocalLock) < 0) + return -1; + if (virThreadLocalInit(&virCondEvent, virCondEventCleanup) < 0) + return -1; + if ((selfkey = TlsAlloc()) == TLS_OUT_OF_INDEXES) + 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 virOnce(virOnceControlPtr once, virOnceFunc func) +{ + if (!once->complete) { + if (InterlockedIncrement(&once->init) == 1) { + /* We're the first thread. */ + func(); + once->complete = 1; + } else { + /* We're a later thread. Decrement the init counter back + * to avoid overflow, then yield until the first thread + * marks that the function is complete. It is rare that + * multiple threads will be waiting here, and since each + * thread is yielding except the first, we should get out + * soon enough. */ + InterlockedDecrement(&once->init); + while (!once->complete) + Sleep(0); + } + } + return 0; +} + +int virMutexInit(virMutexPtr m) +{ + return virMutexInitRecursive(m); +} + +int virMutexInitRecursive(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; + } + if (virThreadLocalSet(&virCondEvent, event) < 0) { + CloseHandle(event); + return -1; + } + } + + 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; +} + +int virCondWaitUntil(virCondPtr c ATTRIBUTE_UNUSED, + virMutexPtr m ATTRIBUTE_UNUSED, + unsigned long long whenms ATTRIBUTE_UNUSED) +{ + /* FIXME: this function is currently only used by the QEMU driver that + * is not compiled on Windows, so it's okay for now to just + * miss an implementation */ + return -1; +} + +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); +} + + +struct virThreadArgs { + virThreadFunc func; + void *opaque; +}; + +static void virThreadHelperDaemon(void *data) +{ + struct virThreadArgs *args = data; + virThread self; + HANDLE handle = GetCurrentThread(); + HANDLE process = GetCurrentProcess(); + + self.joinable = false; + DuplicateHandle(process, handle, process, + &self.thread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + TlsSetValue(selfkey, &self); + + args->func(args->opaque); + + TlsSetValue(selfkey, NULL); + CloseHandle(self.thread); + + VIR_FREE(args); +} + +static unsigned int __stdcall virThreadHelperJoinable(void *data) +{ + struct virThreadArgs *args = data; + virThread self; + HANDLE handle = GetCurrentThread(); + HANDLE process = GetCurrentProcess(); + + self.joinable = true; + DuplicateHandle(process, handle, process, + &self.thread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + TlsSetValue(selfkey, &self); + + args->func(args->opaque); + + TlsSetValue(selfkey, NULL); + CloseHandle(self.thread); + + VIR_FREE(args); + return 0; +} + +int virThreadCreate(virThreadPtr thread, + bool joinable, + virThreadFunc func, + void *opaque) +{ + struct virThreadArgs *args; + uintptr_t ret; + + if (VIR_ALLOC(args) < 0) + return -1; + + args->func = func; + args->opaque = opaque; + + thread->joinable = joinable; + if (joinable) { + ret = _beginthreadex(NULL, 0, + virThreadHelperJoinable, + args, 0, NULL); + if (ret == 0) + return -1; + } else { + ret = _beginthread(virThreadHelperDaemon, + 0, args); + if (ret == -1L) + return -1; + } + + thread->thread = (HANDLE)ret; + + return 0; +} + +void virThreadSelf(virThreadPtr thread) +{ + virThreadPtr self = TlsGetValue(selfkey); + + if (self == NULL) { + /* called on a thread not created by virThreadCreate, e.g. the main thread */ + thread->thread = 0; + thread->joinable = false; + } else { + thread->thread = self->thread; + thread->joinable = self->joinable; + } +} + +bool virThreadIsSelf(virThreadPtr thread) +{ + virThread self; + virThreadSelf(&self); + return self.thread == thread->thread ? true : false; +} + +/* For debugging use only; see comments in threads-pthread.c. */ +int virThreadSelfID(void) +{ + return (int)GetCurrentThreadId(); +} + +/* For debugging use only; see comments in threads-pthread.c. */ +int virThreadID(virThreadPtr thread) +{ + return (intptr_t)thread->thread; +} + + +void virThreadJoin(virThreadPtr thread) +{ + if (thread->joinable) { + WaitForSingleObject(thread->thread, INFINITE); + CloseHandle(thread->thread); + thread->thread = 0; + thread->joinable = false; + } +} + + +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); +} + +int virThreadLocalSet(virThreadLocalPtr l, void *val) +{ + return TlsSetValue(l->key, val) == 0 ? -1 : 0; +} diff --git a/src/util/virthreadwin32.h b/src/util/virthreadwin32.h new file mode 100644 index 0000000..07a1bf5 --- /dev/null +++ b/src/util/virthreadwin32.h @@ -0,0 +1,53 @@ +/* + * threads-win32.h basic thread synchronization primitives + * + * Copyright (C) 2009, 2011-2012 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "internal.h" + +#ifdef HAVE_WINSOCK2_H +# include <winsock2.h> +#endif +#include <windows.h> + +struct virMutex { + HANDLE lock; +}; + +struct virCond { + virMutex lock; + unsigned int nwaiters; + HANDLE *waiters; +}; + +struct virThread { + HANDLE thread; + bool joinable; +}; + +struct virThreadLocal { + DWORD key; +}; + +struct virOnceControl { + volatile long init; /* 0 at startup, > 0 if init has started */ + volatile long complete; /* 0 until first thread completes callback */ +}; + +#define VIR_ONCE_CONTROL_INITIALIZER { 0, 0 } diff --git a/src/vmware/vmware_conf.h b/src/vmware/vmware_conf.h index b7a35a3..22d5240 100644 --- a/src/vmware/vmware_conf.h +++ b/src/vmware/vmware_conf.h @@ -25,7 +25,7 @@ # include "internal.h" # include "domain_conf.h" -# include "threads.h" +# include "virthread.h" # define VIR_FROM_THIS VIR_FROM_VMWARE # define PROGRAM_SENTINAL ((char *)0x1) diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index b308605..5c8fe37 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -77,7 +77,7 @@ #include "virbuffer.h" #include "capabilities.h" #include "viralloc.h" -#include "threads.h" +#include "virthread.h" #include "virfile.h" #include "virnodesuspend.h" #include "virtypedparam.h" diff --git a/tests/eventtest.c b/tests/eventtest.c index cd36a2d..6d00ea8 100644 --- a/tests/eventtest.c +++ b/tests/eventtest.c @@ -28,7 +28,7 @@ #include "testutils.h" #include "internal.h" -#include "threads.h" +#include "virthread.h" #include "virlog.h" #include "util.h" #include "vireventpoll.h" diff --git a/tests/nwfilterxml2xmltest.c b/tests/nwfilterxml2xmltest.c index 224ca93..8c29a46 100644 --- a/tests/nwfilterxml2xmltest.c +++ b/tests/nwfilterxml2xmltest.c @@ -11,7 +11,7 @@ #include "internal.h" #include "testutils.h" #include "xml.h" -#include "threads.h" +#include "virthread.h" #include "nwfilter_params.h" #include "nwfilter_conf.h" #include "testutilsqemu.h" diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 264c140..e1b6c56 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -22,7 +22,7 @@ #include "testutils.h" #include "testutilsqemu.h" #include "qemumonitortestutils.h" -#include "threads.h" +#include "virthread.h" #include "virterror_internal.h" diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 1e3f0da..cc38803 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -26,7 +26,7 @@ #include "qemumonitortestutils.h" -#include "threads.h" +#include "virthread.h" #include "qemu/qemu_monitor.h" #include "rpc/virnetsocket.h" #include "viralloc.h" diff --git a/tests/testutils.c b/tests/testutils.c index 7bb88f0..c6b1d23 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -41,7 +41,7 @@ #include "internal.h" #include "viralloc.h" #include "util.h" -#include "threads.h" +#include "virthread.h" #include "virterror_internal.h" #include "virbuffer.h" #include "virlog.h" diff --git a/tests/viratomictest.c b/tests/viratomictest.c index 88f387b..1ed1707 100644 --- a/tests/viratomictest.c +++ b/tests/viratomictest.c @@ -26,7 +26,7 @@ #include "viratomic.h" #include "virrandom.h" -#include "threads.h" +#include "virthread.h" static int testTypes(const void *data ATTRIBUTE_UNUSED) diff --git a/tools/console.c b/tools/console.c index 1d21189..d031308 100644 --- a/tools/console.c +++ b/tools/console.c @@ -42,7 +42,7 @@ # include "util.h" # include "virfile.h" # include "viralloc.h" -# include "threads.h" +# include "virthread.h" # include "virterror_internal.h" /* diff --git a/tools/virsh.c b/tools/virsh.c index e894aff..91a9677 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -64,7 +64,7 @@ #include "libvirt/libvirt-qemu.h" #include "virfile.h" #include "configmake.h" -#include "threads.h" +#include "virthread.h" #include "vircommand.h" #include "virkeycode.h" #include "virnetdevbandwidth.h" diff --git a/tools/virsh.h b/tools/virsh.h index 6913ed1..6e6d3ee 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -35,7 +35,7 @@ # include "internal.h" # include "virterror_internal.h" -# include "threads.h" +# include "virthread.h" # include "virnetdevbandwidth.h" # define VSH_MAX_XML_FILE (10*1024*1024) -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- cfg.mk | 16 +- daemon/libvirtd.c | 2 +- daemon/remote.c | 2 +- po/POTFILES.in | 2 +- python/libvirt-override.c | 2 +- src/Makefile.am | 5 +- src/conf/capabilities.c | 2 +- src/conf/cpu_conf.c | 2 +- src/conf/cpu_conf.h | 2 +- src/conf/device_conf.c | 2 +- src/conf/device_conf.h | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 2 +- src/conf/interface_conf.c | 2 +- src/conf/interface_conf.h | 2 +- src/conf/netdev_bandwidth_conf.c | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 2 +- src/conf/node_device_conf.h | 2 +- src/conf/nwfilter_conf.h | 2 +- src/conf/secret_conf.c | 2 +- src/conf/secret_conf.h | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_conf.h | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/conf/storage_encryption_conf.h | 2 +- src/cpu/cpu_powerpc.c | 2 +- src/cpu/cpu_x86.c | 2 +- src/datatypes.c | 2 +- src/driver.c | 2 +- src/esx/esx_device_monitor.c | 2 +- src/esx/esx_driver.c | 2 +- src/esx/esx_interface_driver.c | 2 +- src/esx/esx_network_driver.c | 2 +- src/esx/esx_nwfilter_driver.c | 2 +- src/esx/esx_secret_driver.c | 2 +- src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/esx/esx_util.c | 2 +- src/esx/esx_vi.c | 2 +- src/esx/esx_vi_types.c | 2 +- src/fdstream.c | 2 +- src/hyperv/hyperv_device_monitor.c | 2 +- src/hyperv/hyperv_driver.c | 2 +- src/hyperv/hyperv_interface_driver.c | 2 +- src/hyperv/hyperv_network_driver.c | 2 +- src/hyperv/hyperv_nwfilter_driver.c | 2 +- src/hyperv/hyperv_secret_driver.c | 2 +- src/hyperv/hyperv_storage_driver.c | 2 +- src/hyperv/hyperv_util.c | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_daemon_dispatch.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_sanlock.c | 2 +- src/locking/lock_manager.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_controller.c | 4 +- src/lxc/lxc_driver.c | 2 +- src/lxc/lxc_fuse.h | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_driver.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/nodeinfo.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_bridge_filter.c | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_cgroup.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_process.c | 2 +- src/remote/remote_driver.c | 2 +- src/rpc/virkeepalive.c | 2 +- src/rpc/virnetclient.c | 2 +- src/rpc/virnetclientprogram.c | 2 +- src/rpc/virnetmessage.c | 2 +- src/rpc/virnetserver.c | 2 +- src/rpc/virnetsocket.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/rpc/virnettlscontext.c | 2 +- src/secret/secret_driver.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_selinux.c | 4 +- src/security/virt-aa-helper.c | 2 +- src/storage/parthelper.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_disk.c | 2 +- src/storage/storage_backend_iscsi.c | 2 +- src/storage/storage_backend_rbd.c | 2 +- src/storage/storage_backend_sheepdog.c | 2 +- src/storage/storage_driver.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/iohelper.c | 2 +- src/util/util.c | 3131 -------------------------------- src/util/util.h | 284 --- src/util/uuid.c | 2 +- src/util/viraudit.c | 2 +- src/util/virauth.c | 2 +- src/util/virauthconfig.c | 2 +- src/util/virbitmap.c | 2 +- src/util/vircgroup.c | 2 +- src/util/vircommand.c | 2 +- src/util/vircommand.h | 2 +- src/util/virconf.c | 2 +- src/util/virdnsmasq.c | 2 +- src/util/vireventpoll.c | 2 +- src/util/virhooks.c | 2 +- src/util/virhooks.h | 2 +- src/util/virinitctl.c | 2 +- src/util/virjson.c | 2 +- src/util/virkeycode.h | 2 +- src/util/virkeyfile.c | 2 +- src/util/virlockspace.c | 2 +- src/util/virlog.c | 2 +- src/util/virnetdevbridge.c | 2 +- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevopenvswitch.h | 2 +- src/util/virnetdevtap.c | 2 +- src/util/virnetdevvportprofile.h | 2 +- src/util/virpidfile.c | 2 +- src/util/virprocess.c | 2 +- src/util/virrandom.c | 2 +- src/util/virsexpr.c | 2 +- src/util/virsocketaddr.c | 2 +- src/util/virstatslinux.c | 2 +- src/util/virstoragefile.h | 2 +- src/util/virsysinfo.c | 2 +- src/util/virsysinfo.h | 2 +- src/util/virterror.c | 2 +- src/util/virtime.c | 2 +- src/util/virtypedparam.c | 2 +- src/util/viruri.c | 2 +- src/util/virusb.c | 2 +- src/util/virutil.c | 3131 ++++++++++++++++++++++++++++++++ src/util/virutil.h | 284 +++ src/util/xml.c | 2 +- src/vbox/vbox_MSCOMGlue.c | 2 +- src/vbox/vbox_XPCOMCGlue.c | 2 +- src/vbox/vbox_driver.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/xen/block_stats.c | 2 +- src/xen/xen_driver.c | 2 +- src/xen/xen_hypervisor.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xm_internal.c | 2 +- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 2 +- tests/commandhelper.c | 2 +- tests/commandtest.c | 2 +- tests/esxutilstest.c | 2 +- tests/eventtest.c | 2 +- tests/libvirtdconftest.c | 2 +- tests/nodeinfotest.c | 2 +- tests/openvzutilstest.c | 2 +- tests/qemumonitortest.c | 2 +- tests/qemumonitortestutils.c | 2 +- tests/securityselinuxtest.c | 2 +- tests/testutils.c | 2 +- tests/utiltest.c | 2 +- tests/virauthconfigtest.c | 2 +- tests/virbuftest.c | 2 +- tests/virdrivermoduletest.c | 2 +- tests/virhashtest.c | 2 +- tests/virkeyfiletest.c | 2 +- tests/virlockspacetest.c | 2 +- tests/virnetmessagetest.c | 2 +- tests/virnetsockettest.c | 2 +- tests/virnettlscontexttest.c | 2 +- tests/virshtest.c | 2 +- tests/virstringtest.c | 2 +- tests/virtimetest.c | 2 +- tests/viruritest.c | 2 +- tools/console.c | 2 +- tools/virsh-domain.c | 2 +- tools/virsh-host.c | 2 +- tools/virsh-interface.c | 2 +- tools/virsh-network.c | 2 +- tools/virsh-nodedev.c | 2 +- tools/virsh-nwfilter.c | 2 +- tools/virsh-pool.c | 2 +- tools/virsh-secret.c | 2 +- tools/virsh-snapshot.c | 2 +- tools/virsh-volume.c | 2 +- tools/virsh.c | 2 +- tools/virt-host-validate-common.c | 2 +- 194 files changed, 3616 insertions(+), 3615 deletions(-) delete mode 100644 src/util/util.c delete mode 100644 src/util/util.h create mode 100644 src/util/virutil.c create mode 100644 src/util/virutil.h diff --git a/cfg.mk b/cfg.mk index 0a66797..a269f77 100644 --- a/cfg.mk +++ b/cfg.mk @@ -745,7 +745,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco # List all syntax-check exemptions: exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$ -_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon +_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|virutil)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon exclude_file_name_regexp--sc_avoid_write = \ ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$ @@ -764,13 +764,13 @@ exclude_file_name_regexp--sc_po_check = ^(docs/|src/rpc/gendispatch\.pl$$) exclude_file_name_regexp--sc_prohibit_VIR_ERR_NO_MEMORY = \ ^(include/libvirt/virterror\.h|daemon/dispatch\.c|src/util/virterror\.c)$$ -exclude_file_name_regexp--sc_prohibit_access_xok = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_access_xok = ^src/util/virutil\.c$$ exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \ ^python/(libvirt-(qemu-)?override|typewrappers)\.c$$ exclude_file_name_regexp--sc_prohibit_asprintf = \ - ^(bootstrap.conf$$|src/util/util\.c$$|examples/domain-events/events-c/event-test\.c$$) + ^(bootstrap.conf$$|src/util/virutil\.c$$|examples/domain-events/events-c/event-test\.c$$) exclude_file_name_regexp--sc_prohibit_close = \ (\.p[yl]$$|^docs/|^(src/util/virfile\.c|src/libvirt\.c)$$) @@ -782,10 +782,10 @@ _src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon) exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$) -exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/virutil\.c$$ exclude_file_name_regexp--sc_prohibit_internal_functions = \ - ^src/(util/(viralloc|util|virfile)\.[hc]|esx/esx_vi\.c)$$ + ^src/(util/(viralloc|virutil|virfile)\.[hc]|esx/esx_vi\.c)$$ exclude_file_name_regexp--sc_prohibit_newline_at_end_of_diagnostic = \ ^src/rpc/gendispatch\.pl$$ @@ -797,14 +797,14 @@ exclude_file_name_regexp--sc_prohibit_raw_allocation = \ ^(src/util/viralloc\.[ch]|examples/.*)$$ exclude_file_name_regexp--sc_prohibit_readlink = \ - ^src/(util/util|lxc/lxc_container)\.c$$ + ^src/(util/virutil|lxc/lxc_container)\.c$$ -exclude_file_name_regexp--sc_prohibit_setuid = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_setuid = ^src/util/virutil\.c$$ exclude_file_name_regexp--sc_prohibit_sprintf = \ ^(docs/hacking\.html\.in)|(examples/systemtap/.*stp)|(src/dtrace2systemtap\.pl)|(src/rpc/gensystemtap\.pl)$$ -exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/virutil\.c$$ exclude_file_name_regexp--sc_prohibit_strtol = \ ^src/(util/virsexpr|(vbox|xen|xenxs)/.*)\.c$$ diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index dc1d2c5..edc899e 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -43,7 +43,7 @@ #include "libvirtd.h" #include "libvirtd-config.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "remote_driver.h" #include "viralloc.h" diff --git a/daemon/remote.c b/daemon/remote.c index eb75281..0b5a3db 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -35,7 +35,7 @@ #include "datatypes.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "stream.h" #include "uuid.h" #include "libvirt/libvirt-qemu.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index c17c63c..8a24fd4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/util.c src/util/viraudit.c src/util/virauth.c src/util/virauthconfig.c @@ -180,6 +179,7 @@ src/util/virtime.c src/util/virtypedparam.c src/util/viruri.c src/util/virusb.c +src/util/virutil.c src/util/xml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 644f34d..91e82c6 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virtypedparam.h" #include "ignore-value.h" -#include "util.h" +#include "virutil.h" #ifndef __CYGWIN__ extern void initlibvirtmod(void); diff --git a/src/Makefile.am b/src/Makefile.am index d8d96f8..1303edd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,7 +54,6 @@ augeastest_DATA = # helper APIs for various purposes UTIL_SOURCES = \ util/uuid.c util/uuid.h \ - util/util.c util/util.h \ util/viralloc.c util/viralloc.h \ util/viratomic.h util/viratomic.c \ util/viraudit.c util/viraudit.h \ @@ -114,7 +113,9 @@ UTIL_SOURCES = \ util/virstring.h util/virstring.c \ util/virtime.h util/virtime.c \ util/virusb.c util/virusb.h \ - util/viruri.h util/viruri.c + util/viruri.h util/viruri.c \ + util/virutil.c util/virutil.h \ + $(NULL) EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \ $(srcdir)/util/virkeycode-mapgen.py diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 9ac18e2..e46a594 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -28,7 +28,7 @@ #include "capabilities.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "cpu_conf.h" #include "virterror_internal.h" diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 23941c5..95c6ca1 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -25,7 +25,7 @@ #include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "cpu_conf.h" #include "domain_conf.h" diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 357057d..7bec912 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -24,7 +24,7 @@ #ifndef __VIR_CPU_CONF_H__ # define __VIR_CPU_CONF_H__ -# include "util.h" +# include "virutil.h" # include "virbuffer.h" # include "xml.h" # include "virbitmap.h" diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index c3ca2d6..4efafc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -26,7 +26,7 @@ #include "viralloc.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "device_conf.h" diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index c1bf096..52e4ac5 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -28,7 +28,7 @@ # include <libxml/xpath.h> # include "internal.h" -# include "util.h" +# include "virutil.h" # include "virthread.h" # include "virbuffer.h" diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b3c3557..ab1fe2a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -38,7 +38,7 @@ #include "verify.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "virlog.h" #include "nwfilter_conf.h" diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 56aece2..df6e376 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -32,7 +32,7 @@ # include "capabilities.h" # include "storage_encryption_conf.h" # include "cpu_conf.h" -# include "util.h" +# include "virutil.h" # include "virthread.h" # include "virhash.h" # include "virsocketaddr.h" diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index 046a8a1..e4b088a 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -30,7 +30,7 @@ #include "viralloc.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_INTERFACE diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h index d6f98f1..e636c35 100644 --- a/src/conf/interface_conf.h +++ b/src/conf/interface_conf.h @@ -29,7 +29,7 @@ # include <libxml/xpath.h> # include "internal.h" -# include "util.h" +# include "virutil.h" # include "virthread.h" /* There is currently 3 types of interfaces */ diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c index 35f067c..e64aeff 100644 --- a/src/conf/netdev_bandwidth_conf.c +++ b/src/conf/netdev_bandwidth_conf.c @@ -24,7 +24,7 @@ #include "netdev_bandwidth_conf.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "domain_conf.h" diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 1932851..42f3593 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -40,7 +40,7 @@ #include "viralloc.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "c-ctype.h" #include "virfile.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 045f05d..12819c8 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -33,7 +33,7 @@ #include "node_device_conf.h" #include "viralloc.h" #include "xml.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "uuid.h" #include "virpci.h" diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 9860f67..12c36d8 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -26,7 +26,7 @@ # define __VIR_NODE_DEVICE_CONF_H__ # include "internal.h" -# include "util.h" +# include "virutil.h" # include "virthread.h" # include <libxml/tree.h> diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h index d597064..2ca44b3 100644 --- a/src/conf/nwfilter_conf.h +++ b/src/conf/nwfilter_conf.h @@ -28,7 +28,7 @@ # include "internal.h" -# include "util.h" +# include "virutil.h" # include "virhash.h" # include "xml.h" # include "virbuffer.h" diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index 5188c7a..a65cf92 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "secret_conf.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "uuid.h" diff --git a/src/conf/secret_conf.h b/src/conf/secret_conf.h index 2064286..6079d5b 100644 --- a/src/conf/secret_conf.h +++ b/src/conf/secret_conf.h @@ -24,7 +24,7 @@ # define __VIR_SECRET_CONF_H__ # include "internal.h" -# include "util.h" +# include "virutil.h" VIR_ENUM_DECL(virSecretUsageType) diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 5c40e97..810d2bf 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -42,7 +42,7 @@ #include "secret_conf.h" #include "snapshot_conf.h" #include "virstoragefile.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "virfile.h" #include "virterror_internal.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 5cd2393..38bb471 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -41,7 +41,7 @@ #include "xml.h" #include "uuid.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 573c3db..ad16eca 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -25,7 +25,7 @@ # define __VIR_STORAGE_CONF_H__ # include "internal.h" -# include "util.h" +# include "virutil.h" # include "storage_encryption_conf.h" # include "virthread.h" diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 8d3ceac..139c37c 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "storage_conf.h" #include "storage_encryption_conf.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "virterror_internal.h" #include "uuid.h" diff --git a/src/conf/storage_encryption_conf.h b/src/conf/storage_encryption_conf.h index 40a8497..57ab1a0 100644 --- a/src/conf/storage_encryption_conf.h +++ b/src/conf/storage_encryption_conf.h @@ -25,7 +25,7 @@ # include "internal.h" # include "virbuffer.h" -# include "util.h" +# include "virutil.h" # include <libxml/tree.h> diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 6b6c325..40a2d88 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -28,7 +28,7 @@ #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "cpu.h" #include "cpu_map.h" diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 93ee111..b932b93 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -27,7 +27,7 @@ #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "cpu.h" #include "cpu_map.h" #include "cpu_x86.h" diff --git a/src/datatypes.c b/src/datatypes.c index 0907c7d..07aefcc 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -27,7 +27,7 @@ #include "virlog.h" #include "viralloc.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/driver.c b/src/driver.c index 23dc329..0a5fe05 100644 --- a/src/driver.c +++ b/src/driver.c @@ -27,7 +27,7 @@ #include "driver.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "configmake.h" #define DEFAULT_DRIVER_DIR LIBDIR "/libvirt/connection-driver" diff --git a/src/esx/esx_device_monitor.c b/src/esx/esx_device_monitor.c index 854fc38..7cc6ac0 100644 --- a/src/esx/esx_device_monitor.c +++ b/src/esx/esx_device_monitor.c @@ -25,7 +25,7 @@ #include <config.h> #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 0fe9a67..2c0297c 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -28,7 +28,7 @@ #include "domain_conf.h" #include "snapshot_conf.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index fea67ab..524886f 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -25,7 +25,7 @@ #include <config.h> #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index fec7e72..0fc2603 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -26,7 +26,7 @@ #include "md5.h" #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_nwfilter_driver.c b/src/esx/esx_nwfilter_driver.c index 7a05a5a..ecee0fb 100644 --- a/src/esx/esx_nwfilter_driver.c +++ b/src/esx/esx_nwfilter_driver.c @@ -25,7 +25,7 @@ #include <config.h> #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_secret_driver.c b/src/esx/esx_secret_driver.c index 2969b19..722d3f7 100644 --- a/src/esx/esx_secret_driver.c +++ b/src/esx/esx_secret_driver.c @@ -24,7 +24,7 @@ #include <config.h> #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 5ad885a..3c3ab7d 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -28,7 +28,7 @@ #include "internal.h" #include "md5.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index 4886fc3..c57e070 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -31,7 +31,7 @@ #include "internal.h" #include "md5.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index bcda9df..9b2e576 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -28,7 +28,7 @@ #include "internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 37b6e0f..2cc8002 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -29,7 +29,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "vmx.h" #include "xml.h" diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index b93223d..d1f91ff 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -31,7 +31,7 @@ #include "datatypes.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "esx_vi.h" #include "esx_vi_types.h" diff --git a/src/fdstream.c b/src/fdstream.c index 39e92b8..f7f101e 100644 --- a/src/fdstream.c +++ b/src/fdstream.c @@ -37,7 +37,7 @@ #include "datatypes.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "configmake.h" diff --git a/src/hyperv/hyperv_device_monitor.c b/src/hyperv/hyperv_device_monitor.c index d6edb76..10d559f 100644 --- a/src/hyperv/hyperv_device_monitor.c +++ b/src/hyperv/hyperv_device_monitor.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 749c7f0..d777bd8 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -27,7 +27,7 @@ #include "datatypes.h" #include "domain_conf.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c index 43c7dd7..af37de3 100644 --- a/src/hyperv/hyperv_interface_driver.c +++ b/src/hyperv/hyperv_interface_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index 06b051b..cafc956 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c index 7452b7a..46c57b7 100644 --- a/src/hyperv/hyperv_nwfilter_driver.c +++ b/src/hyperv/hyperv_nwfilter_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c index 04a6ada..ea8fa7e 100644 --- a/src/hyperv/hyperv_secret_driver.c +++ b/src/hyperv/hyperv_secret_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c index b2817a2..7549801 100644 --- a/src/hyperv/hyperv_storage_driver.c +++ b/src/hyperv/hyperv_storage_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c index 016d415..69a57c6 100644 --- a/src/hyperv/hyperv_util.c +++ b/src/hyperv/hyperv_util.c @@ -24,7 +24,7 @@ #include "internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 69e7283..f4afdce 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -29,7 +29,7 @@ #include "datatypes.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "virbuffer.h" #include "hyperv_private.h" diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index 3d90c57..df9923e 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -33,7 +33,7 @@ #include "lock_daemon.h" #include "lock_daemon_config.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c index 78c9726..def7c2f 100644 --- a/src/locking/lock_daemon_dispatch.c +++ b/src/locking/lock_daemon_dispatch.c @@ -24,7 +24,7 @@ #include "rpc/virnetserver.h" #include "rpc/virnetserverclient.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "lock_daemon.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index cee530d..547db85 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -26,7 +26,7 @@ #include "viralloc.h" #include "virlog.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virterror_internal.h" #include "rpc/virnetclient.h" diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index e520444..511543a 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -40,7 +40,7 @@ #include "virlog.h" #include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "md5.h" #include "virconf.h" diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c index f938b04..d73e184 100644 --- a/src/locking/lock_manager.c +++ b/src/locking/lock_manager.c @@ -25,7 +25,7 @@ #include "lock_driver_nop.h" #include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "uuid.h" diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index f3c6e19..050a4c1 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -56,7 +56,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "lxc_container.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virnetdevveth.h" #include "uuid.h" diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 6b6ec82..a8e99f2 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -54,7 +54,7 @@ #include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "lxc_conf.h" #include "lxc_container.h" @@ -64,7 +64,7 @@ #include "virnetdev.h" #include "virnetdevveth.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virpidfile.h" #include "vircommand.h" diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 57c1767..e513b76 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -44,7 +44,7 @@ #include "lxc_driver.h" #include "lxc_process.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virnetdevbridge.h" #include "virnetdevveth.h" #include "nodeinfo.h" diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h index 9878017..93964a4 100644 --- a/src/lxc/lxc_fuse.h +++ b/src/lxc/lxc_fuse.h @@ -32,7 +32,7 @@ # endif # include "lxc_conf.h" -# include "util.h" +# include "virutil.h" # include "viralloc.h" struct virLXCMeminfo { diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 2db9197..dbbd49c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -52,7 +52,7 @@ #include "driver.h" #include "virbuffer.h" #include "virpidfile.h" -#include "util.h" +#include "virutil.h" #include "vircommand.h" #include "viralloc.h" #include "uuid.h" diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index d914816..6cc1837 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -37,7 +37,7 @@ #include "node_device_conf.h" #include "node_device_hal.h" #include "node_device_driver.h" -#include "util.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_NODEDEV diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 7289a72..d350955 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -35,7 +35,7 @@ #include "virlog.h" #include "viralloc.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "virpci.h" diff --git a/src/nodeinfo.c b/src/nodeinfo.c index b14e63b..65f4431 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -42,7 +42,7 @@ #include "viralloc.h" #include "nodeinfo.h" #include "physmem.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" #include "count-one-bits.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 6e0f6eb..b0c9c5f 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -49,7 +49,7 @@ #include "uuid.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "nodeinfo.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index a35a6b1..a407193 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -50,7 +50,7 @@ #include "openvz_driver.h" #include "openvz_util.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "openvz_conf.h" #include "nodeinfo.h" #include "viralloc.h" diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 07c1463..87d098e 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -44,7 +44,7 @@ #include "datatypes.h" #include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "vircommand.h" #include "configmake.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index ad56686..25b96b4 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -45,7 +45,7 @@ #include "internal.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "datatypes.h" #include "virbuffer.h" #include "viralloc.h" diff --git a/src/qemu/qemu_bridge_filter.c b/src/qemu/qemu_bridge_filter.c index 08a9f1a..6d84f47 100644 --- a/src/qemu/qemu_bridge_filter.c +++ b/src/qemu/qemu_bridge_filter.c @@ -25,7 +25,7 @@ #include "virebtables.h" #include "qemu_conf.h" #include "qemu_driver.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 46f8540..7a27183 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index b47fb78..9db7ad9 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -30,7 +30,7 @@ #include "virlog.h" #include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "domain_audit.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 464288f..23ccffe 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "uuid.h" #include "c-ctype.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index d6bc1fc..be88d77 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -43,7 +43,7 @@ #include "uuid.h" #include "virbuffer.h" #include "virconf.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "datatypes.h" #include "xml.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 170f15d..15b773b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -63,7 +63,7 @@ #include "virlog.h" #include "datatypes.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "nodeinfo.h" #include "virstatslinux.h" #include "capabilities.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index a77beb6..1e83e3c 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -39,7 +39,7 @@ #include "virlog.h" #include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "datatypes.h" #include "fdstream.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 794596b..d4eaa9e 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -57,7 +57,7 @@ #include "virhooks.h" #include "virfile.h" #include "virpidfile.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "nodeinfo.h" #include "domain_audit.h" diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 2edf6e6..ac7dc87 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -39,7 +39,7 @@ #include "remote_protocol.h" #include "qemu_protocol.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "vircommand.h" #include "intprops.h" diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index 5c14e14..18be350 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -26,7 +26,7 @@ #include "virthread.h" #include "virfile.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virnetsocket.h" #include "virkeepaliveprotocol.h" diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 85787f0..9347f0b 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -34,7 +34,7 @@ #include "virthread.h" #include "virfile.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c index 00948e0..eff4a4c 100644 --- a/src/rpc/virnetclientprogram.c +++ b/src/rpc/virnetclientprogram.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virthread.h" diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c index f273811..b2da65b 100644 --- a/src/rpc/virnetmessage.c +++ b/src/rpc/virnetmessage.c @@ -28,7 +28,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" -#include "util.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index b48af5e..47a6293 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virthread.h" #include "virthreadpool.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virnetservermdns.h" #include "virdbus.h" diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 442850a..a959c30 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -41,7 +41,7 @@ #include "c-ctype.h" #include "virnetsocket.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index 663b7cd..ad8bd48 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -31,7 +31,7 @@ #include "virlog.h" #include "configmake.h" #include "virthread.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virobject.h" diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 1ff40cf..b01de8c 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -32,7 +32,7 @@ #include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virthread.h" #include "configmake.h" diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 672ff54..8dfd921 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -37,7 +37,7 @@ #include "secret_conf.h" #include "secret_driver.h" #include "virthread.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "virterror_internal.h" #include "virfile.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index d28189f..4027cdf 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -38,7 +38,7 @@ #include "internal.h" #include "security_apparmor.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index f9752ef..3104f42 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -25,7 +25,7 @@ #include "security_dac.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "virpci.h" diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 8918257..ccba258 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -34,7 +34,7 @@ #include "security_driver.h" #include "security_selinux.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "virpci.h" @@ -43,7 +43,7 @@ #include "virfile.h" #include "virhash.h" #include "virrandom.h" -#include "util.h" +#include "virutil.h" #include "virconf.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 4945f7c..5cfa3ff 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -41,7 +41,7 @@ #include "internal.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircommand.h" diff --git a/src/storage/parthelper.c b/src/storage/parthelper.c index 5417ced..83f8279 100644 --- a/src/storage/parthelper.c +++ b/src/storage/parthelper.c @@ -41,7 +41,7 @@ #include <unistd.h> #include <locale.h> -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "configmake.h" diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 9b98dbb..29272f1 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -47,7 +47,7 @@ #include "datatypes.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "internal.h" #include "secret_conf.h" diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c index 8759b3a..aceb82b 100644 --- a/src/storage/storage_backend_disk.c +++ b/src/storage/storage_backend_disk.c @@ -29,7 +29,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "storage_backend_disk.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircommand.h" #include "configmake.h" diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index ecb8f8e..e91c4b1 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -37,7 +37,7 @@ #include "virterror_internal.h" #include "storage_backend_scsi.h" #include "storage_backend_iscsi.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index e1f07ab..ffa3234 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -25,7 +25,7 @@ #include "virterror_internal.h" #include "storage_backend_rbd.h" #include "storage_conf.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "base64.h" diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c index d3b9d87..1046ac9 100644 --- a/src/storage/storage_backend_sheepdog.c +++ b/src/storage/storage_backend_sheepdog.c @@ -30,7 +30,7 @@ #include "storage_backend_sheepdog.h" #include "storage_conf.h" #include "vircommand.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index aebf8bb..d93617c 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -39,7 +39,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "driver.h" -#include "util.h" +#include "virutil.h" #include "storage_driver.h" #include "storage_conf.h" #include "viralloc.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 185bb3b..da76367 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -36,7 +36,7 @@ #include "datatypes.h" #include "test_driver.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "capabilities.h" #include "viralloc.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 6da311b..b2057e8 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -39,7 +39,7 @@ #include "uuid.h" #include "virbuffer.h" #include "virconf.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "nodeinfo.h" #include "virlog.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index b20998f..05fb7f2 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -47,7 +47,7 @@ #include "uml_driver.h" #include "uml_conf.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "nodeinfo.h" #include "virstatslinux.h" #include "capabilities.h" diff --git a/src/util/iohelper.c b/src/util/iohelper.c index dcb5c14..40b04f9 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -33,7 +33,7 @@ #include <stdio.h> #include <stdlib.h> -#include "util.h" +#include "virutil.h" #include "virthread.h" #include "virfile.h" #include "viralloc.h" diff --git a/src/util/util.c b/src/util/util.c deleted file mode 100644 index c7d4aa5..0000000 --- a/src/util/util.c +++ /dev/null @@ -1,3131 +0,0 @@ -/* - * utils.c: common, generic utility functions - * - * Copyright (C) 2006-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <poll.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/wait.h> -#if HAVE_MMAP -# include <sys/mman.h> -#endif -#include <string.h> -#include <signal.h> -#include <termios.h> -#include <pty.h> -#include <locale.h> - -#if HAVE_LIBDEVMAPPER_H -# include <libdevmapper.h> -#endif - -#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 -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -# include <mntent.h> -#endif - -#ifdef WIN32 -# ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -# endif -# include <windows.h> -# include <shlobj.h> -#endif - -#include "c-ctype.h" -#include "dirname.h" -#include "virterror_internal.h" -#include "virlog.h" -#include "virbuffer.h" -#include "util.h" -#include "virstoragefile.h" -#include "viralloc.h" -#include "virthread.h" -#include "verify.h" -#include "virfile.h" -#include "vircommand.h" -#include "nonblocking.h" -#include "passfd.h" -#include "virprocess.h" - -#ifndef NSIG -# define NSIG 32 -#endif - -verify(sizeof(gid_t) <= sizeof(unsigned int) && - sizeof(uid_t) <= sizeof(unsigned int)); - -#define VIR_FROM_THIS VIR_FROM_NONE - -/* Like read(), but restarts after EINTR */ -ssize_t -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, off_t offset, off_t len) -{ - int ret = posix_fallocate(fd, offset, len); - if (ret == 0) - return 0; - errno = ret; - return -1; -} -#else - -# ifdef HAVE_MMAP -int safezero(int fd, 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 -1; - - buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); - if (buf == MAP_FAILED) - return -1; - - memset(buf, 0, len); - munmap(buf, len); - - return 0; -} - -# else /* HAVE_MMAP */ - -int safezero(int fd, off_t offset, off_t len) -{ - int r; - char *buf; - unsigned long long remain, bytes; - - if (lseek(fd, offset, SEEK_SET) < 0) - return -1; - - /* 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) { - errno = ENOMEM; - return -1; - } - - while (remain) { - if (bytes > remain) - bytes = remain; - - r = safewrite(fd, buf, bytes); - if (r < 0) { - VIR_FREE(buf); - return -1; - } - - /* safewrite() guarantees all data will be written */ - remain -= bytes; - } - VIR_FREE(buf); - return 0; -} -# endif /* HAVE_MMAP */ -#endif /* HAVE_POSIX_FALLOCATE */ - -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; -} - -#ifndef WIN32 - -int virSetInherit(int fd, bool inherit) { - int fflags; - if ((fflags = fcntl(fd, F_GETFD)) < 0) - return -1; - if (inherit) - fflags &= ~FD_CLOEXEC; - else - fflags |= FD_CLOEXEC; - if ((fcntl(fd, F_SETFD, fflags)) < 0) - return -1; - return 0; -} - -#else /* WIN32 */ - -int virSetInherit(int fd ATTRIBUTE_UNUSED, bool inherit ATTRIBUTE_UNUSED) -{ - /* FIXME: Currently creating child processes is not supported on - * Win32, so there is no point in failing calls that are only relevant - * when creating child processes. So just pretend that we changed the - * inheritance property of the given fd as requested. */ - return 0; -} - -#endif /* WIN32 */ - -int virSetBlocking(int fd, bool blocking) { - return set_nonblocking_flag(fd, !blocking); -} - -int virSetNonBlock(int fd) { - return virSetBlocking(fd, false); -} - -int virSetCloseExec(int fd) -{ - return virSetInherit(fd, false); -} - -int -virPipeReadUntilEOF(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; - fds[0].revents = 0; - finished[0] = 0; - fds[1].fd = errfd; - fds[1].events = POLLIN; - fds[1].revents = 0; - 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; - - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Unknown poll response.")); - goto error; - } - - got = read(fds[i].fd, data, sizeof(data)); - - if (got == sizeof(data)) - finished[i] = 0; - - 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(); - goto error; - } - memmove(*buf+size, data, got); - (*buf)[size+got] = '\0'; - } - continue; - - pollerr: - virReportSystemError(errno, - "%s", _("poll error")); - goto error; - } - - return 0; - -error: - VIR_FREE(*outbuf); - VIR_FREE(*errbuf); - return -1; -} - -/* 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 * -saferead_lim(int fd, size_t max_len, size_t *length) -{ - char *buf = NULL; - size_t alloc = 0; - size_t size = 0; - int save_errno; - - for (;;) { - int count; - int 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 = saferead(fd, buf + size, requested); - size += count; - - if (count != requested || requested == 0) { - save_errno = errno; - if (count < 0) - break; - buf[size] = '\0'; - *length = size; - return buf; - } - } - - VIR_FREE(buf); - errno = save_errno; - return NULL; -} - -/* A wrapper around saferead_lim that maps a failure due to - exceeding the maximum size limitation to EOVERFLOW. */ -int -virFileReadLimFD(int fd, int maxlen, char **buf) -{ - size_t len; - char *s; - - if (maxlen <= 0) { - errno = EINVAL; - return -1; - } - s = saferead_lim(fd, 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; -} - -int virFileReadAll(const char *path, int maxlen, char **buf) -{ - int fd = open(path, O_RDONLY); - if (fd < 0) { - virReportSystemError(errno, _("Failed to open file '%s'"), path); - return -1; - } - - int len = virFileReadLimFD(fd, maxlen, buf); - VIR_FORCE_CLOSE(fd); - if (len < 0) { - virReportSystemError(errno, _("Failed to read file '%s'"), path); - return -1; - } - - return len; -} - -/* Truncate @path and write @str to it. If @mode is 0, ensure that - @path exists; otherwise, use @mode if @path must be created. - Return 0 for success, nonzero for failure. - Be careful to preserve any errno value upon failure. */ -int virFileWriteStr(const char *path, const char *str, mode_t mode) -{ - int fd; - - if (mode) - fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode); - else - fd = open(path, O_WRONLY|O_TRUNC); - if (fd == -1) - return -1; - - if (safewrite(fd, str, strlen(str)) < 0) { - VIR_FORCE_CLOSE(fd); - return -1; - } - - /* Use errno from failed close only if there was no write error. */ - if (VIR_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 STRCASEEQ(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)); -} - - - -static int -virFileResolveLinkHelper(const char *linkpath, - bool intermediatePaths, - char **resultpath) -{ - struct stat st; - - *resultpath = NULL; - - /* We don't need the full canonicalization of intermediate - * directories, if linkpath is absolute and the basename is - * already a non-symlink. */ - if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) { - if (lstat(linkpath, &st) < 0) - return -1; - - if (!S_ISLNK(st.st_mode)) { - if (!(*resultpath = strdup(linkpath))) - return -1; - return 0; - } - } - - *resultpath = canonicalize_file_name(linkpath); - - return *resultpath == NULL ? -1 : 0; -} - -/* - * Attempt to resolve a symbolic link, returning an - * absolute path where only the last component is guaranteed - * not to be a symlink. - * - * Return 0 if path was not a symbolic, or the link was - * resolved. Return -1 with errno set upon error - */ -int virFileResolveLink(const char *linkpath, - char **resultpath) -{ - return virFileResolveLinkHelper(linkpath, false, resultpath); -} - -/* - * Attempt to resolve a symbolic link, returning an - * absolute path where every component is guaranteed - * not to be a symlink. - * - * Return 0 if path was not a symbolic, or the link was - * resolved. Return -1 with errno set upon error - */ -int virFileResolveAllLinks(const char *linkpath, - char **resultpath) -{ - return virFileResolveLinkHelper(linkpath, true, resultpath); -} - -/* - * Check whether the given file is a link. - * Returns 1 in case of the file being a link, 0 in case it is not - * a link and the negative errno in all other cases. - */ -int virFileIsLink(const char *linkpath) -{ - struct stat st; - - if (lstat(linkpath, &st) < 0) - return -errno; - - return S_ISLNK(st.st_mode) != 0; -} - - -/* - * Finds a requested executable 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 *path = NULL; - char *pathiter; - char *pathseg; - char *fullpath = NULL; - - if (file == NULL) - return NULL; - - /* if we are passed an absolute path (starting with /), return a - * copy of that path, after validating that it is executable - */ - if (IS_ABSOLUTE_FILE_NAME(file)) { - if (virFileIsExecutable(file)) - return strdup(file); - else - return NULL; - } - - /* If we are passed an anchored path (containing a /), then there - * is no path search - it must exist in the current directory - */ - if (strchr(file, '/')) { - if (virFileIsExecutable(file)) - ignore_value(virFileAbsPath(file, &path)); - return path; - } - - /* copy PATH env so we can tweak it */ - path = getenv("PATH"); - - if (path == NULL || (path = strdup(path)) == NULL) - return NULL; - - /* for each path segment, append the file to search for and test for - * it. return it if found. - */ - pathiter = path; - while ((pathseg = strsep(&pathiter, ":")) != NULL) { - if (virAsprintf(&fullpath, "%s/%s", pathseg, file) < 0 || - virFileIsExecutable(fullpath)) - break; - VIR_FREE(fullpath); - } - - VIR_FREE(path); - return fullpath; -} - -bool virFileIsDir(const char *path) -{ - struct stat s; - return (stat(path, &s) == 0) && S_ISDIR(s.st_mode); -} - -bool virFileExists(const char *path) -{ - return access(path, F_OK) == 0; -} - -/* Check that a file is regular and has executable bits. If false is - * returned, errno is valid. - * - * Note: In the presence of ACLs, this may return true for a file that - * would actually fail with EACCES for a given user, or false for a - * file that the user could actually execute, but setups with ACLs - * that weird are unusual. */ -bool -virFileIsExecutable(const char *file) -{ - struct stat sb; - - /* We would also want to check faccessat if we cared about ACLs, - * but we don't. */ - if (stat(file, &sb) < 0) - return false; - if (S_ISREG(sb.st_mode) && (sb.st_mode & 0111) != 0) - return true; - errno = S_ISDIR(sb.st_mode) ? EISDIR : EACCES; - return false; -} - -#ifndef WIN32 -/* Check that a file is accessible under certain - * user & gid. - * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK. - * see 'man access' for more details. - * Returns 0 on success, -1 on fail with errno set. - */ -int -virFileAccessibleAs(const char *path, int mode, - uid_t uid, gid_t gid) -{ - pid_t pid = 0; - int status, ret = 0; - int forkRet = 0; - - if (uid == getuid() && - gid == getgid()) - return access(path, mode); - - forkRet = virFork(&pid); - - if (pid < 0) { - return -1; - } - - if (pid) { /* parent */ - if (virProcessWait(pid, &status) < 0) { - /* virProcessWait() already - * reported error */ - return -1; - } - - if (!WIFEXITED(status)) { - errno = EINTR; - return -1; - } - - if (status) { - errno = WEXITSTATUS(status); - return -1; - } - - return 0; - } - - /* child. - * Return positive value here. Parent - * will change it to negative one. */ - - if (forkRet < 0) { - ret = errno; - goto childerror; - } - - if (virSetUIDGID(uid, gid) < 0) { - ret = errno; - goto childerror; - } - - if (access(path, mode) < 0) - ret = errno; - -childerror: - if ((ret & 0xFF) != ret) { - VIR_WARN("unable to pass desired return value %d", ret); - ret = 0xFF; - } - - _exit(ret); -} - -/* virFileOpenForceOwnerMode() - an internal utility function called - * only by virFileOpenAs(). Sets the owner and mode of the file - * opened as "fd" if it's not correct AND the flags say it should be - * forced. */ -static int -virFileOpenForceOwnerMode(const char *path, int fd, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) -{ - int ret = 0; - struct stat st; - - if (!(flags & (VIR_FILE_OPEN_FORCE_OWNER | VIR_FILE_OPEN_FORCE_MODE))) - return 0; - - if (fstat(fd, &st) == -1) { - ret = -errno; - virReportSystemError(errno, _("stat of '%s' failed"), path); - return ret; - } - /* NB: uid:gid are never "-1" (default) at this point - the caller - * has always changed -1 to the value of get[gu]id(). - */ - if ((flags & VIR_FILE_OPEN_FORCE_OWNER) && - ((st.st_uid != uid) || (st.st_gid != gid)) && - (fchown(fd, uid, gid) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot chown '%s' to (%u, %u)"), - path, (unsigned int) uid, - (unsigned int) gid); - return ret; - } - if ((flags & VIR_FILE_OPEN_FORCE_MODE) && - ((mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != - (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) && - (fchmod(fd, mode) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot set mode of '%s' to %04o"), - path, mode); - return ret; - } - return ret; -} - -/* virFileOpenForked() - an internal utility function called only by - * virFileOpenAs(). It forks, then the child does setuid+setgid to - * given uid:gid and attempts to open the file, while the parent just - * calls recvfd to get the open fd back from the child. returns the - * fd, or -errno if there is an error. */ -static int -virFileOpenForked(const char *path, int openflags, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) -{ - pid_t pid; - int waitret, status, ret = 0; - int fd = -1; - int pair[2] = { -1, -1 }; - int forkRet; - - /* parent is running as root, but caller requested that the - * file be opened as some other user and/or group). The - * following dance avoids problems caused by root-squashing - * NFS servers. */ - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { - ret = -errno; - virReportSystemError(errno, - _("failed to create socket needed for '%s'"), - path); - return ret; - } - - forkRet = virFork(&pid); - if (pid < 0) - return -errno; - - if (pid == 0) { - - /* child */ - - VIR_FORCE_CLOSE(pair[0]); /* preserves errno */ - if (forkRet < 0) { - /* error encountered and logged in virFork() after the fork. */ - ret = -errno; - goto childerror; - } - - /* set desired uid/gid, then attempt to create the file */ - - if (virSetUIDGID(uid, gid) < 0) { - ret = -errno; - goto childerror; - } - - if ((fd = open(path, openflags, mode)) < 0) { - ret = -errno; - virReportSystemError(errno, - _("child process failed to create file '%s'"), - path); - goto childerror; - } - - /* File is successfully open. Set permissions if requested. */ - ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); - if (ret < 0) - goto childerror; - - do { - ret = sendfd(pair[1], fd); - } while (ret < 0 && errno == EINTR); - - if (ret < 0) { - ret = -errno; - virReportSystemError(errno, "%s", - _("child process failed to send fd to parent")); - goto childerror; - } - - childerror: - /* ret tracks -errno on failure, but exit value must be positive. - * If the child exits with EACCES, then the parent tries again. */ - /* XXX This makes assumptions about errno being < 255, which is - * not true on Hurd. */ - VIR_FORCE_CLOSE(pair[1]); - if (ret < 0) { - VIR_FORCE_CLOSE(fd); - } - ret = -ret; - if ((ret & 0xff) != ret) { - VIR_WARN("unable to pass desired return value %d", ret); - ret = 0xff; - } - _exit(ret); - } - - /* parent */ - - VIR_FORCE_CLOSE(pair[1]); - - do { - fd = recvfd(pair[0], 0); - } while (fd < 0 && errno == EINTR); - VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */ - - if (fd < 0 && errno != EACCES) { - ret = -errno; - while (waitpid(pid, NULL, 0) == -1 && errno == EINTR); - return ret; - } - - /* wait for child to complete, and retrieve its exit code */ - while ((waitret = waitpid(pid, &status, 0) == -1) - && (errno == EINTR)); - if (waitret == -1) { - ret = -errno; - virReportSystemError(errno, - _("failed to wait for child creating '%s'"), - path); - VIR_FORCE_CLOSE(fd); - return ret; - } - if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES || - fd == -1) { - /* fall back to the simpler method, which works better in - * some cases */ - VIR_FORCE_CLOSE(fd); - if (flags & VIR_FILE_OPEN_NOFORK) { - /* If we had already tried opening w/o fork+setuid and - * failed, no sense trying again. Just set return the - * original errno that we got at that time (by - * definition, always either EACCES or EPERM - EACCES - * is close enough). - */ - return -EACCES; - } - if ((fd = open(path, openflags, mode)) < 0) - return -errno; - ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); - if (ret < 0) { - VIR_FORCE_CLOSE(fd); - return ret; - } - } - return fd; -} - -/** - * virFileOpenAs: - * @path: file to open or create - * @openflags: flags to pass to open - * @mode: mode to use on creation or when forcing permissions - * @uid: uid that should own file on creation - * @gid: gid that should own file - * @flags: bit-wise or of VIR_FILE_OPEN_* flags - * - * Open @path, and return an fd to the open file. @openflags contains - * the flags normally passed to open(2), while those in @flags are - * used internally. If @flags includes VIR_FILE_OPEN_NOFORK, then try - * opening the file while executing with the current uid:gid - * (i.e. don't fork+setuid+setgid before the call to open()). If - * @flags includes VIR_FILE_OPEN_FORK, then try opening the file while - * the effective user id is @uid (by forking a child process); this - * allows one to bypass root-squashing NFS issues; NOFORK is always - * tried before FORK (the absence of both flags is treated identically - * to (VIR_FILE_OPEN_NOFORK | VIR_FILE_OPEN_FORK)). If @flags includes - * VIR_FILE_OPEN_FORCE_OWNER, then ensure that @path is owned by - * uid:gid before returning (even if it already existed with a - * different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE, - * ensure it has those permissions before returning (again, even if - * the file already existed with different permissions). The return - * value (if non-negative) is the file descriptor, left open. Returns - * -errno on failure. */ -int -virFileOpenAs(const char *path, int openflags, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) -{ - int ret = 0, fd = -1; - - /* allow using -1 to mean "current value" */ - if (uid == (uid_t) -1) - uid = getuid(); - if (gid == (gid_t) -1) - gid = getgid(); - - /* treat absence of both flags as presence of both for simpler - * calling. */ - if (!(flags & (VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK))) - flags |= VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK; - - if ((flags & VIR_FILE_OPEN_NOFORK) - || (getuid() != 0) - || ((uid == 0) && (gid == 0))) { - - if ((fd = open(path, openflags, mode)) < 0) { - ret = -errno; - } else { - ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); - if (ret < 0) - goto error; - } - } - - /* If we either 1) didn't try opening as current user at all, or - * 2) failed, and errno/virStorageFileIsSharedFS indicate we might - * be successful if we try as a different uid, then try doing - * fork+setuid+setgid before opening. - */ - if ((fd < 0) && (flags & VIR_FILE_OPEN_FORK)) { - - if (ret < 0) { - /* An open(2) that failed due to insufficient permissions - * could return one or the other of these depending on OS - * version and circumstances. Any other errno indicates a - * problem that couldn't be remedied by fork+setuid - * anyway. */ - if (ret != -EACCES && ret != -EPERM) - goto error; - - /* On Linux we can also verify the FS-type of the - * directory. (this is a NOP on other platforms). */ - switch (virStorageFileIsSharedFS(path)) { - case 1: - /* it was on a network share, so we'll re-try */ - break; - case -1: - /* failure detecting fstype */ - virReportSystemError(errno, _("couldn't determine fs type " - "of mount containing '%s'"), path); - goto error; - case 0: - default: - /* file isn't on a recognized network FS */ - goto error; - } - } - - /* passed all prerequisites - retry the open w/fork+setuid */ - if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) { - ret = fd; - fd = -1; - goto error; - } - } - - /* File is successfully opened */ - - return fd; - -error: - if (fd < 0) { - /* whoever failed the open last has already set ret = -errno */ - virReportSystemError(-ret, openflags & O_CREAT - ? _("failed to create file '%s'") - : _("failed to open file '%s'"), - path); - } else { - /* some other failure after the open succeeded */ - VIR_FORCE_CLOSE(fd); - } - return ret; -} - -/* return -errno on failure, or 0 on success */ -static int virDirCreateNoFork(const char *path, mode_t mode, uid_t uid, gid_t gid, - unsigned int flags) { - int ret = 0; - struct stat st; - - if ((mkdir(path, mode) < 0) - && !((errno == EEXIST) && (flags & VIR_DIR_CREATE_ALLOW_EXIST))) { - ret = -errno; - virReportSystemError(errno, _("failed to create directory '%s'"), - path); - goto error; - } - - if (stat(path, &st) == -1) { - ret = -errno; - virReportSystemError(errno, _("stat of '%s' failed"), path); - goto error; - } - if (((st.st_uid != uid) || (st.st_gid != gid)) - && (chown(path, uid, gid) < 0)) { - ret = -errno; - virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"), - path, (unsigned int) uid, (unsigned int) gid); - goto error; - } - if ((flags & VIR_DIR_CREATE_FORCE_PERMS) - && (chmod(path, mode) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot set mode of '%s' to %04o"), - path, mode); - goto error; - } -error: - return ret; -} - -/* return -errno on failure, or 0 on success */ -int virDirCreate(const char *path, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) { - struct stat st; - pid_t pid; - int waitret; - int status, ret = 0; - - /* allow using -1 to mean "current value" */ - if (uid == (uid_t) -1) - uid = getuid(); - if (gid == (gid_t) -1) - gid = getgid(); - - if ((!(flags & VIR_DIR_CREATE_AS_UID)) - || (getuid() != 0) - || ((uid == 0) && (gid == 0)) - || ((flags & VIR_DIR_CREATE_ALLOW_EXIST) && (stat(path, &st) >= 0))) { - return virDirCreateNoFork(path, mode, uid, gid, flags); - } - - int forkRet = virFork(&pid); - - if (pid < 0) { - ret = -errno; - return ret; - } - - if (pid) { /* parent */ - /* wait for child to complete, and retrieve its exit code */ - while ((waitret = waitpid(pid, &status, 0) == -1) && (errno == EINTR)); - if (waitret == -1) { - ret = -errno; - virReportSystemError(errno, - _("failed to wait for child creating '%s'"), - path); - goto parenterror; - } - if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) { - /* fall back to the simpler method, which works better in - * some cases */ - return virDirCreateNoFork(path, mode, uid, gid, flags); - } -parenterror: - return ret; - } - - /* child */ - - if (forkRet < 0) { - /* error encountered and logged in virFork() after the fork. */ - goto childerror; - } - - /* set desired uid/gid, then attempt to create the directory */ - - if (virSetUIDGID(uid, gid) < 0) { - ret = -errno; - goto childerror; - } - if (mkdir(path, mode) < 0) { - ret = -errno; - if (ret != -EACCES) { - /* in case of EACCES, the parent will retry */ - virReportSystemError(errno, _("child failed to create directory '%s'"), - path); - } - goto childerror; - } - /* check if group was set properly by creating after - * setgid. If not, try doing it with chown */ - if (stat(path, &st) == -1) { - ret = -errno; - virReportSystemError(errno, - _("stat of '%s' failed"), path); - goto childerror; - } - if ((st.st_gid != gid) && (chown(path, -1, gid) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot chown '%s' to group %u"), - path, (unsigned int) gid); - goto childerror; - } - if ((flags & VIR_DIR_CREATE_FORCE_PERMS) - && chmod(path, mode) < 0) { - virReportSystemError(errno, - _("cannot set mode of '%s' to %04o"), - path, mode); - goto childerror; - } -childerror: - _exit(ret); -} - -#else /* WIN32 */ - -int -virFileAccessibleAs(const char *path, - int mode, - uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED) -{ - - VIR_WARN("Ignoring uid/gid due to WIN32"); - - return access(path, mode); -} - -/* return -errno on failure, or 0 on success */ -int virFileOpenAs(const char *path ATTRIBUTE_UNUSED, - int openflags ATTRIBUTE_UNUSED, - mode_t mode ATTRIBUTE_UNUSED, - uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED, - unsigned int flags_unused ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virFileOpenAs is not implemented for WIN32")); - - return -ENOSYS; -} - -int virDirCreate(const char *path ATTRIBUTE_UNUSED, - mode_t mode ATTRIBUTE_UNUSED, - uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED, - unsigned int flags_unused ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virDirCreate is not implemented for WIN32")); - - return -ENOSYS; -} -#endif /* WIN32 */ - -static int virFileMakePathHelper(char *path, mode_t mode) -{ - struct stat st; - char *p; - - VIR_DEBUG("path=%s mode=0%o", path, mode); - - if (stat(path, &st) >= 0) { - if (S_ISDIR(st.st_mode)) - return 0; - - errno = ENOTDIR; - return -1; - } - - if (errno != ENOENT) - return -1; - - if ((p = strrchr(path, '/')) == NULL) { - errno = EINVAL; - return -1; - } - - if (p != path) { - *p = '\0'; - - if (virFileMakePathHelper(path, mode) < 0) - return -1; - - *p = '/'; - } - - if (mkdir(path, mode) < 0 && errno != EEXIST) - return -1; - - return 0; -} - -/** - * Creates the given directory with mode 0777 if it's not already existing. - * - * Returns 0 on success, or -1 if an error occurred (in which case, errno - * is set appropriately). - */ -int virFileMakePath(const char *path) -{ - return virFileMakePathWithMode(path, 0777); -} - -int -virFileMakePathWithMode(const char *path, - mode_t mode) -{ - int ret = -1; - char *tmp; - - if ((tmp = strdup(path)) == NULL) - goto cleanup; - - ret = virFileMakePathHelper(tmp, mode); - -cleanup: - VIR_FREE(tmp); - return ret; -} - -/* Build up a fully qualified path for a config file to be - * associated with a persistent guest or network */ -char * -virFileBuildPath(const char *dir, const char *name, const char *ext) -{ - char *path; - - if (ext == NULL) { - if (virAsprintf(&path, "%s/%s", dir, name) < 0) { - virReportOOMError(); - return NULL; - } - } else { - if (virAsprintf(&path, "%s/%s%s", dir, name, ext) < 0) { - virReportOOMError(); - return NULL; - } - } - - return path; -} - -/* Open a non-blocking master side of a pty. If ttyName is not NULL, - * then populate it with the name of the slave. If rawmode is set, - * also put the master side into raw mode before returning. */ -#ifndef WIN32 -int virFileOpenTty(int *ttymaster, - char **ttyName, - int rawmode) -{ - /* XXX A word of caution - on some platforms (Solaris and HP-UX), - * additional ioctl() calls are needs after opening the slave - * before it will cause isatty() to return true. Should we make - * virFileOpenTty also return the opened slave fd, so the caller - * doesn't have to worry about that mess? */ - int ret = -1; - int slave = -1; - char *name = NULL; - - /* Unfortunately, we can't use the name argument of openpty, since - * there is no guarantee on how large the buffer has to be. - * Likewise, we can't use the termios argument: we have to use - * read-modify-write since there is no portable way to initialize - * a struct termios without use of tcgetattr. */ - if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0) - return -1; - - /* What a shame that openpty cannot atomically set FD_CLOEXEC, but - * that using posix_openpt/grantpt/unlockpt/ptsname is not - * thread-safe, and that ptsname_r is not portable. */ - if (virSetNonBlock(*ttymaster) < 0 || - virSetCloseExec(*ttymaster) < 0) - goto cleanup; - - /* While Linux supports tcgetattr on either the master or the - * slave, Solaris requires it to be on the slave. */ - if (rawmode) { - struct termios ttyAttr; - if (tcgetattr(slave, &ttyAttr) < 0) - goto cleanup; - - cfmakeraw(&ttyAttr); - - if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0) - goto cleanup; - } - - /* ttyname_r on the slave is required by POSIX, while ptsname_r on - * the master is a glibc extension, and the POSIX ptsname is not - * thread-safe. Since openpty gave us both descriptors, guess - * which way we will determine the name? :) */ - if (ttyName) { - /* Initial guess of 64 is generally sufficient; rely on ERANGE - * to tell us if we need to grow. */ - size_t len = 64; - int rc; - - if (VIR_ALLOC_N(name, len) < 0) - goto cleanup; - - while ((rc = ttyname_r(slave, name, len)) == ERANGE) { - if (VIR_RESIZE_N(name, len, len, len) < 0) - goto cleanup; - } - if (rc != 0) { - errno = rc; - goto cleanup; - } - *ttyName = name; - name = NULL; - } - - ret = 0; - -cleanup: - if (ret != 0) - VIR_FORCE_CLOSE(*ttymaster); - VIR_FORCE_CLOSE(slave); - VIR_FREE(name); - - return ret; -} -#else /* WIN32 */ -int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED, - char **ttyName ATTRIBUTE_UNUSED, - int rawmode ATTRIBUTE_UNUSED) -{ - /* mingw completely lacks pseudo-terminals, and the gnulib - * replacements are not (yet) license compatible. */ - errno = ENOSYS; - return -1; -} -#endif /* WIN32 */ - -bool virFileIsAbsPath(const char *path) -{ - if (!path) - return false; - - if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) - return true; - -#ifdef WIN32 - if (c_isalpha(path[0]) && - path[1] == ':' && - VIR_FILE_IS_DIR_SEPARATOR(path[2])) - return true; -#endif - - return false; -} - - -const char *virFileSkipRoot(const char *path) -{ -#ifdef WIN32 - /* Skip \\server\share or //server/share */ - if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) && - VIR_FILE_IS_DIR_SEPARATOR(path[1]) && - path[2] && - !VIR_FILE_IS_DIR_SEPARATOR(path[2])) - { - const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR); - const char *q = strchr(path + 2, '/'); - - if (p == NULL || (q != NULL && q < p)) - p = q; - - if (p && p > path + 2 && p[1]) { - path = p + 1; - - while (path[0] && - !VIR_FILE_IS_DIR_SEPARATOR(path[0])) - path++; - - /* Possibly skip a backslash after the share name */ - if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) - path++; - - return path; - } - } -#endif - - /* Skip initial slashes */ - if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) { - while (VIR_FILE_IS_DIR_SEPARATOR(path[0])) - path++; - - return path; - } - -#ifdef WIN32 - /* Skip X:\ */ - if (c_isalpha(path[0]) && - path[1] == ':' && - VIR_FILE_IS_DIR_SEPARATOR(path[2])) - return path + 3; -#endif - - return path; -} - - - -/* - * Creates an absolute path for a potentially relative path. - * Return 0 if the path was not relative, or on success. - * Return -1 on error. - * - * You must free the result. - */ -int virFileAbsPath(const char *path, char **abspath) -{ - char *buf; - - if (path[0] == '/') { - if (!(*abspath = strdup(path))) - return -1; - } else { - buf = getcwd(NULL, 0); - if (buf == NULL) - return -1; - - if (virAsprintf(abspath, "%s/%s", buf, path) < 0) { - VIR_FREE(buf); - return -1; - } - VIR_FREE(buf); - } - - return 0; -} - -/* Remove spurious / characters from a path. The result must be freed */ -char * -virFileSanitizePath(const char *path) -{ - const char *cur = path; - char *cleanpath; - int idx = 0; - - cleanpath = strdup(path); - if (!cleanpath) { - virReportOOMError(); - return NULL; - } - - /* Need to sanitize: - * // -> // - * /// -> / - * /../foo -> /../foo - * /foo///bar/ -> /foo/bar - */ - - /* Starting with // is valid posix, but ///foo == /foo */ - if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') { - idx = 2; - cur += 2; - } - - /* Sanitize path in place */ - while (*cur != '\0') { - if (*cur != '/') { - cleanpath[idx++] = *cur++; - continue; - } - - /* Skip all extra / */ - while (*++cur == '/') - continue; - - /* Don't add a trailing / */ - if (idx != 0 && *cur == '\0') - break; - - cleanpath[idx++] = '/'; - } - cleanpath[idx] = '\0'; - - return cleanpath; -} - -/* 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); /* exempt from syntax-check */ - 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); /* exempt from syntax-check */ - 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 a "long" value. */ -int -virStrToLong_l(char const *s, char **end_ptr, int base, long *result) -{ - long int val; - char *p; - int err; - - errno = 0; - val = strtol(s, &p, base); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - if (end_ptr) - *end_ptr = p; - if (err) - return -1; - *result = val; - return 0; -} - -/* Just like virStrToLong_i, above, but produce an "unsigned long" value. */ -int -virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result) -{ - unsigned long int val; - char *p; - int err; - - errno = 0; - val = strtoul(s, &p, base); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - if (end_ptr) - *end_ptr = p; - if (err) - return -1; - *result = val; - return 0; -} - -/* Just like virStrToLong_i, above, but produce a "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); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - 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); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - 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); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - if (end_ptr) - *end_ptr = p; - if (err) - return -1; - *result = val; - return 0; -} - -/* Convert C from hexadecimal character to integer. */ -int -virHexToBin(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; - } -} - -/* Scale an integer VALUE in-place by an optional case-insensitive - * SUFFIX, defaulting to SCALE if suffix is NULL or empty (scale is - * typically 1 or 1024). Recognized suffixes include 'b' or 'bytes', - * as well as power-of-two scaling via binary abbreviations ('KiB', - * 'MiB', ...) or their one-letter counterpart ('k', 'M', ...), and - * power-of-ten scaling via SI abbreviations ('KB', 'MB', ...). - * Ensure that the result does not exceed LIMIT. Return 0 on success, - * -1 with error message raised on failure. */ -int -virScaleInteger(unsigned long long *value, const char *suffix, - unsigned long long scale, unsigned long long limit) -{ - if (!suffix || !*suffix) { - if (!scale) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid scale %llu"), scale); - return -1; - } - suffix = ""; - } else if (STRCASEEQ(suffix, "b") || STRCASEEQ(suffix, "byte") || - STRCASEEQ(suffix, "bytes")) { - scale = 1; - } else { - int base; - - if (!suffix[1] || STRCASEEQ(suffix + 1, "iB")) { - base = 1024; - } else if (c_tolower(suffix[1]) == 'b' && !suffix[2]) { - base = 1000; - } else { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown suffix '%s'"), suffix); - return -1; - } - scale = 1; - switch (c_tolower(*suffix)) { - case 'e': - scale *= base; - /* fallthrough */ - case 'p': - scale *= base; - /* fallthrough */ - case 't': - scale *= base; - /* fallthrough */ - case 'g': - scale *= base; - /* fallthrough */ - case 'm': - scale *= base; - /* fallthrough */ - case 'k': - scale *= base; - break; - default: - virReportError(VIR_ERR_INVALID_ARG, - _("unknown suffix '%s'"), suffix); - return -1; - } - } - - if (*value && *value >= (limit / scale)) { - virReportError(VIR_ERR_OVERFLOW, _("value too large: %llu%s"), - *value, suffix); - return -1; - } - *value *= scale; - return 0; -} - -/** - * virSkipSpaces: - * @str: pointer to the char pointer used - * - * Skip potential blanks, this includes space tabs, line feed, - * carriage returns. - */ -void -virSkipSpaces(const char **str) -{ - const char *cur = *str; - - while (c_isspace(*cur)) - cur++; - *str = cur; -} - -/** - * virSkipSpacesAndBackslash: - * @str: pointer to the char pointer used - * - * Like virSkipSpaces, but also skip backslashes erroneously emitted - * by xend - */ -void -virSkipSpacesAndBackslash(const char **str) -{ - const char *cur = *str; - - while (c_isspace(*cur) || *cur == '\\') - cur++; - *str = cur; -} - -/** - * virTrimSpaces: - * @str: string to modify to remove all trailing spaces - * @endp: track the end of the string - * - * If @endp is NULL on entry, then all spaces prior to the trailing - * NUL in @str are removed, by writing NUL into the appropriate - * location. If @endp is non-NULL but points to a NULL pointer, - * then all spaces prior to the trailing NUL in @str are removed, - * NUL is written to the new string end, and endp is set to the - * location of the (new) string end. If @endp is non-NULL and - * points to a non-NULL pointer, then that pointer is used as - * the end of the string, endp is set to the (new) location, but - * no NUL pointer is written into the string. - */ -void -virTrimSpaces(char *str, char **endp) -{ - char *end; - - if (!endp || !*endp) - end = str + strlen(str); - else - end = *endp; - while (end > str && c_isspace(end[-1])) - end--; - if (endp) { - if (!*endp) - *end = '\0'; - *endp = end; - } else { - *end = '\0'; - } -} - -/** - * virSkipSpacesBackwards: - * @str: start of string - * @endp: on entry, *endp must be NULL or a location within @str, on exit, - * will be adjusted to skip trailing spaces, or to NULL if @str had nothing - * but spaces. - */ -void -virSkipSpacesBackwards(const char *str, char **endp) -{ - /* Casting away const is safe, since virTrimSpaces does not - * modify string with this particular usage. */ - char *s = (char*) str; - - if (!*endp) - *endp = s + strlen(s); - virTrimSpaces(s, endp); - if (s == *endp) - *endp = NULL; -} - -/** - * 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; -} - - -/** - * virParseVersionString: - * @str: const char pointer to the version string - * @version: unsigned long pointer to output the version number - * @allowMissing: true to treat 3 like 3.0.0, false to error out on - * missing minor or micro - * - * Parse an unsigned version number from a version string. Expecting - * 'major.minor.micro' format, ignoring an optional suffix. - * - * The major, minor and micro numbers are encoded into a single version number: - * - * 1000000 * major + 1000 * minor + micro - * - * Returns the 0 for success, -1 for error. - */ -int -virParseVersionString(const char *str, unsigned long *version, - bool allowMissing) -{ - unsigned int major, minor = 0, micro = 0; - char *tmp; - - if (virStrToLong_ui(str, &tmp, 10, &major) < 0) - return -1; - - if (!allowMissing && *tmp != '.') - return -1; - - if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, &minor) < 0) - return -1; - - if (!allowMissing && *tmp != '.') - return -1; - - if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, µ) < 0) - return -1; - - if (major > UINT_MAX / 1000000 || minor > 999 || micro > 999) - return -1; - - *version = 1000000 * major + 1000 * minor + micro; - - return 0; -} - -/** - * virVasprintf - * - * like glibc's vasprintf but makes sure *strp == NULL on failure - */ -int -virVasprintf(char **strp, const char *fmt, va_list list) -{ - int ret; - - if ((ret = vasprintf(strp, fmt, list)) == -1) - *strp = NULL; - - 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); - ret = virVasprintf(strp, fmt, ap); - va_end(ap); - return ret; -} - -/** - * virStrncpy - * - * A safe version of strncpy. The last parameter is the number of bytes - * available in the destination string, *not* the number of bytes you want - * to copy. If the destination is not large enough to hold all n of the - * src string bytes plus a \0, NULL is returned and no data is copied. - * If the destination is large enough to hold the n bytes plus \0, then the - * string is copied and a pointer to the destination string is returned. - */ -char * -virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) -{ - char *ret; - - if (n > (destbytes - 1)) - return NULL; - - ret = strncpy(dest, src, n); - /* strncpy NULL terminates iff the last character is \0. Therefore - * force the last byte to be \0 - */ - dest[n] = '\0'; - - return ret; -} - -/** - * virStrcpy - * - * A safe version of strcpy. The last parameter is the number of bytes - * available in the destination string, *not* the number of bytes you want - * to copy. If the destination is not large enough to hold all n of the - * src string bytes plus a \0, NULL is returned and no data is copied. - * If the destination is large enough to hold the source plus \0, then the - * string is copied and a pointer to the destination string is returned. - */ -char * -virStrcpy(char *dest, const char *src, size_t destbytes) -{ - return virStrncpy(dest, src, strlen(src), destbytes); -} - -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; -} - -/* In case thread-safe locales are available */ -#if HAVE_NEWLOCALE - -static locale_t virLocale; - -static int -virLocaleOnceInit(void) -{ - virLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0); - if (!virLocale) - return -1; - return 0; -} - -VIR_ONCE_GLOBAL_INIT(virLocale) -#endif - -/** - * virDoubleToStr - * - * converts double to string with C locale (thread-safe). - * - * Returns -1 on error, size of the string otherwise. - */ -int -virDoubleToStr(char **strp, double number) -{ - int ret = -1; - -#if HAVE_NEWLOCALE - - locale_t old_loc; - - if (virLocaleInitialize() < 0) - goto error; - - old_loc = uselocale(virLocale); - ret = virAsprintf(strp, "%lf", number); - uselocale(old_loc); - -#else - - char *radix, *tmp; - struct lconv *lc; - - if ((ret = virAsprintf(strp, "%lf", number) < 0)) - goto error; - - lc = localeconv(); - radix = lc->decimal_point; - tmp = strstr(*strp, radix); - if (tmp) { - *tmp = '.'; - if (strlen(radix) > 1) - memmove(tmp + 1, tmp + strlen(radix), strlen(*strp) - (tmp - *strp)); - } - -#endif /* HAVE_NEWLOCALE */ - error: - return ret; -} - - -/** - * Format @val as a base-10 decimal number, in the - * buffer @buf of size @buflen. To allocate a suitable - * sized buffer, the INT_BUFLEN(int) macro should be - * used - * - * Returns pointer to start of the number in @buf - */ -char * -virFormatIntDecimal(char *buf, size_t buflen, int val) -{ - char *p = buf + buflen - 1; - *p = '\0'; - if (val >= 0) { - do { - *--p = '0' + (val % 10); - val /= 10; - } while (val != 0); - } else { - do { - *--p = '0' - (val % 10); - val /= 10; - } while (val != 0); - *--p = '-'; - } - return p; -} - - -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]+[0-9]*$/ - * into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26) - * Note that any trailing string of digits is simply ignored. - * @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", "ubd"}; - 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++) { - if (!c_islower(*ptr)) - break; - - idx = (idx + (i < 1 ? 0 : 1)) * 26; - idx += *ptr - 'a'; - ptr++; - } - - /* Count the trailing digits. */ - size_t n_digits = strspn(ptr, "0123456789"); - if (ptr[n_digits] != '\0') - return -1; - - return idx; -} - -char *virIndexToDiskName(int idx, const char *prefix) -{ - char *name = NULL; - int i, k, offset; - - if (idx < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Disk index %d is negative"), idx); - return NULL; - } - - for (i = 0, k = idx; k >= 0; ++i, k = k / 26 - 1) { } - - offset = strlen(prefix); - - if (VIR_ALLOC_N(name, offset + i + 1)) { - virReportOOMError(); - return NULL; - } - - strcpy(name, prefix); - name[offset + i] = '\0'; - - for (i = i - 1, k = idx; k >= 0; --i, k = k / 26 - 1) { - name[offset + i] = 'a' + (k % 26); - } - - return name; -} - -#ifndef AI_CANONIDN -# define AI_CANONIDN 0 -#endif - -/* Who knew getting a hostname could be so delicate. In Linux (and Unices - * in general), many things depend on "hostname" returning a value that will - * resolve one way or another. In the modern world where networks frequently - * come and go this is often being hard-coded to resolve to "localhost". If - * it *doesn't* resolve to localhost, then we would prefer to have the FQDN. - * That leads us to 3 possibilities: - * - * 1) gethostname() returns an FQDN (not localhost) - we return the string - * as-is, it's all of the information we want - * 2) gethostname() returns "localhost" - we return localhost; doing further - * work to try to resolve it is pointless - * 3) gethostname() returns a shortened hostname - in this case, we want to - * try to resolve this to a fully-qualified name. Therefore we pass it - * to getaddrinfo(). There are two possible responses: - * a) getaddrinfo() resolves to a FQDN - return the FQDN - * b) getaddrinfo() fails or resolves to localhost - in this case, the - * data we got from gethostname() is actually more useful than what - * we got from getaddrinfo(). Return the value from gethostname() - * and hope for the best. - */ -char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - int r; - char hostname[HOST_NAME_MAX+1], *result; - struct addrinfo hints, *info; - - r = gethostname(hostname, sizeof(hostname)); - if (r == -1) { - virReportSystemError(errno, - "%s", _("failed to determine host name")); - return NULL; - } - NUL_TERMINATE(hostname); - - if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) { - /* in this case, gethostname returned localhost (meaning we can't - * do any further canonicalization), or it returned an FQDN (and - * we don't need to do any further canonicalization). Return the - * string as-is; it's up to callers to check whether "localhost" - * is allowed. - */ - result = strdup(hostname); - goto check_and_return; - } - - /* otherwise, it's a shortened, non-localhost, hostname. Attempt to - * canonicalize the hostname by running it through getaddrinfo - */ - - 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) { - VIR_WARN("getaddrinfo failed for '%s': %s", - hostname, gai_strerror(r)); - result = strdup(hostname); - goto check_and_return; - } - - /* Tell static analyzers about getaddrinfo semantics. */ - sa_assert(info); - - if (info->ai_canonname == NULL || - STRPREFIX(info->ai_canonname, "localhost")) - /* in this case, we tried to canonicalize and we ended up back with - * localhost. Ignore the canonicalized name and just return the - * original hostname - */ - result = strdup(hostname); - else - /* Caller frees this string. */ - result = strdup(info->ai_canonname); - - freeaddrinfo(info); - -check_and_return: - if (result == NULL) - virReportOOMError(); - return result; -} - -#ifdef HAVE_GETPWUID_R -enum { - VIR_USER_ENT_DIRECTORY, - VIR_USER_ENT_NAME, -}; - -static char *virGetUserEnt(uid_t uid, - int field) -{ - char *strbuf; - char *ret; - struct passwd pwbuf; - struct passwd *pw = NULL; - long val = sysconf(_SC_GETPW_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - 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. - */ - while ((rc = getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - VIR_FREE(strbuf); - return NULL; - } - } - if (rc != 0 || pw == NULL) { - virReportSystemError(rc, - _("Failed to find user record for uid '%u'"), - (unsigned int) 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(); - - return ret; -} - -static char *virGetGroupEnt(gid_t gid) -{ - char *strbuf; - char *ret; - struct group grbuf; - struct group *gr = NULL; - long val = sysconf(_SC_GETGR_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - return NULL; - } - - /* - * From the manpage (terrifying but true): - * - * ERRORS - * 0 or ENOENT or ESRCH or EBADF or EPERM or ... - * The given name or gid was not found. - */ - while ((rc = getgrgid_r(gid, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - VIR_FREE(strbuf); - return NULL; - } - } - if (rc != 0 || gr == NULL) { - virReportSystemError(rc, - _("Failed to find group record for gid '%u'"), - (unsigned int) gid); - VIR_FREE(strbuf); - return NULL; - } - - ret = strdup(gr->gr_name); - - VIR_FREE(strbuf); - if (!ret) - virReportOOMError(); - - return ret; -} - -char *virGetUserDirectory(void) -{ - return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); -} - -static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir) -{ - const char *path = getenv(xdgenvname); - char *ret = NULL; - char *home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); - - if (path && path[0]) { - if (virAsprintf(&ret, "%s/libvirt", path) < 0) - goto no_memory; - } else { - if (virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir) < 0) - goto no_memory; - } - - cleanup: - VIR_FREE(home); - return ret; - no_memory: - virReportOOMError(); - goto cleanup; -} - -char *virGetUserConfigDirectory(void) -{ - return virGetXDGDirectory("XDG_CONFIG_HOME", ".config"); -} - -char *virGetUserCacheDirectory(void) -{ - return virGetXDGDirectory("XDG_CACHE_HOME", ".cache"); -} - -char *virGetUserRuntimeDirectory(void) -{ - const char *path = getenv("XDG_RUNTIME_DIR"); - - if (!path || !path[0]) { - return virGetUserCacheDirectory(); - } else { - char *ret; - - if (virAsprintf(&ret, "%s/libvirt", path) < 0) { - virReportOOMError(); - return NULL; - } - - return ret; - } -} - -char *virGetUserName(uid_t uid) -{ - return virGetUserEnt(uid, VIR_USER_ENT_NAME); -} - -char *virGetGroupName(gid_t gid) -{ - return virGetGroupEnt(gid); -} - -/* Search in the password database for a user id that matches the user name - * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. - */ -static int -virGetUserIDByName(const char *name, uid_t *uid) -{ - char *strbuf = NULL; - struct passwd pwbuf; - struct passwd *pw = NULL; - long val = sysconf(_SC_GETPW_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - int ret = -1; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - - while ((rc = getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - } - - if (!pw) { - if (rc != 0) { - char buf[1024]; - /* log the possible error from getpwnam_r. Unfortunately error - * reporting from this function is bad and we can't really - * rely on it, so we just report that the user wasn't found */ - VIR_WARN("User record for user '%s' was not found: %s", - name, virStrerror(rc, buf, sizeof(buf))); - } - - ret = 1; - goto cleanup; - } - - *uid = pw->pw_uid; - ret = 0; - -cleanup: - VIR_FREE(strbuf); - - return ret; -} - -/* Try to match a user id based on `user`. The default behavior is to parse - * `user` first as a user name and then as a user id. However if `user` - * contains a leading '+', the rest of the string is always parsed as a uid. - * - * Returns 0 on success and -1 otherwise. - */ -int -virGetUserID(const char *user, uid_t *uid) -{ - unsigned int uint_uid; - - if (*user == '+') { - user++; - } else { - int rc = virGetUserIDByName(user, uid); - if (rc <= 0) - return rc; - } - - if (virStrToLong_ui(user, NULL, 10, &uint_uid) < 0 || - ((uid_t) uint_uid) != uint_uid) { - virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse user '%s'"), - user); - return -1; - } - - *uid = uint_uid; - - return 0; -} - -/* Search in the group database for a group id that matches the group name - * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. - */ -static int -virGetGroupIDByName(const char *name, gid_t *gid) -{ - char *strbuf = NULL; - struct group grbuf; - struct group *gr = NULL; - long val = sysconf(_SC_GETGR_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - int ret = -1; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - - while ((rc = getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - } - - if (!gr) { - if (rc != 0) { - char buf[1024]; - /* log the possible error from getgrnam_r. Unfortunately error - * reporting from this function is bad and we can't really - * rely on it, so we just report that the user wasn't found */ - VIR_WARN("Group record for user '%s' was not found: %s", - name, virStrerror(rc, buf, sizeof(buf))); - } - - ret = 1; - goto cleanup; - } - - *gid = gr->gr_gid; - ret = 0; - -cleanup: - VIR_FREE(strbuf); - - return ret; -} - -/* Try to match a group id based on `group`. The default behavior is to parse - * `group` first as a group name and then as a group id. However if `group` - * contains a leading '+', the rest of the string is always parsed as a guid. - * - * Returns 0 on success and -1 otherwise. - */ -int -virGetGroupID(const char *group, gid_t *gid) -{ - unsigned int uint_gid; - - if (*group == '+') { - group++; - } else { - int rc = virGetGroupIDByName(group, gid); - if (rc <= 0) - return rc; - } - - if (virStrToLong_ui(group, NULL, 10, &uint_gid) < 0 || - ((gid_t) uint_gid) != uint_gid) { - virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse group '%s'"), - group); - return -1; - } - - *gid = uint_gid; - - return 0; -} - -/* Set the real and effective uid and gid to the given values, and call - * initgroups so that the process has all the assumed group membership of - * that uid. return 0 on success, -1 on failure (the original system error - * remains in errno). - */ -int -virSetUIDGID(uid_t uid, gid_t gid) -{ - int err; - char *buf = NULL; - - if (gid > 0) { - if (setregid(gid, gid) < 0) { - virReportSystemError(err = errno, - _("cannot change to '%d' group"), - (unsigned int) gid); - goto error; - } - } - - if (uid > 0) { -# ifdef HAVE_INITGROUPS - struct passwd pwd, *pwd_result; - size_t bufsize; - int rc; - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize == -1) - bufsize = 16384; - - if (VIR_ALLOC_N(buf, bufsize) < 0) { - virReportOOMError(); - err = ENOMEM; - goto error; - } - while ((rc = getpwuid_r(uid, &pwd, buf, bufsize, - &pwd_result)) == ERANGE) { - if (VIR_RESIZE_N(buf, bufsize, bufsize, bufsize) < 0) { - virReportOOMError(); - err = ENOMEM; - goto error; - } - } - - if (rc) { - virReportSystemError(err = rc, _("cannot getpwuid_r(%d)"), - (unsigned int) uid); - goto error; - } - - if (!pwd_result) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("getpwuid_r failed to retrieve data " - "for uid '%d'"), - (unsigned int) uid); - err = EINVAL; - goto error; - } - - if (initgroups(pwd.pw_name, pwd.pw_gid) < 0) { - virReportSystemError(err = errno, - _("cannot initgroups(\"%s\", %d)"), - pwd.pw_name, (unsigned int) pwd.pw_gid); - goto error; - } -# endif - if (setreuid(uid, uid) < 0) { - virReportSystemError(err = errno, - _("cannot change to uid to '%d'"), - (unsigned int) uid); - goto error; - } - } - - VIR_FREE(buf); - return 0; - -error: - VIR_FREE(buf); - errno = err; - return -1; -} - -#else /* ! HAVE_GETPWUID_R */ - -# ifdef WIN32 -/* These methods are adapted from GLib2 under terms of LGPLv2+ */ -static int -virGetWin32SpecialFolder(int csidl, char **path) -{ - char buf[MAX_PATH+1]; - LPITEMIDLIST pidl = NULL; - int ret = 0; - - *path = NULL; - - if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK) { - if (SHGetPathFromIDList(pidl, buf)) { - if (!(*path = strdup(buf))) { - virReportOOMError(); - ret = -1; - } - } - CoTaskMemFree(pidl); - } - return ret; -} - -static int -virGetWin32DirectoryRoot(char **path) -{ - char windowsdir[MAX_PATH]; - int ret = 0; - - *path = NULL; - - if (GetWindowsDirectory(windowsdir, ARRAY_CARDINALITY(windowsdir))) - { - const char *tmp; - /* Usually X:\Windows, but in terminal server environments - * might be an UNC path, AFAIK. - */ - tmp = virFileSkipRoot(windowsdir); - if (VIR_FILE_IS_DIR_SEPARATOR(tmp[-1]) && - tmp[-2] != ':') - tmp--; - - windowsdir[tmp - windowsdir] = '\0'; - } else { - strcpy(windowsdir, "C:\\"); - } - - if (!(*path = strdup(windowsdir))) { - virReportOOMError(); - ret = -1; - } - - return ret; -} - - - -char * -virGetUserDirectory(void) -{ - const char *dir; - char *ret; - - dir = getenv("HOME"); - - /* Only believe HOME if it is an absolute path and exists */ - if (dir) { - if (!virFileIsAbsPath(dir) || - !virFileExists(dir)) - dir = NULL; - } - - /* In case HOME is Unix-style (it happens), convert it to - * Windows style. - */ - if (dir) { - char *p; - while ((p = strchr(dir, '/')) != NULL) - *p = '\\'; - } - - if (!dir) - /* USERPROFILE is probably the closest equivalent to $HOME? */ - dir = getenv("USERPROFILE"); - - if (dir) { - if (!(ret = strdup(dir))) { - virReportOOMError(); - return NULL; - } - } - - if (!ret && - virGetWin32SpecialFolder(CSIDL_PROFILE, &ret) < 0) - return NULL; - - if (!ret && - virGetWin32DirectoryRoot(&ret) < 0) - return NULL; - - if (!ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine home directory")); - return NULL; - } - - return ret; -} - -char * -virGetUserConfigDirectory(void) -{ - char *ret; - if (virGetWin32SpecialFolder(CSIDL_LOCAL_APPDATA, &ret) < 0) - return NULL; - - if (!ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine config directory")); - return NULL; - } - return ret; -} - -char * -virGetUserCacheDirectory(void) -{ - char *ret; - if (virGetWin32SpecialFolder(CSIDL_INTERNET_CACHE, &ret) < 0) - return NULL; - - if (!ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine config directory")); - return NULL; - } - return ret; -} - -char * -virGetUserRuntimeDirectory(void) -{ - return virGetUserCacheDirectory(); -} -# else /* !HAVE_GETPWUID_R && !WIN32 */ -char * -virGetUserDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserDirectory is not available")); - - return NULL; -} - -char * -virGetUserConfigDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserConfigDirectory is not available")); - - return NULL; -} - -char * -virGetUserCacheDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserCacheDirectory is not available")); - - return NULL; -} - -char * -virGetUserRuntimeDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserRuntimeDirectory is not available")); - - return NULL; -} -# endif /* ! HAVE_GETPWUID_R && ! WIN32 */ - -char * -virGetUserName(uid_t uid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserName is not available")); - - return NULL; -} - -int virGetUserID(const char *name ATTRIBUTE_UNUSED, - uid_t *uid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserID is not available")); - - return 0; -} - - -int virGetGroupID(const char *name ATTRIBUTE_UNUSED, - gid_t *gid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetGroupID is not available")); - - return 0; -} - -int -virSetUIDGID(uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virSetUIDGID is not available")); - return -1; -} - -char * -virGetGroupName(gid_t gid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetGroupName is not available")); - - return NULL; -} -#endif /* HAVE_GETPWUID_R */ - - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -/* 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; -} - -#else /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ - -char * -virFileFindMountPoint(const char *type ATTRIBUTE_UNUSED) -{ - errno = ENOSYS; - - return NULL; -} - -#endif /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ - -#if defined(UDEVADM) || defined(UDEVSETTLE) -void virFileWaitForDevices(void) -{ -# 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. - */ - if (virRun(settleprog, &exitstatus) < 0) - {} -} -#else -void virFileWaitForDevices(void) {} -#endif - -int virBuildPathInternal(char **path, ...) -{ - char *path_component = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - va_list ap; - int ret = 0; - - va_start(ap, path); - - path_component = va_arg(ap, char *); - virBufferAdd(&buf, path_component, -1); - - while ((path_component = va_arg(ap, char *)) != NULL) - { - virBufferAddChar(&buf, '/'); - virBufferAdd(&buf, path_component, -1); - } - - va_end(ap); - - *path = virBufferContentAndReset(&buf); - if (*path == NULL) { - ret = -1; - } - - return ret; -} - -#if HAVE_LIBDEVMAPPER_H -bool -virIsDevMapperDevice(const char *dev_name) -{ - struct stat buf; - - if (!stat(dev_name, &buf) && - S_ISBLK(buf.st_mode) && - dm_is_dm_major(major(buf.st_rdev))) - return true; - - return false; -} -#else -bool virIsDevMapperDevice(const char *dev_name ATTRIBUTE_UNUSED) -{ - return false; -} -#endif - -bool -virValidateWWN(const char *wwn) { - int i; - - for (i = 0; wwn[i]; i++) - if (!c_isxdigit(wwn[i])) - break; - - if (i != 16 || wwn[i]) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Malformed wwn: %s")); - return false; - } - - return true; -} - -bool -virStrIsPrint(const char *str) -{ - int i; - - for (i = 0; str[i]; i++) - if (!c_isprint(str[i])) - return false; - - return true; -} diff --git a/src/util/util.h b/src/util/util.h deleted file mode 100644 index 6d5dd03..0000000 --- a/src/util/util.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * utils.h: common, generic utility functions - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * 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, see - * <http://www.gnu.org/licenses/>. - * - * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com> - */ - -#ifndef __VIR_UTIL_H__ -# define __VIR_UTIL_H__ - -# include "verify.h" -# include "internal.h" -# include <unistd.h> -# include <sys/select.h> -# include <sys/types.h> -# include <stdarg.h> - -# ifndef MIN -# define MIN(a, b) ((a) < (b) ? (a) : (b)) -# endif -# ifndef MAX -# define MAX(a, b) ((a) > (b) ? (a) : (b)) -# endif - -ssize_t saferead(int fd, void *buf, size_t count) ATTRIBUTE_RETURN_CHECK; -ssize_t safewrite(int fd, const void *buf, size_t count) - ATTRIBUTE_RETURN_CHECK; -int safezero(int fd, off_t offset, off_t len) - ATTRIBUTE_RETURN_CHECK; - -int virSetBlocking(int fd, bool blocking) ATTRIBUTE_RETURN_CHECK; -int virSetNonBlock(int fd) ATTRIBUTE_RETURN_CHECK; -int virSetInherit(int fd, bool inherit) ATTRIBUTE_RETURN_CHECK; -int virSetCloseExec(int fd) ATTRIBUTE_RETURN_CHECK; - -int virPipeReadUntilEOF(int outfd, int errfd, - char **outbuf, char **errbuf); - -int virSetUIDGID(uid_t uid, gid_t gid); - -int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; - -int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; - -int virFileWriteStr(const char *path, const char *str, mode_t mode) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; - -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) ATTRIBUTE_RETURN_CHECK; - -int virFileLinkPointsTo(const char *checkLink, - const char *checkDest); - -int virFileResolveLink(const char *linkpath, - char **resultpath) ATTRIBUTE_RETURN_CHECK; -int virFileResolveAllLinks(const char *linkpath, - char **resultpath) ATTRIBUTE_RETURN_CHECK; - -int virFileIsLink(const char *linkpath) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -char *virFindFileInPath(const char *file); - -bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1); -bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1); -bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1); - -char *virFileSanitizePath(const char *path); - -enum { - VIR_FILE_OPEN_NONE = 0, - VIR_FILE_OPEN_NOFORK = (1 << 0), - VIR_FILE_OPEN_FORK = (1 << 1), - VIR_FILE_OPEN_FORCE_MODE = (1 << 2), - VIR_FILE_OPEN_FORCE_OWNER = (1 << 3), -}; -int virFileAccessibleAs(const char *path, int mode, - uid_t uid, gid_t gid) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; -int virFileOpenAs(const char *path, int openflags, mode_t mode, - uid_t uid, gid_t gid, - unsigned int flags) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -enum { - VIR_DIR_CREATE_NONE = 0, - VIR_DIR_CREATE_AS_UID = (1 << 0), - VIR_DIR_CREATE_FORCE_PERMS = (1 << 1), - VIR_DIR_CREATE_ALLOW_EXIST = (1 << 2), -}; -int virDirCreate(const char *path, mode_t mode, uid_t uid, gid_t gid, - unsigned int flags) ATTRIBUTE_RETURN_CHECK; -int virFileMakePath(const char *path) ATTRIBUTE_RETURN_CHECK; -int virFileMakePathWithMode(const char *path, - mode_t mode) ATTRIBUTE_RETURN_CHECK; - -char *virFileBuildPath(const char *dir, - const char *name, - const char *ext) ATTRIBUTE_RETURN_CHECK; - - -# ifdef WIN32 -/* On Win32, the canonical directory separator is the backslash, and - * the search path separator is the semicolon. Note that also the - * (forward) slash works as directory separator. - */ -# define VIR_FILE_DIR_SEPARATOR '\\' -# define VIR_FILE_DIR_SEPARATOR_S "\\" -# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR || (c) == '/') -# define VIR_FILE_PATH_SEPARATOR ';' -# define VIR_FILE_PATH_SEPARATOR_S ";" - -# else /* !WIN32 */ - -# define VIR_FILE_DIR_SEPARATOR '/' -# define VIR_FILE_DIR_SEPARATOR_S "/" -# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR) -# define VIR_FILE_PATH_SEPARATOR ':' -# define VIR_FILE_PATH_SEPARATOR_S ":" - -# endif /* !WIN32 */ - -bool virFileIsAbsPath(const char *path); -int virFileAbsPath(const char *path, - char **abspath) ATTRIBUTE_RETURN_CHECK; -const char *virFileSkipRoot(const char *path); - -int virFileOpenTty(int *ttymaster, - char **ttyName, - int rawmode); - -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_l(char const *s, - char **end_ptr, - int base, - long *result); -int virStrToLong_ul(char const *s, - char **end_ptr, - int base, - unsigned long *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 virScaleInteger(unsigned long long *value, const char *suffix, - unsigned long long scale, unsigned long long limit) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -int virHexToBin(unsigned char c); - -void virSkipSpaces(const char **str) ATTRIBUTE_NONNULL(1); -void virSkipSpacesAndBackslash(const char **str) ATTRIBUTE_NONNULL(1); -void virTrimSpaces(char *str, char **endp) ATTRIBUTE_NONNULL(1); -void virSkipSpacesBackwards(const char *str, char **endp) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -int virParseNumber(const char **str); -int virParseVersionString(const char *str, unsigned long *version, - bool allowMissing); -int virAsprintf(char **strp, const char *fmt, ...) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); -int virVasprintf(char **strp, const char *fmt, va_list list) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 0); -char *virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) - ATTRIBUTE_RETURN_CHECK; -char *virStrcpy(char *dest, const char *src, size_t destbytes) - ATTRIBUTE_RETURN_CHECK; -# define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest)) - -int virDoubleToStr(char **strp, double number) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -char *virFormatIntDecimal(char *buf, size_t buflen, int val) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -int virDiskNameToIndex(const char* str); -char *virIndexToDiskName(int idx, const char *prefix); - -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__ }; \ - verify(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_GETEUID -static inline int geteuid (void) { return 0; } -# endif - -# ifndef HAVE_GETGID -static inline int getgid (void) { return 0; } -# endif - -char *virGetHostname(virConnectPtr conn); - -char *virGetUserDirectory(void); -char *virGetUserConfigDirectory(void); -char *virGetUserCacheDirectory(void); -char *virGetUserRuntimeDirectory(void); -char *virGetUserName(uid_t uid); -char *virGetGroupName(gid_t gid); -int virGetUserID(const char *name, - uid_t *uid) ATTRIBUTE_RETURN_CHECK; -int virGetGroupID(const char *name, - gid_t *gid) ATTRIBUTE_RETURN_CHECK; - -char *virFileFindMountPoint(const char *type); - -void virFileWaitForDevices(void); - -# define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL) -int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL; - -bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1); - -bool virValidateWWN(const char *wwn); - -bool virStrIsPrint(const char *str); -#endif /* __VIR_UTIL_H__ */ diff --git a/src/util/uuid.c b/src/util/uuid.c index 5232ba9..57cfaa6 100644 --- a/src/util/uuid.c +++ b/src/util/uuid.c @@ -35,7 +35,7 @@ #include "c-ctype.h" #include "internal.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virlog.h" #include "viralloc.h" diff --git a/src/util/viraudit.c b/src/util/viraudit.c index a807b76..05189d5 100644 --- a/src/util/viraudit.c +++ b/src/util/viraudit.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "viraudit.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "viralloc.h" diff --git a/src/util/virauth.c b/src/util/virauth.c index c4c5676..cbb16ec 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -25,7 +25,7 @@ #include <stdlib.h> #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "datatypes.h" diff --git a/src/util/virauthconfig.c b/src/util/virauthconfig.c index a0f0be5..d60f7bf 100644 --- a/src/util/virauthconfig.c +++ b/src/util/virauthconfig.c @@ -26,7 +26,7 @@ #include "virkeyfile.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index cb9606b..b4ba3ef 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -33,7 +33,7 @@ #include "virbitmap.h" #include "viralloc.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "count-one-bits.h" diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index 5c628cc..48cba93 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -38,7 +38,7 @@ #include <dirent.h> #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircgroup.h" #include "virlog.h" diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 6e17a8d..d059586 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -36,7 +36,7 @@ #include "vircommand.h" #include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virfile.h" #include "virpidfile.h" diff --git a/src/util/vircommand.h b/src/util/vircommand.h index 4c88165..9b7117d 100644 --- a/src/util/vircommand.h +++ b/src/util/vircommand.h @@ -23,7 +23,7 @@ # define __VIR_COMMAND_H__ # include "internal.h" -# include "util.h" +# include "virutil.h" # include "virbuffer.h" typedef struct _virCommand virCommand; diff --git a/src/util/virconf.c b/src/util/virconf.c index 2f6d60e..7e4c8c1 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virbuffer.h" #include "virconf.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "virlog.h" #include "viralloc.h" diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c index 918610a..6b9abd9 100644 --- a/src/util/virdnsmasq.c +++ b/src/util/virdnsmasq.c @@ -41,7 +41,7 @@ #include "datatypes.h" #include "virbitmap.h" #include "virdnsmasq.h" -#include "util.h" +#include "virutil.h" #include "vircommand.h" #include "viralloc.h" #include "virterror_internal.h" diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index 1180fda..afb0e05 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -35,7 +35,7 @@ #include "virlog.h" #include "vireventpoll.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virterror_internal.h" #include "virtime.h" diff --git a/src/util/virhooks.c b/src/util/virhooks.c index ad3a371..54a869a 100644 --- a/src/util/virhooks.c +++ b/src/util/virhooks.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "virhooks.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/util/virhooks.h b/src/util/virhooks.h index 0ca376f..56573df 100644 --- a/src/util/virhooks.h +++ b/src/util/virhooks.h @@ -25,7 +25,7 @@ # define __VIR_HOOKS_H__ # include "internal.h" -# include "util.h" +# include "virutil.h" enum virHookDriverType { VIR_HOOK_DRIVER_DAEMON = 0, /* Daemon related events */ diff --git a/src/util/virinitctl.c b/src/util/virinitctl.c index 91a948f..f8ac673 100644 --- a/src/util/virinitctl.c +++ b/src/util/virinitctl.c @@ -29,7 +29,7 @@ #include "internal.h" #include "virinitctl.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/util/virjson.c b/src/util/virjson.c index 4fa5363..4c9797c 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #if HAVE_YAJL # include <yajl/yajl_gen.h> diff --git a/src/util/virkeycode.h b/src/util/virkeycode.h index 1522f77..a2e1391 100644 --- a/src/util/virkeycode.h +++ b/src/util/virkeycode.h @@ -22,7 +22,7 @@ #ifndef __VIR_UTIL_VIRTKEYCODE_H__ # define __VIR_UTIL_VIRTKEYCODE_H__ -# include "util.h" +# include "virutil.h" # include "libvirt/libvirt.h" VIR_ENUM_DECL(virKeycodeSet); diff --git a/src/util/virkeyfile.c b/src/util/virkeyfile.c index fc61cf5..99e5cd7 100644 --- a/src/util/virkeyfile.c +++ b/src/util/virkeyfile.c @@ -28,7 +28,7 @@ #include "c-ctype.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virhash.h" #include "virkeyfile.h" #include "virterror_internal.h" diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c index 961e171..81a1d81 100644 --- a/src/util/virlockspace.c +++ b/src/util/virlockspace.c @@ -25,7 +25,7 @@ #include "virlog.h" #include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virhash.h" #include "virthread.h" diff --git a/src/util/virlog.c b/src/util/virlog.c index 0c6c13a..43a59b4 100644 --- a/src/util/virlog.c +++ b/src/util/virlog.c @@ -43,7 +43,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "virthread.h" #include "virfile.h" diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index eb341a2..4de88e3 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -24,7 +24,7 @@ #include "virnetdevbridge.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "viralloc.h" #include "intprops.h" diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 0f7107b..953d76b 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -29,7 +29,7 @@ #include "virnetdevmacvlan.h" #include "virmacaddr.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NET diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h index 147cd6f..3216ea0 100644 --- a/src/util/virnetdevopenvswitch.h +++ b/src/util/virnetdevopenvswitch.h @@ -25,7 +25,7 @@ # define __VIR_NETDEV_OPENVSWITCH_H__ # include "internal.h" -# include "util.h" +# include "virutil.h" # include "virnetdevvportprofile.h" # include "virnetdevvlan.h" diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 339d636..3565bbd 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include <sys/ioctl.h> #include <net/if.h> diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h index c4585a8..cc106b8 100644 --- a/src/util/virnetdevvportprofile.h +++ b/src/util/virnetdevvportprofile.h @@ -25,7 +25,7 @@ # include "internal.h" # include "uuid.h" -# include "util.h" +# include "virutil.h" # include "virmacaddr.h" # define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX 40 diff --git a/src/util/virpidfile.c b/src/util/virpidfile.c index 3b3322b..29097e3 100644 --- a/src/util/virpidfile.c +++ b/src/util/virpidfile.c @@ -30,7 +30,7 @@ #include "virpidfile.h" #include "virfile.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "intprops.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 155e4e2..b276643 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -31,7 +31,7 @@ #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virrandom.c b/src/util/virrandom.c index 1dd96cf..1b6de6b 100644 --- a/src/util/virrandom.c +++ b/src/util/virrandom.c @@ -29,7 +29,7 @@ #include "virrandom.h" #include "virthread.h" #include "count-one-bits.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/util/virsexpr.c b/src/util/virsexpr.c index 80c24c4..8b70404 100644 --- a/src/util/virsexpr.c +++ b/src/util/virsexpr.c @@ -19,7 +19,7 @@ #include "virterror_internal.h" #include "virsexpr.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_SEXPR diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 488ff4b..0f2f23d 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -25,7 +25,7 @@ #include "virsocketaddr.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include <netdb.h> diff --git a/src/util/virstatslinux.c b/src/util/virstatslinux.c index 9359db9..135df75 100644 --- a/src/util/virstatslinux.c +++ b/src/util/virstatslinux.c @@ -34,7 +34,7 @@ # include "virterror_internal.h" # include "datatypes.h" -# include "util.h" +# include "virutil.h" # include "virstatslinux.h" # include "viralloc.h" # include "virfile.h" diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 6fbd275..abf319a 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -24,7 +24,7 @@ #ifndef __VIR_STORAGE_FILE_H__ # define __VIR_STORAGE_FILE_H__ -# include "util.h" +# include "virutil.h" enum virStorageFileFormat { VIR_STORAGE_FILE_AUTO_SAFE = -2, diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c index 13d3c22..88e4f5c 100644 --- a/src/util/virsysinfo.c +++ b/src/util/virsysinfo.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "virsysinfo.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "viralloc.h" #include "vircommand.h" diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h index 0b1f000..dded51b 100644 --- a/src/util/virsysinfo.h +++ b/src/util/virsysinfo.h @@ -25,7 +25,7 @@ # define __VIR_SYSINFOS_H__ # include "internal.h" -# include "util.h" +# include "virutil.h" # include "virbuffer.h" enum virSysinfoType { diff --git a/src/util/virterror.c b/src/util/virterror.c index 6c773d3..a586738 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -32,7 +32,7 @@ #include "virlog.h" #include "viralloc.h" #include "virthread.h" -#include "util.h" +#include "virutil.h" virThreadLocal virLastErr; diff --git a/src/util/virtime.c b/src/util/virtime.c index f9fc282..c614380 100644 --- a/src/util/virtime.c +++ b/src/util/virtime.c @@ -37,7 +37,7 @@ #include <sys/time.h> #include "virtime.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virterror_internal.h" diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index e08530e..60fb485 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -25,7 +25,7 @@ #include <stdarg.h> #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/viruri.c b/src/util/viruri.c index f48079d..e59cd5a 100644 --- a/src/util/viruri.c +++ b/src/util/viruri.c @@ -23,7 +23,7 @@ #include "viruri.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virbuffer.h" diff --git a/src/util/virusb.c b/src/util/virusb.c index 9786e86..c053c44 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -34,7 +34,7 @@ #include "virusb.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #define USB_SYSFS "/sys/bus/usb" diff --git a/src/util/virutil.c b/src/util/virutil.c new file mode 100644 index 0000000..9fb1c6f --- /dev/null +++ b/src/util/virutil.c @@ -0,0 +1,3131 @@ +/* + * utils.c: common, generic utility functions + * + * Copyright (C) 2006-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * 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 <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <poll.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#if HAVE_MMAP +# include <sys/mman.h> +#endif +#include <string.h> +#include <signal.h> +#include <termios.h> +#include <pty.h> +#include <locale.h> + +#if HAVE_LIBDEVMAPPER_H +# include <libdevmapper.h> +#endif + +#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 +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +# include <mntent.h> +#endif + +#ifdef WIN32 +# ifdef HAVE_WINSOCK2_H +# include <winsock2.h> +# endif +# include <windows.h> +# include <shlobj.h> +#endif + +#include "c-ctype.h" +#include "dirname.h" +#include "virterror_internal.h" +#include "virlog.h" +#include "virbuffer.h" +#include "virutil.h" +#include "virstoragefile.h" +#include "viralloc.h" +#include "virthread.h" +#include "verify.h" +#include "virfile.h" +#include "vircommand.h" +#include "nonblocking.h" +#include "passfd.h" +#include "virprocess.h" + +#ifndef NSIG +# define NSIG 32 +#endif + +verify(sizeof(gid_t) <= sizeof(unsigned int) && + sizeof(uid_t) <= sizeof(unsigned int)); + +#define VIR_FROM_THIS VIR_FROM_NONE + +/* Like read(), but restarts after EINTR */ +ssize_t +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, off_t offset, off_t len) +{ + int ret = posix_fallocate(fd, offset, len); + if (ret == 0) + return 0; + errno = ret; + return -1; +} +#else + +# ifdef HAVE_MMAP +int safezero(int fd, 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 -1; + + buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); + if (buf == MAP_FAILED) + return -1; + + memset(buf, 0, len); + munmap(buf, len); + + return 0; +} + +# else /* HAVE_MMAP */ + +int safezero(int fd, off_t offset, off_t len) +{ + int r; + char *buf; + unsigned long long remain, bytes; + + if (lseek(fd, offset, SEEK_SET) < 0) + return -1; + + /* 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) { + errno = ENOMEM; + return -1; + } + + while (remain) { + if (bytes > remain) + bytes = remain; + + r = safewrite(fd, buf, bytes); + if (r < 0) { + VIR_FREE(buf); + return -1; + } + + /* safewrite() guarantees all data will be written */ + remain -= bytes; + } + VIR_FREE(buf); + return 0; +} +# endif /* HAVE_MMAP */ +#endif /* HAVE_POSIX_FALLOCATE */ + +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; +} + +#ifndef WIN32 + +int virSetInherit(int fd, bool inherit) { + int fflags; + if ((fflags = fcntl(fd, F_GETFD)) < 0) + return -1; + if (inherit) + fflags &= ~FD_CLOEXEC; + else + fflags |= FD_CLOEXEC; + if ((fcntl(fd, F_SETFD, fflags)) < 0) + return -1; + return 0; +} + +#else /* WIN32 */ + +int virSetInherit(int fd ATTRIBUTE_UNUSED, bool inherit ATTRIBUTE_UNUSED) +{ + /* FIXME: Currently creating child processes is not supported on + * Win32, so there is no point in failing calls that are only relevant + * when creating child processes. So just pretend that we changed the + * inheritance property of the given fd as requested. */ + return 0; +} + +#endif /* WIN32 */ + +int virSetBlocking(int fd, bool blocking) { + return set_nonblocking_flag(fd, !blocking); +} + +int virSetNonBlock(int fd) { + return virSetBlocking(fd, false); +} + +int virSetCloseExec(int fd) +{ + return virSetInherit(fd, false); +} + +int +virPipeReadUntilEOF(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; + fds[0].revents = 0; + finished[0] = 0; + fds[1].fd = errfd; + fds[1].events = POLLIN; + fds[1].revents = 0; + 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; + + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Unknown poll response.")); + goto error; + } + + got = read(fds[i].fd, data, sizeof(data)); + + if (got == sizeof(data)) + finished[i] = 0; + + 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(); + goto error; + } + memmove(*buf+size, data, got); + (*buf)[size+got] = '\0'; + } + continue; + + pollerr: + virReportSystemError(errno, + "%s", _("poll error")); + goto error; + } + + return 0; + +error: + VIR_FREE(*outbuf); + VIR_FREE(*errbuf); + return -1; +} + +/* 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 * +saferead_lim(int fd, size_t max_len, size_t *length) +{ + char *buf = NULL; + size_t alloc = 0; + size_t size = 0; + int save_errno; + + for (;;) { + int count; + int 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 = saferead(fd, buf + size, requested); + size += count; + + if (count != requested || requested == 0) { + save_errno = errno; + if (count < 0) + break; + buf[size] = '\0'; + *length = size; + return buf; + } + } + + VIR_FREE(buf); + errno = save_errno; + return NULL; +} + +/* A wrapper around saferead_lim that maps a failure due to + exceeding the maximum size limitation to EOVERFLOW. */ +int +virFileReadLimFD(int fd, int maxlen, char **buf) +{ + size_t len; + char *s; + + if (maxlen <= 0) { + errno = EINVAL; + return -1; + } + s = saferead_lim(fd, 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; +} + +int virFileReadAll(const char *path, int maxlen, char **buf) +{ + int fd = open(path, O_RDONLY); + if (fd < 0) { + virReportSystemError(errno, _("Failed to open file '%s'"), path); + return -1; + } + + int len = virFileReadLimFD(fd, maxlen, buf); + VIR_FORCE_CLOSE(fd); + if (len < 0) { + virReportSystemError(errno, _("Failed to read file '%s'"), path); + return -1; + } + + return len; +} + +/* Truncate @path and write @str to it. If @mode is 0, ensure that + @path exists; otherwise, use @mode if @path must be created. + Return 0 for success, nonzero for failure. + Be careful to preserve any errno value upon failure. */ +int virFileWriteStr(const char *path, const char *str, mode_t mode) +{ + int fd; + + if (mode) + fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode); + else + fd = open(path, O_WRONLY|O_TRUNC); + if (fd == -1) + return -1; + + if (safewrite(fd, str, strlen(str)) < 0) { + VIR_FORCE_CLOSE(fd); + return -1; + } + + /* Use errno from failed close only if there was no write error. */ + if (VIR_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 STRCASEEQ(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)); +} + + + +static int +virFileResolveLinkHelper(const char *linkpath, + bool intermediatePaths, + char **resultpath) +{ + struct stat st; + + *resultpath = NULL; + + /* We don't need the full canonicalization of intermediate + * directories, if linkpath is absolute and the basename is + * already a non-symlink. */ + if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) { + if (lstat(linkpath, &st) < 0) + return -1; + + if (!S_ISLNK(st.st_mode)) { + if (!(*resultpath = strdup(linkpath))) + return -1; + return 0; + } + } + + *resultpath = canonicalize_file_name(linkpath); + + return *resultpath == NULL ? -1 : 0; +} + +/* + * Attempt to resolve a symbolic link, returning an + * absolute path where only the last component is guaranteed + * not to be a symlink. + * + * Return 0 if path was not a symbolic, or the link was + * resolved. Return -1 with errno set upon error + */ +int virFileResolveLink(const char *linkpath, + char **resultpath) +{ + return virFileResolveLinkHelper(linkpath, false, resultpath); +} + +/* + * Attempt to resolve a symbolic link, returning an + * absolute path where every component is guaranteed + * not to be a symlink. + * + * Return 0 if path was not a symbolic, or the link was + * resolved. Return -1 with errno set upon error + */ +int virFileResolveAllLinks(const char *linkpath, + char **resultpath) +{ + return virFileResolveLinkHelper(linkpath, true, resultpath); +} + +/* + * Check whether the given file is a link. + * Returns 1 in case of the file being a link, 0 in case it is not + * a link and the negative errno in all other cases. + */ +int virFileIsLink(const char *linkpath) +{ + struct stat st; + + if (lstat(linkpath, &st) < 0) + return -errno; + + return S_ISLNK(st.st_mode) != 0; +} + + +/* + * Finds a requested executable 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 *path = NULL; + char *pathiter; + char *pathseg; + char *fullpath = NULL; + + if (file == NULL) + return NULL; + + /* if we are passed an absolute path (starting with /), return a + * copy of that path, after validating that it is executable + */ + if (IS_ABSOLUTE_FILE_NAME(file)) { + if (virFileIsExecutable(file)) + return strdup(file); + else + return NULL; + } + + /* If we are passed an anchored path (containing a /), then there + * is no path search - it must exist in the current directory + */ + if (strchr(file, '/')) { + if (virFileIsExecutable(file)) + ignore_value(virFileAbsPath(file, &path)); + return path; + } + + /* copy PATH env so we can tweak it */ + path = getenv("PATH"); + + if (path == NULL || (path = strdup(path)) == NULL) + return NULL; + + /* for each path segment, append the file to search for and test for + * it. return it if found. + */ + pathiter = path; + while ((pathseg = strsep(&pathiter, ":")) != NULL) { + if (virAsprintf(&fullpath, "%s/%s", pathseg, file) < 0 || + virFileIsExecutable(fullpath)) + break; + VIR_FREE(fullpath); + } + + VIR_FREE(path); + return fullpath; +} + +bool virFileIsDir(const char *path) +{ + struct stat s; + return (stat(path, &s) == 0) && S_ISDIR(s.st_mode); +} + +bool virFileExists(const char *path) +{ + return access(path, F_OK) == 0; +} + +/* Check that a file is regular and has executable bits. If false is + * returned, errno is valid. + * + * Note: In the presence of ACLs, this may return true for a file that + * would actually fail with EACCES for a given user, or false for a + * file that the user could actually execute, but setups with ACLs + * that weird are unusual. */ +bool +virFileIsExecutable(const char *file) +{ + struct stat sb; + + /* We would also want to check faccessat if we cared about ACLs, + * but we don't. */ + if (stat(file, &sb) < 0) + return false; + if (S_ISREG(sb.st_mode) && (sb.st_mode & 0111) != 0) + return true; + errno = S_ISDIR(sb.st_mode) ? EISDIR : EACCES; + return false; +} + +#ifndef WIN32 +/* Check that a file is accessible under certain + * user & gid. + * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK. + * see 'man access' for more details. + * Returns 0 on success, -1 on fail with errno set. + */ +int +virFileAccessibleAs(const char *path, int mode, + uid_t uid, gid_t gid) +{ + pid_t pid = 0; + int status, ret = 0; + int forkRet = 0; + + if (uid == getuid() && + gid == getgid()) + return access(path, mode); + + forkRet = virFork(&pid); + + if (pid < 0) { + return -1; + } + + if (pid) { /* parent */ + if (virProcessWait(pid, &status) < 0) { + /* virProcessWait() already + * reported error */ + return -1; + } + + if (!WIFEXITED(status)) { + errno = EINTR; + return -1; + } + + if (status) { + errno = WEXITSTATUS(status); + return -1; + } + + return 0; + } + + /* child. + * Return positive value here. Parent + * will change it to negative one. */ + + if (forkRet < 0) { + ret = errno; + goto childerror; + } + + if (virSetUIDGID(uid, gid) < 0) { + ret = errno; + goto childerror; + } + + if (access(path, mode) < 0) + ret = errno; + +childerror: + if ((ret & 0xFF) != ret) { + VIR_WARN("unable to pass desired return value %d", ret); + ret = 0xFF; + } + + _exit(ret); +} + +/* virFileOpenForceOwnerMode() - an internal utility function called + * only by virFileOpenAs(). Sets the owner and mode of the file + * opened as "fd" if it's not correct AND the flags say it should be + * forced. */ +static int +virFileOpenForceOwnerMode(const char *path, int fd, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) +{ + int ret = 0; + struct stat st; + + if (!(flags & (VIR_FILE_OPEN_FORCE_OWNER | VIR_FILE_OPEN_FORCE_MODE))) + return 0; + + if (fstat(fd, &st) == -1) { + ret = -errno; + virReportSystemError(errno, _("stat of '%s' failed"), path); + return ret; + } + /* NB: uid:gid are never "-1" (default) at this point - the caller + * has always changed -1 to the value of get[gu]id(). + */ + if ((flags & VIR_FILE_OPEN_FORCE_OWNER) && + ((st.st_uid != uid) || (st.st_gid != gid)) && + (fchown(fd, uid, gid) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot chown '%s' to (%u, %u)"), + path, (unsigned int) uid, + (unsigned int) gid); + return ret; + } + if ((flags & VIR_FILE_OPEN_FORCE_MODE) && + ((mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != + (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) && + (fchmod(fd, mode) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot set mode of '%s' to %04o"), + path, mode); + return ret; + } + return ret; +} + +/* virFileOpenForked() - an internal utility function called only by + * virFileOpenAs(). It forks, then the child does setuid+setgid to + * given uid:gid and attempts to open the file, while the parent just + * calls recvfd to get the open fd back from the child. returns the + * fd, or -errno if there is an error. */ +static int +virFileOpenForked(const char *path, int openflags, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) +{ + pid_t pid; + int waitret, status, ret = 0; + int fd = -1; + int pair[2] = { -1, -1 }; + int forkRet; + + /* parent is running as root, but caller requested that the + * file be opened as some other user and/or group). The + * following dance avoids problems caused by root-squashing + * NFS servers. */ + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { + ret = -errno; + virReportSystemError(errno, + _("failed to create socket needed for '%s'"), + path); + return ret; + } + + forkRet = virFork(&pid); + if (pid < 0) + return -errno; + + if (pid == 0) { + + /* child */ + + VIR_FORCE_CLOSE(pair[0]); /* preserves errno */ + if (forkRet < 0) { + /* error encountered and logged in virFork() after the fork. */ + ret = -errno; + goto childerror; + } + + /* set desired uid/gid, then attempt to create the file */ + + if (virSetUIDGID(uid, gid) < 0) { + ret = -errno; + goto childerror; + } + + if ((fd = open(path, openflags, mode)) < 0) { + ret = -errno; + virReportSystemError(errno, + _("child process failed to create file '%s'"), + path); + goto childerror; + } + + /* File is successfully open. Set permissions if requested. */ + ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); + if (ret < 0) + goto childerror; + + do { + ret = sendfd(pair[1], fd); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + ret = -errno; + virReportSystemError(errno, "%s", + _("child process failed to send fd to parent")); + goto childerror; + } + + childerror: + /* ret tracks -errno on failure, but exit value must be positive. + * If the child exits with EACCES, then the parent tries again. */ + /* XXX This makes assumptions about errno being < 255, which is + * not true on Hurd. */ + VIR_FORCE_CLOSE(pair[1]); + if (ret < 0) { + VIR_FORCE_CLOSE(fd); + } + ret = -ret; + if ((ret & 0xff) != ret) { + VIR_WARN("unable to pass desired return value %d", ret); + ret = 0xff; + } + _exit(ret); + } + + /* parent */ + + VIR_FORCE_CLOSE(pair[1]); + + do { + fd = recvfd(pair[0], 0); + } while (fd < 0 && errno == EINTR); + VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */ + + if (fd < 0 && errno != EACCES) { + ret = -errno; + while (waitpid(pid, NULL, 0) == -1 && errno == EINTR); + return ret; + } + + /* wait for child to complete, and retrieve its exit code */ + while ((waitret = waitpid(pid, &status, 0) == -1) + && (errno == EINTR)); + if (waitret == -1) { + ret = -errno; + virReportSystemError(errno, + _("failed to wait for child creating '%s'"), + path); + VIR_FORCE_CLOSE(fd); + return ret; + } + if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES || + fd == -1) { + /* fall back to the simpler method, which works better in + * some cases */ + VIR_FORCE_CLOSE(fd); + if (flags & VIR_FILE_OPEN_NOFORK) { + /* If we had already tried opening w/o fork+setuid and + * failed, no sense trying again. Just set return the + * original errno that we got at that time (by + * definition, always either EACCES or EPERM - EACCES + * is close enough). + */ + return -EACCES; + } + if ((fd = open(path, openflags, mode)) < 0) + return -errno; + ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); + if (ret < 0) { + VIR_FORCE_CLOSE(fd); + return ret; + } + } + return fd; +} + +/** + * virFileOpenAs: + * @path: file to open or create + * @openflags: flags to pass to open + * @mode: mode to use on creation or when forcing permissions + * @uid: uid that should own file on creation + * @gid: gid that should own file + * @flags: bit-wise or of VIR_FILE_OPEN_* flags + * + * Open @path, and return an fd to the open file. @openflags contains + * the flags normally passed to open(2), while those in @flags are + * used internally. If @flags includes VIR_FILE_OPEN_NOFORK, then try + * opening the file while executing with the current uid:gid + * (i.e. don't fork+setuid+setgid before the call to open()). If + * @flags includes VIR_FILE_OPEN_FORK, then try opening the file while + * the effective user id is @uid (by forking a child process); this + * allows one to bypass root-squashing NFS issues; NOFORK is always + * tried before FORK (the absence of both flags is treated identically + * to (VIR_FILE_OPEN_NOFORK | VIR_FILE_OPEN_FORK)). If @flags includes + * VIR_FILE_OPEN_FORCE_OWNER, then ensure that @path is owned by + * uid:gid before returning (even if it already existed with a + * different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE, + * ensure it has those permissions before returning (again, even if + * the file already existed with different permissions). The return + * value (if non-negative) is the file descriptor, left open. Returns + * -errno on failure. */ +int +virFileOpenAs(const char *path, int openflags, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) +{ + int ret = 0, fd = -1; + + /* allow using -1 to mean "current value" */ + if (uid == (uid_t) -1) + uid = getuid(); + if (gid == (gid_t) -1) + gid = getgid(); + + /* treat absence of both flags as presence of both for simpler + * calling. */ + if (!(flags & (VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK))) + flags |= VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK; + + if ((flags & VIR_FILE_OPEN_NOFORK) + || (getuid() != 0) + || ((uid == 0) && (gid == 0))) { + + if ((fd = open(path, openflags, mode)) < 0) { + ret = -errno; + } else { + ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); + if (ret < 0) + goto error; + } + } + + /* If we either 1) didn't try opening as current user at all, or + * 2) failed, and errno/virStorageFileIsSharedFS indicate we might + * be successful if we try as a different uid, then try doing + * fork+setuid+setgid before opening. + */ + if ((fd < 0) && (flags & VIR_FILE_OPEN_FORK)) { + + if (ret < 0) { + /* An open(2) that failed due to insufficient permissions + * could return one or the other of these depending on OS + * version and circumstances. Any other errno indicates a + * problem that couldn't be remedied by fork+setuid + * anyway. */ + if (ret != -EACCES && ret != -EPERM) + goto error; + + /* On Linux we can also verify the FS-type of the + * directory. (this is a NOP on other platforms). */ + switch (virStorageFileIsSharedFS(path)) { + case 1: + /* it was on a network share, so we'll re-try */ + break; + case -1: + /* failure detecting fstype */ + virReportSystemError(errno, _("couldn't determine fs type " + "of mount containing '%s'"), path); + goto error; + case 0: + default: + /* file isn't on a recognized network FS */ + goto error; + } + } + + /* passed all prerequisites - retry the open w/fork+setuid */ + if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) { + ret = fd; + fd = -1; + goto error; + } + } + + /* File is successfully opened */ + + return fd; + +error: + if (fd < 0) { + /* whoever failed the open last has already set ret = -errno */ + virReportSystemError(-ret, openflags & O_CREAT + ? _("failed to create file '%s'") + : _("failed to open file '%s'"), + path); + } else { + /* some other failure after the open succeeded */ + VIR_FORCE_CLOSE(fd); + } + return ret; +} + +/* return -errno on failure, or 0 on success */ +static int virDirCreateNoFork(const char *path, mode_t mode, uid_t uid, gid_t gid, + unsigned int flags) { + int ret = 0; + struct stat st; + + if ((mkdir(path, mode) < 0) + && !((errno == EEXIST) && (flags & VIR_DIR_CREATE_ALLOW_EXIST))) { + ret = -errno; + virReportSystemError(errno, _("failed to create directory '%s'"), + path); + goto error; + } + + if (stat(path, &st) == -1) { + ret = -errno; + virReportSystemError(errno, _("stat of '%s' failed"), path); + goto error; + } + if (((st.st_uid != uid) || (st.st_gid != gid)) + && (chown(path, uid, gid) < 0)) { + ret = -errno; + virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"), + path, (unsigned int) uid, (unsigned int) gid); + goto error; + } + if ((flags & VIR_DIR_CREATE_FORCE_PERMS) + && (chmod(path, mode) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot set mode of '%s' to %04o"), + path, mode); + goto error; + } +error: + return ret; +} + +/* return -errno on failure, or 0 on success */ +int virDirCreate(const char *path, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) { + struct stat st; + pid_t pid; + int waitret; + int status, ret = 0; + + /* allow using -1 to mean "current value" */ + if (uid == (uid_t) -1) + uid = getuid(); + if (gid == (gid_t) -1) + gid = getgid(); + + if ((!(flags & VIR_DIR_CREATE_AS_UID)) + || (getuid() != 0) + || ((uid == 0) && (gid == 0)) + || ((flags & VIR_DIR_CREATE_ALLOW_EXIST) && (stat(path, &st) >= 0))) { + return virDirCreateNoFork(path, mode, uid, gid, flags); + } + + int forkRet = virFork(&pid); + + if (pid < 0) { + ret = -errno; + return ret; + } + + if (pid) { /* parent */ + /* wait for child to complete, and retrieve its exit code */ + while ((waitret = waitpid(pid, &status, 0) == -1) && (errno == EINTR)); + if (waitret == -1) { + ret = -errno; + virReportSystemError(errno, + _("failed to wait for child creating '%s'"), + path); + goto parenterror; + } + if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) { + /* fall back to the simpler method, which works better in + * some cases */ + return virDirCreateNoFork(path, mode, uid, gid, flags); + } +parenterror: + return ret; + } + + /* child */ + + if (forkRet < 0) { + /* error encountered and logged in virFork() after the fork. */ + goto childerror; + } + + /* set desired uid/gid, then attempt to create the directory */ + + if (virSetUIDGID(uid, gid) < 0) { + ret = -errno; + goto childerror; + } + if (mkdir(path, mode) < 0) { + ret = -errno; + if (ret != -EACCES) { + /* in case of EACCES, the parent will retry */ + virReportSystemError(errno, _("child failed to create directory '%s'"), + path); + } + goto childerror; + } + /* check if group was set properly by creating after + * setgid. If not, try doing it with chown */ + if (stat(path, &st) == -1) { + ret = -errno; + virReportSystemError(errno, + _("stat of '%s' failed"), path); + goto childerror; + } + if ((st.st_gid != gid) && (chown(path, -1, gid) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot chown '%s' to group %u"), + path, (unsigned int) gid); + goto childerror; + } + if ((flags & VIR_DIR_CREATE_FORCE_PERMS) + && chmod(path, mode) < 0) { + virReportSystemError(errno, + _("cannot set mode of '%s' to %04o"), + path, mode); + goto childerror; + } +childerror: + _exit(ret); +} + +#else /* WIN32 */ + +int +virFileAccessibleAs(const char *path, + int mode, + uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED) +{ + + VIR_WARN("Ignoring uid/gid due to WIN32"); + + return access(path, mode); +} + +/* return -errno on failure, or 0 on success */ +int virFileOpenAs(const char *path ATTRIBUTE_UNUSED, + int openflags ATTRIBUTE_UNUSED, + mode_t mode ATTRIBUTE_UNUSED, + uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED, + unsigned int flags_unused ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virFileOpenAs is not implemented for WIN32")); + + return -ENOSYS; +} + +int virDirCreate(const char *path ATTRIBUTE_UNUSED, + mode_t mode ATTRIBUTE_UNUSED, + uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED, + unsigned int flags_unused ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virDirCreate is not implemented for WIN32")); + + return -ENOSYS; +} +#endif /* WIN32 */ + +static int virFileMakePathHelper(char *path, mode_t mode) +{ + struct stat st; + char *p; + + VIR_DEBUG("path=%s mode=0%o", path, mode); + + if (stat(path, &st) >= 0) { + if (S_ISDIR(st.st_mode)) + return 0; + + errno = ENOTDIR; + return -1; + } + + if (errno != ENOENT) + return -1; + + if ((p = strrchr(path, '/')) == NULL) { + errno = EINVAL; + return -1; + } + + if (p != path) { + *p = '\0'; + + if (virFileMakePathHelper(path, mode) < 0) + return -1; + + *p = '/'; + } + + if (mkdir(path, mode) < 0 && errno != EEXIST) + return -1; + + return 0; +} + +/** + * Creates the given directory with mode 0777 if it's not already existing. + * + * Returns 0 on success, or -1 if an error occurred (in which case, errno + * is set appropriately). + */ +int virFileMakePath(const char *path) +{ + return virFileMakePathWithMode(path, 0777); +} + +int +virFileMakePathWithMode(const char *path, + mode_t mode) +{ + int ret = -1; + char *tmp; + + if ((tmp = strdup(path)) == NULL) + goto cleanup; + + ret = virFileMakePathHelper(tmp, mode); + +cleanup: + VIR_FREE(tmp); + return ret; +} + +/* Build up a fully qualified path for a config file to be + * associated with a persistent guest or network */ +char * +virFileBuildPath(const char *dir, const char *name, const char *ext) +{ + char *path; + + if (ext == NULL) { + if (virAsprintf(&path, "%s/%s", dir, name) < 0) { + virReportOOMError(); + return NULL; + } + } else { + if (virAsprintf(&path, "%s/%s%s", dir, name, ext) < 0) { + virReportOOMError(); + return NULL; + } + } + + return path; +} + +/* Open a non-blocking master side of a pty. If ttyName is not NULL, + * then populate it with the name of the slave. If rawmode is set, + * also put the master side into raw mode before returning. */ +#ifndef WIN32 +int virFileOpenTty(int *ttymaster, + char **ttyName, + int rawmode) +{ + /* XXX A word of caution - on some platforms (Solaris and HP-UX), + * additional ioctl() calls are needs after opening the slave + * before it will cause isatty() to return true. Should we make + * virFileOpenTty also return the opened slave fd, so the caller + * doesn't have to worry about that mess? */ + int ret = -1; + int slave = -1; + char *name = NULL; + + /* Unfortunately, we can't use the name argument of openpty, since + * there is no guarantee on how large the buffer has to be. + * Likewise, we can't use the termios argument: we have to use + * read-modify-write since there is no portable way to initialize + * a struct termios without use of tcgetattr. */ + if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0) + return -1; + + /* What a shame that openpty cannot atomically set FD_CLOEXEC, but + * that using posix_openpt/grantpt/unlockpt/ptsname is not + * thread-safe, and that ptsname_r is not portable. */ + if (virSetNonBlock(*ttymaster) < 0 || + virSetCloseExec(*ttymaster) < 0) + goto cleanup; + + /* While Linux supports tcgetattr on either the master or the + * slave, Solaris requires it to be on the slave. */ + if (rawmode) { + struct termios ttyAttr; + if (tcgetattr(slave, &ttyAttr) < 0) + goto cleanup; + + cfmakeraw(&ttyAttr); + + if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0) + goto cleanup; + } + + /* ttyname_r on the slave is required by POSIX, while ptsname_r on + * the master is a glibc extension, and the POSIX ptsname is not + * thread-safe. Since openpty gave us both descriptors, guess + * which way we will determine the name? :) */ + if (ttyName) { + /* Initial guess of 64 is generally sufficient; rely on ERANGE + * to tell us if we need to grow. */ + size_t len = 64; + int rc; + + if (VIR_ALLOC_N(name, len) < 0) + goto cleanup; + + while ((rc = ttyname_r(slave, name, len)) == ERANGE) { + if (VIR_RESIZE_N(name, len, len, len) < 0) + goto cleanup; + } + if (rc != 0) { + errno = rc; + goto cleanup; + } + *ttyName = name; + name = NULL; + } + + ret = 0; + +cleanup: + if (ret != 0) + VIR_FORCE_CLOSE(*ttymaster); + VIR_FORCE_CLOSE(slave); + VIR_FREE(name); + + return ret; +} +#else /* WIN32 */ +int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED, + char **ttyName ATTRIBUTE_UNUSED, + int rawmode ATTRIBUTE_UNUSED) +{ + /* mingw completely lacks pseudo-terminals, and the gnulib + * replacements are not (yet) license compatible. */ + errno = ENOSYS; + return -1; +} +#endif /* WIN32 */ + +bool virFileIsAbsPath(const char *path) +{ + if (!path) + return false; + + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + return true; + +#ifdef WIN32 + if (c_isalpha(path[0]) && + path[1] == ':' && + VIR_FILE_IS_DIR_SEPARATOR(path[2])) + return true; +#endif + + return false; +} + + +const char *virFileSkipRoot(const char *path) +{ +#ifdef WIN32 + /* Skip \\server\share or //server/share */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) && + VIR_FILE_IS_DIR_SEPARATOR(path[1]) && + path[2] && + !VIR_FILE_IS_DIR_SEPARATOR(path[2])) + { + const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR); + const char *q = strchr(path + 2, '/'); + + if (p == NULL || (q != NULL && q < p)) + p = q; + + if (p && p > path + 2 && p[1]) { + path = p + 1; + + while (path[0] && + !VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + /* Possibly skip a backslash after the share name */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + return path; + } + } +#endif + + /* Skip initial slashes */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) { + while (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + return path; + } + +#ifdef WIN32 + /* Skip X:\ */ + if (c_isalpha(path[0]) && + path[1] == ':' && + VIR_FILE_IS_DIR_SEPARATOR(path[2])) + return path + 3; +#endif + + return path; +} + + + +/* + * Creates an absolute path for a potentially relative path. + * Return 0 if the path was not relative, or on success. + * Return -1 on error. + * + * You must free the result. + */ +int virFileAbsPath(const char *path, char **abspath) +{ + char *buf; + + if (path[0] == '/') { + if (!(*abspath = strdup(path))) + return -1; + } else { + buf = getcwd(NULL, 0); + if (buf == NULL) + return -1; + + if (virAsprintf(abspath, "%s/%s", buf, path) < 0) { + VIR_FREE(buf); + return -1; + } + VIR_FREE(buf); + } + + return 0; +} + +/* Remove spurious / characters from a path. The result must be freed */ +char * +virFileSanitizePath(const char *path) +{ + const char *cur = path; + char *cleanpath; + int idx = 0; + + cleanpath = strdup(path); + if (!cleanpath) { + virReportOOMError(); + return NULL; + } + + /* Need to sanitize: + * // -> // + * /// -> / + * /../foo -> /../foo + * /foo///bar/ -> /foo/bar + */ + + /* Starting with // is valid posix, but ///foo == /foo */ + if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') { + idx = 2; + cur += 2; + } + + /* Sanitize path in place */ + while (*cur != '\0') { + if (*cur != '/') { + cleanpath[idx++] = *cur++; + continue; + } + + /* Skip all extra / */ + while (*++cur == '/') + continue; + + /* Don't add a trailing / */ + if (idx != 0 && *cur == '\0') + break; + + cleanpath[idx++] = '/'; + } + cleanpath[idx] = '\0'; + + return cleanpath; +} + +/* 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); /* exempt from syntax-check */ + 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); /* exempt from syntax-check */ + 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 a "long" value. */ +int +virStrToLong_l(char const *s, char **end_ptr, int base, long *result) +{ + long int val; + char *p; + int err; + + errno = 0; + val = strtol(s, &p, base); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + if (end_ptr) + *end_ptr = p; + if (err) + return -1; + *result = val; + return 0; +} + +/* Just like virStrToLong_i, above, but produce an "unsigned long" value. */ +int +virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result) +{ + unsigned long int val; + char *p; + int err; + + errno = 0; + val = strtoul(s, &p, base); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + if (end_ptr) + *end_ptr = p; + if (err) + return -1; + *result = val; + return 0; +} + +/* Just like virStrToLong_i, above, but produce a "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); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + 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); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + 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); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + if (end_ptr) + *end_ptr = p; + if (err) + return -1; + *result = val; + return 0; +} + +/* Convert C from hexadecimal character to integer. */ +int +virHexToBin(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; + } +} + +/* Scale an integer VALUE in-place by an optional case-insensitive + * SUFFIX, defaulting to SCALE if suffix is NULL or empty (scale is + * typically 1 or 1024). Recognized suffixes include 'b' or 'bytes', + * as well as power-of-two scaling via binary abbreviations ('KiB', + * 'MiB', ...) or their one-letter counterpart ('k', 'M', ...), and + * power-of-ten scaling via SI abbreviations ('KB', 'MB', ...). + * Ensure that the result does not exceed LIMIT. Return 0 on success, + * -1 with error message raised on failure. */ +int +virScaleInteger(unsigned long long *value, const char *suffix, + unsigned long long scale, unsigned long long limit) +{ + if (!suffix || !*suffix) { + if (!scale) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid scale %llu"), scale); + return -1; + } + suffix = ""; + } else if (STRCASEEQ(suffix, "b") || STRCASEEQ(suffix, "byte") || + STRCASEEQ(suffix, "bytes")) { + scale = 1; + } else { + int base; + + if (!suffix[1] || STRCASEEQ(suffix + 1, "iB")) { + base = 1024; + } else if (c_tolower(suffix[1]) == 'b' && !suffix[2]) { + base = 1000; + } else { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown suffix '%s'"), suffix); + return -1; + } + scale = 1; + switch (c_tolower(*suffix)) { + case 'e': + scale *= base; + /* fallthrough */ + case 'p': + scale *= base; + /* fallthrough */ + case 't': + scale *= base; + /* fallthrough */ + case 'g': + scale *= base; + /* fallthrough */ + case 'm': + scale *= base; + /* fallthrough */ + case 'k': + scale *= base; + break; + default: + virReportError(VIR_ERR_INVALID_ARG, + _("unknown suffix '%s'"), suffix); + return -1; + } + } + + if (*value && *value >= (limit / scale)) { + virReportError(VIR_ERR_OVERFLOW, _("value too large: %llu%s"), + *value, suffix); + return -1; + } + *value *= scale; + return 0; +} + +/** + * virSkipSpaces: + * @str: pointer to the char pointer used + * + * Skip potential blanks, this includes space tabs, line feed, + * carriage returns. + */ +void +virSkipSpaces(const char **str) +{ + const char *cur = *str; + + while (c_isspace(*cur)) + cur++; + *str = cur; +} + +/** + * virSkipSpacesAndBackslash: + * @str: pointer to the char pointer used + * + * Like virSkipSpaces, but also skip backslashes erroneously emitted + * by xend + */ +void +virSkipSpacesAndBackslash(const char **str) +{ + const char *cur = *str; + + while (c_isspace(*cur) || *cur == '\\') + cur++; + *str = cur; +} + +/** + * virTrimSpaces: + * @str: string to modify to remove all trailing spaces + * @endp: track the end of the string + * + * If @endp is NULL on entry, then all spaces prior to the trailing + * NUL in @str are removed, by writing NUL into the appropriate + * location. If @endp is non-NULL but points to a NULL pointer, + * then all spaces prior to the trailing NUL in @str are removed, + * NUL is written to the new string end, and endp is set to the + * location of the (new) string end. If @endp is non-NULL and + * points to a non-NULL pointer, then that pointer is used as + * the end of the string, endp is set to the (new) location, but + * no NUL pointer is written into the string. + */ +void +virTrimSpaces(char *str, char **endp) +{ + char *end; + + if (!endp || !*endp) + end = str + strlen(str); + else + end = *endp; + while (end > str && c_isspace(end[-1])) + end--; + if (endp) { + if (!*endp) + *end = '\0'; + *endp = end; + } else { + *end = '\0'; + } +} + +/** + * virSkipSpacesBackwards: + * @str: start of string + * @endp: on entry, *endp must be NULL or a location within @str, on exit, + * will be adjusted to skip trailing spaces, or to NULL if @str had nothing + * but spaces. + */ +void +virSkipSpacesBackwards(const char *str, char **endp) +{ + /* Casting away const is safe, since virTrimSpaces does not + * modify string with this particular usage. */ + char *s = (char*) str; + + if (!*endp) + *endp = s + strlen(s); + virTrimSpaces(s, endp); + if (s == *endp) + *endp = NULL; +} + +/** + * 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; +} + + +/** + * virParseVersionString: + * @str: const char pointer to the version string + * @version: unsigned long pointer to output the version number + * @allowMissing: true to treat 3 like 3.0.0, false to error out on + * missing minor or micro + * + * Parse an unsigned version number from a version string. Expecting + * 'major.minor.micro' format, ignoring an optional suffix. + * + * The major, minor and micro numbers are encoded into a single version number: + * + * 1000000 * major + 1000 * minor + micro + * + * Returns the 0 for success, -1 for error. + */ +int +virParseVersionString(const char *str, unsigned long *version, + bool allowMissing) +{ + unsigned int major, minor = 0, micro = 0; + char *tmp; + + if (virStrToLong_ui(str, &tmp, 10, &major) < 0) + return -1; + + if (!allowMissing && *tmp != '.') + return -1; + + if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, &minor) < 0) + return -1; + + if (!allowMissing && *tmp != '.') + return -1; + + if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, µ) < 0) + return -1; + + if (major > UINT_MAX / 1000000 || minor > 999 || micro > 999) + return -1; + + *version = 1000000 * major + 1000 * minor + micro; + + return 0; +} + +/** + * virVasprintf + * + * like glibc's vasprintf but makes sure *strp == NULL on failure + */ +int +virVasprintf(char **strp, const char *fmt, va_list list) +{ + int ret; + + if ((ret = vasprintf(strp, fmt, list)) == -1) + *strp = NULL; + + 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); + ret = virVasprintf(strp, fmt, ap); + va_end(ap); + return ret; +} + +/** + * virStrncpy + * + * A safe version of strncpy. The last parameter is the number of bytes + * available in the destination string, *not* the number of bytes you want + * to copy. If the destination is not large enough to hold all n of the + * src string bytes plus a \0, NULL is returned and no data is copied. + * If the destination is large enough to hold the n bytes plus \0, then the + * string is copied and a pointer to the destination string is returned. + */ +char * +virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) +{ + char *ret; + + if (n > (destbytes - 1)) + return NULL; + + ret = strncpy(dest, src, n); + /* strncpy NULL terminates iff the last character is \0. Therefore + * force the last byte to be \0 + */ + dest[n] = '\0'; + + return ret; +} + +/** + * virStrcpy + * + * A safe version of strcpy. The last parameter is the number of bytes + * available in the destination string, *not* the number of bytes you want + * to copy. If the destination is not large enough to hold all n of the + * src string bytes plus a \0, NULL is returned and no data is copied. + * If the destination is large enough to hold the source plus \0, then the + * string is copied and a pointer to the destination string is returned. + */ +char * +virStrcpy(char *dest, const char *src, size_t destbytes) +{ + return virStrncpy(dest, src, strlen(src), destbytes); +} + +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; +} + +/* In case thread-safe locales are available */ +#if HAVE_NEWLOCALE + +static locale_t virLocale; + +static int +virLocaleOnceInit(void) +{ + virLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0); + if (!virLocale) + return -1; + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virLocale) +#endif + +/** + * virDoubleToStr + * + * converts double to string with C locale (thread-safe). + * + * Returns -1 on error, size of the string otherwise. + */ +int +virDoubleToStr(char **strp, double number) +{ + int ret = -1; + +#if HAVE_NEWLOCALE + + locale_t old_loc; + + if (virLocaleInitialize() < 0) + goto error; + + old_loc = uselocale(virLocale); + ret = virAsprintf(strp, "%lf", number); + uselocale(old_loc); + +#else + + char *radix, *tmp; + struct lconv *lc; + + if ((ret = virAsprintf(strp, "%lf", number) < 0)) + goto error; + + lc = localeconv(); + radix = lc->decimal_point; + tmp = strstr(*strp, radix); + if (tmp) { + *tmp = '.'; + if (strlen(radix) > 1) + memmove(tmp + 1, tmp + strlen(radix), strlen(*strp) - (tmp - *strp)); + } + +#endif /* HAVE_NEWLOCALE */ + error: + return ret; +} + + +/** + * Format @val as a base-10 decimal number, in the + * buffer @buf of size @buflen. To allocate a suitable + * sized buffer, the INT_BUFLEN(int) macro should be + * used + * + * Returns pointer to start of the number in @buf + */ +char * +virFormatIntDecimal(char *buf, size_t buflen, int val) +{ + char *p = buf + buflen - 1; + *p = '\0'; + if (val >= 0) { + do { + *--p = '0' + (val % 10); + val /= 10; + } while (val != 0); + } else { + do { + *--p = '0' - (val % 10); + val /= 10; + } while (val != 0); + *--p = '-'; + } + return p; +} + + +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]+[0-9]*$/ + * into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26) + * Note that any trailing string of digits is simply ignored. + * @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", "ubd"}; + 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++) { + if (!c_islower(*ptr)) + break; + + idx = (idx + (i < 1 ? 0 : 1)) * 26; + idx += *ptr - 'a'; + ptr++; + } + + /* Count the trailing digits. */ + size_t n_digits = strspn(ptr, "0123456789"); + if (ptr[n_digits] != '\0') + return -1; + + return idx; +} + +char *virIndexToDiskName(int idx, const char *prefix) +{ + char *name = NULL; + int i, k, offset; + + if (idx < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Disk index %d is negative"), idx); + return NULL; + } + + for (i = 0, k = idx; k >= 0; ++i, k = k / 26 - 1) { } + + offset = strlen(prefix); + + if (VIR_ALLOC_N(name, offset + i + 1)) { + virReportOOMError(); + return NULL; + } + + strcpy(name, prefix); + name[offset + i] = '\0'; + + for (i = i - 1, k = idx; k >= 0; --i, k = k / 26 - 1) { + name[offset + i] = 'a' + (k % 26); + } + + return name; +} + +#ifndef AI_CANONIDN +# define AI_CANONIDN 0 +#endif + +/* Who knew getting a hostname could be so delicate. In Linux (and Unices + * in general), many things depend on "hostname" returning a value that will + * resolve one way or another. In the modern world where networks frequently + * come and go this is often being hard-coded to resolve to "localhost". If + * it *doesn't* resolve to localhost, then we would prefer to have the FQDN. + * That leads us to 3 possibilities: + * + * 1) gethostname() returns an FQDN (not localhost) - we return the string + * as-is, it's all of the information we want + * 2) gethostname() returns "localhost" - we return localhost; doing further + * work to try to resolve it is pointless + * 3) gethostname() returns a shortened hostname - in this case, we want to + * try to resolve this to a fully-qualified name. Therefore we pass it + * to getaddrinfo(). There are two possible responses: + * a) getaddrinfo() resolves to a FQDN - return the FQDN + * b) getaddrinfo() fails or resolves to localhost - in this case, the + * data we got from gethostname() is actually more useful than what + * we got from getaddrinfo(). Return the value from gethostname() + * and hope for the best. + */ +char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + int r; + char hostname[HOST_NAME_MAX+1], *result; + struct addrinfo hints, *info; + + r = gethostname(hostname, sizeof(hostname)); + if (r == -1) { + virReportSystemError(errno, + "%s", _("failed to determine host name")); + return NULL; + } + NUL_TERMINATE(hostname); + + if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) { + /* in this case, gethostname returned localhost (meaning we can't + * do any further canonicalization), or it returned an FQDN (and + * we don't need to do any further canonicalization). Return the + * string as-is; it's up to callers to check whether "localhost" + * is allowed. + */ + result = strdup(hostname); + goto check_and_return; + } + + /* otherwise, it's a shortened, non-localhost, hostname. Attempt to + * canonicalize the hostname by running it through getaddrinfo + */ + + 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) { + VIR_WARN("getaddrinfo failed for '%s': %s", + hostname, gai_strerror(r)); + result = strdup(hostname); + goto check_and_return; + } + + /* Tell static analyzers about getaddrinfo semantics. */ + sa_assert(info); + + if (info->ai_canonname == NULL || + STRPREFIX(info->ai_canonname, "localhost")) + /* in this case, we tried to canonicalize and we ended up back with + * localhost. Ignore the canonicalized name and just return the + * original hostname + */ + result = strdup(hostname); + else + /* Caller frees this string. */ + result = strdup(info->ai_canonname); + + freeaddrinfo(info); + +check_and_return: + if (result == NULL) + virReportOOMError(); + return result; +} + +#ifdef HAVE_GETPWUID_R +enum { + VIR_USER_ENT_DIRECTORY, + VIR_USER_ENT_NAME, +}; + +static char *virGetUserEnt(uid_t uid, + int field) +{ + char *strbuf; + char *ret; + struct passwd pwbuf; + struct passwd *pw = NULL; + long val = sysconf(_SC_GETPW_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + 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. + */ + while ((rc = getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + VIR_FREE(strbuf); + return NULL; + } + } + if (rc != 0 || pw == NULL) { + virReportSystemError(rc, + _("Failed to find user record for uid '%u'"), + (unsigned int) 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(); + + return ret; +} + +static char *virGetGroupEnt(gid_t gid) +{ + char *strbuf; + char *ret; + struct group grbuf; + struct group *gr = NULL; + long val = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + return NULL; + } + + /* + * From the manpage (terrifying but true): + * + * ERRORS + * 0 or ENOENT or ESRCH or EBADF or EPERM or ... + * The given name or gid was not found. + */ + while ((rc = getgrgid_r(gid, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + VIR_FREE(strbuf); + return NULL; + } + } + if (rc != 0 || gr == NULL) { + virReportSystemError(rc, + _("Failed to find group record for gid '%u'"), + (unsigned int) gid); + VIR_FREE(strbuf); + return NULL; + } + + ret = strdup(gr->gr_name); + + VIR_FREE(strbuf); + if (!ret) + virReportOOMError(); + + return ret; +} + +char *virGetUserDirectory(void) +{ + return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); +} + +static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir) +{ + const char *path = getenv(xdgenvname); + char *ret = NULL; + char *home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); + + if (path && path[0]) { + if (virAsprintf(&ret, "%s/libvirt", path) < 0) + goto no_memory; + } else { + if (virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir) < 0) + goto no_memory; + } + + cleanup: + VIR_FREE(home); + return ret; + no_memory: + virReportOOMError(); + goto cleanup; +} + +char *virGetUserConfigDirectory(void) +{ + return virGetXDGDirectory("XDG_CONFIG_HOME", ".config"); +} + +char *virGetUserCacheDirectory(void) +{ + return virGetXDGDirectory("XDG_CACHE_HOME", ".cache"); +} + +char *virGetUserRuntimeDirectory(void) +{ + const char *path = getenv("XDG_RUNTIME_DIR"); + + if (!path || !path[0]) { + return virGetUserCacheDirectory(); + } else { + char *ret; + + if (virAsprintf(&ret, "%s/libvirt", path) < 0) { + virReportOOMError(); + return NULL; + } + + return ret; + } +} + +char *virGetUserName(uid_t uid) +{ + return virGetUserEnt(uid, VIR_USER_ENT_NAME); +} + +char *virGetGroupName(gid_t gid) +{ + return virGetGroupEnt(gid); +} + +/* Search in the password database for a user id that matches the user name + * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. + */ +static int +virGetUserIDByName(const char *name, uid_t *uid) +{ + char *strbuf = NULL; + struct passwd pwbuf; + struct passwd *pw = NULL; + long val = sysconf(_SC_GETPW_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + int ret = -1; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + + while ((rc = getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + if (!pw) { + if (rc != 0) { + char buf[1024]; + /* log the possible error from getpwnam_r. Unfortunately error + * reporting from this function is bad and we can't really + * rely on it, so we just report that the user wasn't found */ + VIR_WARN("User record for user '%s' was not found: %s", + name, virStrerror(rc, buf, sizeof(buf))); + } + + ret = 1; + goto cleanup; + } + + *uid = pw->pw_uid; + ret = 0; + +cleanup: + VIR_FREE(strbuf); + + return ret; +} + +/* Try to match a user id based on `user`. The default behavior is to parse + * `user` first as a user name and then as a user id. However if `user` + * contains a leading '+', the rest of the string is always parsed as a uid. + * + * Returns 0 on success and -1 otherwise. + */ +int +virGetUserID(const char *user, uid_t *uid) +{ + unsigned int uint_uid; + + if (*user == '+') { + user++; + } else { + int rc = virGetUserIDByName(user, uid); + if (rc <= 0) + return rc; + } + + if (virStrToLong_ui(user, NULL, 10, &uint_uid) < 0 || + ((uid_t) uint_uid) != uint_uid) { + virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse user '%s'"), + user); + return -1; + } + + *uid = uint_uid; + + return 0; +} + +/* Search in the group database for a group id that matches the group name + * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. + */ +static int +virGetGroupIDByName(const char *name, gid_t *gid) +{ + char *strbuf = NULL; + struct group grbuf; + struct group *gr = NULL; + long val = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + int ret = -1; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + + while ((rc = getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + if (!gr) { + if (rc != 0) { + char buf[1024]; + /* log the possible error from getgrnam_r. Unfortunately error + * reporting from this function is bad and we can't really + * rely on it, so we just report that the user wasn't found */ + VIR_WARN("Group record for user '%s' was not found: %s", + name, virStrerror(rc, buf, sizeof(buf))); + } + + ret = 1; + goto cleanup; + } + + *gid = gr->gr_gid; + ret = 0; + +cleanup: + VIR_FREE(strbuf); + + return ret; +} + +/* Try to match a group id based on `group`. The default behavior is to parse + * `group` first as a group name and then as a group id. However if `group` + * contains a leading '+', the rest of the string is always parsed as a guid. + * + * Returns 0 on success and -1 otherwise. + */ +int +virGetGroupID(const char *group, gid_t *gid) +{ + unsigned int uint_gid; + + if (*group == '+') { + group++; + } else { + int rc = virGetGroupIDByName(group, gid); + if (rc <= 0) + return rc; + } + + if (virStrToLong_ui(group, NULL, 10, &uint_gid) < 0 || + ((gid_t) uint_gid) != uint_gid) { + virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse group '%s'"), + group); + return -1; + } + + *gid = uint_gid; + + return 0; +} + +/* Set the real and effective uid and gid to the given values, and call + * initgroups so that the process has all the assumed group membership of + * that uid. return 0 on success, -1 on failure (the original system error + * remains in errno). + */ +int +virSetUIDGID(uid_t uid, gid_t gid) +{ + int err; + char *buf = NULL; + + if (gid > 0) { + if (setregid(gid, gid) < 0) { + virReportSystemError(err = errno, + _("cannot change to '%d' group"), + (unsigned int) gid); + goto error; + } + } + + if (uid > 0) { +# ifdef HAVE_INITGROUPS + struct passwd pwd, *pwd_result; + size_t bufsize; + int rc; + + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + if (bufsize == -1) + bufsize = 16384; + + if (VIR_ALLOC_N(buf, bufsize) < 0) { + virReportOOMError(); + err = ENOMEM; + goto error; + } + while ((rc = getpwuid_r(uid, &pwd, buf, bufsize, + &pwd_result)) == ERANGE) { + if (VIR_RESIZE_N(buf, bufsize, bufsize, bufsize) < 0) { + virReportOOMError(); + err = ENOMEM; + goto error; + } + } + + if (rc) { + virReportSystemError(err = rc, _("cannot getpwuid_r(%d)"), + (unsigned int) uid); + goto error; + } + + if (!pwd_result) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("getpwuid_r failed to retrieve data " + "for uid '%d'"), + (unsigned int) uid); + err = EINVAL; + goto error; + } + + if (initgroups(pwd.pw_name, pwd.pw_gid) < 0) { + virReportSystemError(err = errno, + _("cannot initgroups(\"%s\", %d)"), + pwd.pw_name, (unsigned int) pwd.pw_gid); + goto error; + } +# endif + if (setreuid(uid, uid) < 0) { + virReportSystemError(err = errno, + _("cannot change to uid to '%d'"), + (unsigned int) uid); + goto error; + } + } + + VIR_FREE(buf); + return 0; + +error: + VIR_FREE(buf); + errno = err; + return -1; +} + +#else /* ! HAVE_GETPWUID_R */ + +# ifdef WIN32 +/* These methods are adapted from GLib2 under terms of LGPLv2+ */ +static int +virGetWin32SpecialFolder(int csidl, char **path) +{ + char buf[MAX_PATH+1]; + LPITEMIDLIST pidl = NULL; + int ret = 0; + + *path = NULL; + + if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK) { + if (SHGetPathFromIDList(pidl, buf)) { + if (!(*path = strdup(buf))) { + virReportOOMError(); + ret = -1; + } + } + CoTaskMemFree(pidl); + } + return ret; +} + +static int +virGetWin32DirectoryRoot(char **path) +{ + char windowsdir[MAX_PATH]; + int ret = 0; + + *path = NULL; + + if (GetWindowsDirectory(windowsdir, ARRAY_CARDINALITY(windowsdir))) + { + const char *tmp; + /* Usually X:\Windows, but in terminal server environments + * might be an UNC path, AFAIK. + */ + tmp = virFileSkipRoot(windowsdir); + if (VIR_FILE_IS_DIR_SEPARATOR(tmp[-1]) && + tmp[-2] != ':') + tmp--; + + windowsdir[tmp - windowsdir] = '\0'; + } else { + strcpy(windowsdir, "C:\\"); + } + + if (!(*path = strdup(windowsdir))) { + virReportOOMError(); + ret = -1; + } + + return ret; +} + + + +char * +virGetUserDirectory(void) +{ + const char *dir; + char *ret; + + dir = getenv("HOME"); + + /* Only believe HOME if it is an absolute path and exists */ + if (dir) { + if (!virFileIsAbsPath(dir) || + !virFileExists(dir)) + dir = NULL; + } + + /* In case HOME is Unix-style (it happens), convert it to + * Windows style. + */ + if (dir) { + char *p; + while ((p = strchr(dir, '/')) != NULL) + *p = '\\'; + } + + if (!dir) + /* USERPROFILE is probably the closest equivalent to $HOME? */ + dir = getenv("USERPROFILE"); + + if (dir) { + if (!(ret = strdup(dir))) { + virReportOOMError(); + return NULL; + } + } + + if (!ret && + virGetWin32SpecialFolder(CSIDL_PROFILE, &ret) < 0) + return NULL; + + if (!ret && + virGetWin32DirectoryRoot(&ret) < 0) + return NULL; + + if (!ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine home directory")); + return NULL; + } + + return ret; +} + +char * +virGetUserConfigDirectory(void) +{ + char *ret; + if (virGetWin32SpecialFolder(CSIDL_LOCAL_APPDATA, &ret) < 0) + return NULL; + + if (!ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine config directory")); + return NULL; + } + return ret; +} + +char * +virGetUserCacheDirectory(void) +{ + char *ret; + if (virGetWin32SpecialFolder(CSIDL_INTERNET_CACHE, &ret) < 0) + return NULL; + + if (!ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine config directory")); + return NULL; + } + return ret; +} + +char * +virGetUserRuntimeDirectory(void) +{ + return virGetUserCacheDirectory(); +} +# else /* !HAVE_GETPWUID_R && !WIN32 */ +char * +virGetUserDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserDirectory is not available")); + + return NULL; +} + +char * +virGetUserConfigDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserConfigDirectory is not available")); + + return NULL; +} + +char * +virGetUserCacheDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserCacheDirectory is not available")); + + return NULL; +} + +char * +virGetUserRuntimeDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserRuntimeDirectory is not available")); + + return NULL; +} +# endif /* ! HAVE_GETPWUID_R && ! WIN32 */ + +char * +virGetUserName(uid_t uid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserName is not available")); + + return NULL; +} + +int virGetUserID(const char *name ATTRIBUTE_UNUSED, + uid_t *uid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserID is not available")); + + return 0; +} + + +int virGetGroupID(const char *name ATTRIBUTE_UNUSED, + gid_t *gid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetGroupID is not available")); + + return 0; +} + +int +virSetUIDGID(uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virSetUIDGID is not available")); + return -1; +} + +char * +virGetGroupName(gid_t gid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetGroupName is not available")); + + return NULL; +} +#endif /* HAVE_GETPWUID_R */ + + +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +/* 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; +} + +#else /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ + +char * +virFileFindMountPoint(const char *type ATTRIBUTE_UNUSED) +{ + errno = ENOSYS; + + return NULL; +} + +#endif /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ + +#if defined(UDEVADM) || defined(UDEVSETTLE) +void virFileWaitForDevices(void) +{ +# 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. + */ + if (virRun(settleprog, &exitstatus) < 0) + {} +} +#else +void virFileWaitForDevices(void) {} +#endif + +int virBuildPathInternal(char **path, ...) +{ + char *path_component = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + va_list ap; + int ret = 0; + + va_start(ap, path); + + path_component = va_arg(ap, char *); + virBufferAdd(&buf, path_component, -1); + + while ((path_component = va_arg(ap, char *)) != NULL) + { + virBufferAddChar(&buf, '/'); + virBufferAdd(&buf, path_component, -1); + } + + va_end(ap); + + *path = virBufferContentAndReset(&buf); + if (*path == NULL) { + ret = -1; + } + + return ret; +} + +#if HAVE_LIBDEVMAPPER_H +bool +virIsDevMapperDevice(const char *dev_name) +{ + struct stat buf; + + if (!stat(dev_name, &buf) && + S_ISBLK(buf.st_mode) && + dm_is_dm_major(major(buf.st_rdev))) + return true; + + return false; +} +#else +bool virIsDevMapperDevice(const char *dev_name ATTRIBUTE_UNUSED) +{ + return false; +} +#endif + +bool +virValidateWWN(const char *wwn) { + int i; + + for (i = 0; wwn[i]; i++) + if (!c_isxdigit(wwn[i])) + break; + + if (i != 16 || wwn[i]) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed wwn: %s")); + return false; + } + + return true; +} + +bool +virStrIsPrint(const char *str) +{ + int i; + + for (i = 0; str[i]; i++) + if (!c_isprint(str[i])) + return false; + + return true; +} diff --git a/src/util/virutil.h b/src/util/virutil.h new file mode 100644 index 0000000..6d5dd03 --- /dev/null +++ b/src/util/virutil.h @@ -0,0 +1,284 @@ +/* + * utils.h: common, generic utility functions + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * 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, see + * <http://www.gnu.org/licenses/>. + * + * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com> + */ + +#ifndef __VIR_UTIL_H__ +# define __VIR_UTIL_H__ + +# include "verify.h" +# include "internal.h" +# include <unistd.h> +# include <sys/select.h> +# include <sys/types.h> +# include <stdarg.h> + +# ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +# endif +# ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +# endif + +ssize_t saferead(int fd, void *buf, size_t count) ATTRIBUTE_RETURN_CHECK; +ssize_t safewrite(int fd, const void *buf, size_t count) + ATTRIBUTE_RETURN_CHECK; +int safezero(int fd, off_t offset, off_t len) + ATTRIBUTE_RETURN_CHECK; + +int virSetBlocking(int fd, bool blocking) ATTRIBUTE_RETURN_CHECK; +int virSetNonBlock(int fd) ATTRIBUTE_RETURN_CHECK; +int virSetInherit(int fd, bool inherit) ATTRIBUTE_RETURN_CHECK; +int virSetCloseExec(int fd) ATTRIBUTE_RETURN_CHECK; + +int virPipeReadUntilEOF(int outfd, int errfd, + char **outbuf, char **errbuf); + +int virSetUIDGID(uid_t uid, gid_t gid); + +int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; + +int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; + +int virFileWriteStr(const char *path, const char *str, mode_t mode) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +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) ATTRIBUTE_RETURN_CHECK; + +int virFileLinkPointsTo(const char *checkLink, + const char *checkDest); + +int virFileResolveLink(const char *linkpath, + char **resultpath) ATTRIBUTE_RETURN_CHECK; +int virFileResolveAllLinks(const char *linkpath, + char **resultpath) ATTRIBUTE_RETURN_CHECK; + +int virFileIsLink(const char *linkpath) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +char *virFindFileInPath(const char *file); + +bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1); +bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1); +bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1); + +char *virFileSanitizePath(const char *path); + +enum { + VIR_FILE_OPEN_NONE = 0, + VIR_FILE_OPEN_NOFORK = (1 << 0), + VIR_FILE_OPEN_FORK = (1 << 1), + VIR_FILE_OPEN_FORCE_MODE = (1 << 2), + VIR_FILE_OPEN_FORCE_OWNER = (1 << 3), +}; +int virFileAccessibleAs(const char *path, int mode, + uid_t uid, gid_t gid) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; +int virFileOpenAs(const char *path, int openflags, mode_t mode, + uid_t uid, gid_t gid, + unsigned int flags) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +enum { + VIR_DIR_CREATE_NONE = 0, + VIR_DIR_CREATE_AS_UID = (1 << 0), + VIR_DIR_CREATE_FORCE_PERMS = (1 << 1), + VIR_DIR_CREATE_ALLOW_EXIST = (1 << 2), +}; +int virDirCreate(const char *path, mode_t mode, uid_t uid, gid_t gid, + unsigned int flags) ATTRIBUTE_RETURN_CHECK; +int virFileMakePath(const char *path) ATTRIBUTE_RETURN_CHECK; +int virFileMakePathWithMode(const char *path, + mode_t mode) ATTRIBUTE_RETURN_CHECK; + +char *virFileBuildPath(const char *dir, + const char *name, + const char *ext) ATTRIBUTE_RETURN_CHECK; + + +# ifdef WIN32 +/* On Win32, the canonical directory separator is the backslash, and + * the search path separator is the semicolon. Note that also the + * (forward) slash works as directory separator. + */ +# define VIR_FILE_DIR_SEPARATOR '\\' +# define VIR_FILE_DIR_SEPARATOR_S "\\" +# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR || (c) == '/') +# define VIR_FILE_PATH_SEPARATOR ';' +# define VIR_FILE_PATH_SEPARATOR_S ";" + +# else /* !WIN32 */ + +# define VIR_FILE_DIR_SEPARATOR '/' +# define VIR_FILE_DIR_SEPARATOR_S "/" +# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR) +# define VIR_FILE_PATH_SEPARATOR ':' +# define VIR_FILE_PATH_SEPARATOR_S ":" + +# endif /* !WIN32 */ + +bool virFileIsAbsPath(const char *path); +int virFileAbsPath(const char *path, + char **abspath) ATTRIBUTE_RETURN_CHECK; +const char *virFileSkipRoot(const char *path); + +int virFileOpenTty(int *ttymaster, + char **ttyName, + int rawmode); + +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_l(char const *s, + char **end_ptr, + int base, + long *result); +int virStrToLong_ul(char const *s, + char **end_ptr, + int base, + unsigned long *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 virScaleInteger(unsigned long long *value, const char *suffix, + unsigned long long scale, unsigned long long limit) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +int virHexToBin(unsigned char c); + +void virSkipSpaces(const char **str) ATTRIBUTE_NONNULL(1); +void virSkipSpacesAndBackslash(const char **str) ATTRIBUTE_NONNULL(1); +void virTrimSpaces(char *str, char **endp) ATTRIBUTE_NONNULL(1); +void virSkipSpacesBackwards(const char *str, char **endp) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int virParseNumber(const char **str); +int virParseVersionString(const char *str, unsigned long *version, + bool allowMissing); +int virAsprintf(char **strp, const char *fmt, ...) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); +int virVasprintf(char **strp, const char *fmt, va_list list) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 0); +char *virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) + ATTRIBUTE_RETURN_CHECK; +char *virStrcpy(char *dest, const char *src, size_t destbytes) + ATTRIBUTE_RETURN_CHECK; +# define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest)) + +int virDoubleToStr(char **strp, double number) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +char *virFormatIntDecimal(char *buf, size_t buflen, int val) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +int virDiskNameToIndex(const char* str); +char *virIndexToDiskName(int idx, const char *prefix); + +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__ }; \ + verify(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_GETEUID +static inline int geteuid (void) { return 0; } +# endif + +# ifndef HAVE_GETGID +static inline int getgid (void) { return 0; } +# endif + +char *virGetHostname(virConnectPtr conn); + +char *virGetUserDirectory(void); +char *virGetUserConfigDirectory(void); +char *virGetUserCacheDirectory(void); +char *virGetUserRuntimeDirectory(void); +char *virGetUserName(uid_t uid); +char *virGetGroupName(gid_t gid); +int virGetUserID(const char *name, + uid_t *uid) ATTRIBUTE_RETURN_CHECK; +int virGetGroupID(const char *name, + gid_t *gid) ATTRIBUTE_RETURN_CHECK; + +char *virFileFindMountPoint(const char *type); + +void virFileWaitForDevices(void); + +# define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL) +int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL; + +bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1); + +bool virValidateWWN(const char *wwn); + +bool virStrIsPrint(const char *str); +#endif /* __VIR_UTIL_H__ */ diff --git a/src/util/xml.c b/src/util/xml.c index caf26a3..05c7f33 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "xml.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index cab4398..36539f6 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -31,7 +31,7 @@ #include "internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" #include "vbox_MSCOMGlue.h" diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 5296127..1954ddb 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -38,7 +38,7 @@ #include "vbox_XPCOMCGlue.h" #include "internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index cd29e19..f2a0c8f 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -38,7 +38,7 @@ #include "vbox_driver.h" #include "vbox_glue.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_VBOX diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 233804e..12195bf 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "virfile.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "vircommand.h" #include "vmx.h" diff --git a/src/xen/block_stats.c b/src/xen/block_stats.c index 126283b..3f7c97b 100644 --- a/src/xen/block_stats.c +++ b/src/xen/block_stats.c @@ -40,7 +40,7 @@ # include "virterror_internal.h" # include "datatypes.h" -# include "util.h" +# include "virutil.h" # include "block_stats.h" # include "viralloc.h" # include "virfile.h" diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 9b2fcf3..2b8496c 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -54,7 +54,7 @@ # include "xen_inotify.h" #endif #include "xml.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "node_device_conf.h" #include "virpci.h" diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 5c8fe37..f804620 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -67,7 +67,7 @@ #include "virlog.h" #include "datatypes.h" #include "driver.h" -#include "util.h" +#include "virutil.h" #include "xen_driver.h" #include "xen_hypervisor.h" #include "xs_internal.h" diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 6e8bc2f..7ffc5bb 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -34,7 +34,7 @@ #include "datatypes.h" #include "xend_internal.h" #include "driver.h" -#include "util.h" +#include "virutil.h" #include "virsexpr.h" #include "xen_sxpr.h" #include "virbuffer.h" diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 2109972..e3206eb 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -45,7 +45,7 @@ #include "virhash.h" #include "virbuffer.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "count-one-bits.h" diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 0a0ac0e..04b24ab 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -31,7 +31,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "viralloc.h" #include "virbuffer.h" diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 33aa4d7..15be403 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -29,7 +29,7 @@ #include "domain_conf.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "viralloc.h" #include "virbuffer.h" diff --git a/tests/commandhelper.c b/tests/commandhelper.c index 3c7fef5..39f3c53 100644 --- a/tests/commandhelper.c +++ b/tests/commandhelper.c @@ -27,7 +27,7 @@ #include <string.h> #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h" #include "testutils.h" diff --git a/tests/commandtest.c b/tests/commandtest.c index b15c168..d6a285e 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -31,7 +31,7 @@ #include "testutils.h" #include "internal.h" #include "nodeinfo.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircommand.h" #include "virfile.h" diff --git a/tests/esxutilstest.c b/tests/esxutilstest.c index b65009b..55b3623 100644 --- a/tests/esxutilstest.c +++ b/tests/esxutilstest.c @@ -9,7 +9,7 @@ # include "internal.h" # include "viralloc.h" # include "testutils.h" -# include "util.h" +# include "virutil.h" # include "vmx/vmx.h" # include "esx/esx_util.h" # include "esx/esx_vi_types.h" diff --git a/tests/eventtest.c b/tests/eventtest.c index 6d00ea8..16a693c 100644 --- a/tests/eventtest.c +++ b/tests/eventtest.c @@ -30,7 +30,7 @@ #include "internal.h" #include "virthread.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "vireventpoll.h" #define NUM_FDS 31 diff --git a/tests/libvirtdconftest.c b/tests/libvirtdconftest.c index 0365ade..c1d94d2 100644 --- a/tests/libvirtdconftest.c +++ b/tests/libvirtdconftest.c @@ -24,7 +24,7 @@ #include "testutils.h" #include "daemon/libvirtd-config.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/tests/nodeinfotest.c b/tests/nodeinfotest.c index c79788e..d900eb9 100644 --- a/tests/nodeinfotest.c +++ b/tests/nodeinfotest.c @@ -8,7 +8,7 @@ #include "testutils.h" #include "internal.h" #include "nodeinfo.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #if ! (defined __linux__ && (defined(__x86_64__) || \ diff --git a/tests/openvzutilstest.c b/tests/openvzutilstest.c index 80701a2..9fb7178 100644 --- a/tests/openvzutilstest.c +++ b/tests/openvzutilstest.c @@ -9,7 +9,7 @@ # include "internal.h" # include "viralloc.h" # include "testutils.h" -# include "util.h" +# include "virutil.h" # include "openvz/openvz_conf.h" static int diff --git a/tests/qemumonitortest.c b/tests/qemumonitortest.c index 21a6828..285dfa8 100644 --- a/tests/qemumonitortest.c +++ b/tests/qemumonitortest.c @@ -10,7 +10,7 @@ # include "internal.h" # include "viralloc.h" # include "testutils.h" -# include "util.h" +# include "virutil.h" # include "qemu/qemu_monitor.h" struct testEscapeString diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index cc38803..b82eb5d 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -30,7 +30,7 @@ #include "qemu/qemu_monitor.h" #include "rpc/virnetsocket.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/tests/securityselinuxtest.c b/tests/securityselinuxtest.c index 045c9c0..b523c79 100644 --- a/tests/securityselinuxtest.c +++ b/tests/securityselinuxtest.c @@ -31,7 +31,7 @@ #include "internal.h" #include "testutils.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" #include "security/security_manager.h" diff --git a/tests/testutils.c b/tests/testutils.c index c6b1d23..d88af21 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -40,7 +40,7 @@ #include "testutils.h" #include "internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virthread.h" #include "virterror_internal.h" #include "virbuffer.h" diff --git a/tests/utiltest.c b/tests/utiltest.c index 4fbb25c..9d18652 100644 --- a/tests/utiltest.c +++ b/tests/utiltest.c @@ -8,7 +8,7 @@ #include "internal.h" #include "viralloc.h" #include "testutils.h" -#include "util.h" +#include "virutil.h" static void diff --git a/tests/virauthconfigtest.c b/tests/virauthconfigtest.c index 9e7dac5..2ad237d 100644 --- a/tests/virauthconfigtest.c +++ b/tests/virauthconfigtest.c @@ -24,7 +24,7 @@ #include <signal.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virbuftest.c b/tests/virbuftest.c index ec93939..7f9ee66 100644 --- a/tests/virbuftest.c +++ b/tests/virbuftest.c @@ -5,7 +5,7 @@ #include <string.h> #include "internal.h" -#include "util.h" +#include "virutil.h" #include "testutils.h" #include "virbuffer.h" #include "viralloc.h" diff --git a/tests/virdrivermoduletest.c b/tests/virdrivermoduletest.c index e06179f..cab47d3 100644 --- a/tests/virdrivermoduletest.c +++ b/tests/virdrivermoduletest.c @@ -21,7 +21,7 @@ #include <config.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virhashtest.c b/tests/virhashtest.c index a2a40c6..6e4f267 100644 --- a/tests/virhashtest.c +++ b/tests/virhashtest.c @@ -10,7 +10,7 @@ #include "virhashdata.h" #include "testutils.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" diff --git a/tests/virkeyfiletest.c b/tests/virkeyfiletest.c index ad5a516..33f64c1 100644 --- a/tests/virkeyfiletest.c +++ b/tests/virkeyfiletest.c @@ -24,7 +24,7 @@ #include <signal.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c index 80478d9..c434f47 100644 --- a/tests/virlockspacetest.c +++ b/tests/virlockspacetest.c @@ -25,7 +25,7 @@ #include <sys/stat.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnetmessagetest.c b/tests/virnetmessagetest.c index e3517e8..4e7a1fd 100644 --- a/tests/virnetmessagetest.c +++ b/tests/virnetmessagetest.c @@ -24,7 +24,7 @@ #include <signal.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index 399c4fd..819257b 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -28,7 +28,7 @@ #include <netdb.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c index 27078ea..d945181 100644 --- a/tests/virnettlscontexttest.c +++ b/tests/virnettlscontexttest.c @@ -27,7 +27,7 @@ #include <gnutls/x509.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virshtest.c b/tests/virshtest.c index 72f2a1e..8741d47 100644 --- a/tests/virshtest.c +++ b/tests/virshtest.c @@ -6,7 +6,7 @@ #include "internal.h" #include "xml.h" -#include "util.h" +#include "virutil.h" #include "testutils.h" #ifdef WIN32 diff --git a/tests/virstringtest.c b/tests/virstringtest.c index a8f4c79..58ab843 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -23,7 +23,7 @@ #include <stdlib.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virtimetest.c b/tests/virtimetest.c index 7d7a2d6..1c22d07 100644 --- a/tests/virtimetest.c +++ b/tests/virtimetest.c @@ -24,7 +24,7 @@ #include <signal.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/viruritest.c b/tests/viruritest.c index 57d3895..ad59270 100644 --- a/tests/viruritest.c +++ b/tests/viruritest.c @@ -24,7 +24,7 @@ #include <signal.h> #include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tools/console.c b/tools/console.c index d031308..d024d38 100644 --- a/tools/console.c +++ b/tools/console.c @@ -39,7 +39,7 @@ # include "internal.h" # include "console.h" # include "virlog.h" -# include "util.h" +# include "virutil.h" # include "virfile.h" # include "viralloc.h" # include "virthread.h" diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index b0b0c94..244ffb8 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -43,7 +43,7 @@ #include "conf/domain_conf.h" #include "console.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virkeycode.h" #include "virmacaddr.h" diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 2d59a75..0ad4296 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virsh-domain.h" #include "xml.h" #include "virtypedparam.h" diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index 40216c6..ea8a6c5 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" virInterfacePtr diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 66ee7e3..918dee6 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "conf/network_conf.h" diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 7e569b3..974e495 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "conf/node_device_conf.h" diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index c3dba0c..1480d13 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" virNWFilterPtr diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 6e29604..b3177e0 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "conf/storage_conf.h" diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index d81e8ce..a29454f 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -35,7 +35,7 @@ #include "base64.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" static virSecretPtr diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index 3fecde6..8428282 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -36,7 +36,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virsh-domain.h" #include "xml.h" #include "conf/snapshot_conf.h" diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index ebfe52d..6f2c591 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -36,7 +36,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virsh-pool.h" #include "xml.h" diff --git a/tools/virsh.c b/tools/virsh.c index 91a9677..bfeaaa1 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -58,7 +58,7 @@ #include "base64.h" #include "virbuffer.h" #include "console.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "xml.h" #include "libvirt/libvirt-qemu.h" diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c index cd75eba..34a527f 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -27,7 +27,7 @@ #include <unistd.h> #include <sys/utsname.h> -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h" #include "virt-host-validate-common.h" -- 1.7.11.7

On 17.12.2012 15:57, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
--- cfg.mk | 16 +- daemon/libvirtd.c | 2 +- daemon/remote.c | 2 +- po/POTFILES.in | 2 +- python/libvirt-override.c | 2 +- src/Makefile.am | 5 +- src/conf/capabilities.c | 2 +- src/conf/cpu_conf.c | 2 +- src/conf/cpu_conf.h | 2 +- src/conf/device_conf.c | 2 +- src/conf/device_conf.h | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 2 +- src/conf/interface_conf.c | 2 +- src/conf/interface_conf.h | 2 +- src/conf/netdev_bandwidth_conf.c | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 2 +- src/conf/node_device_conf.h | 2 +- src/conf/nwfilter_conf.h | 2 +- src/conf/secret_conf.c | 2 +- src/conf/secret_conf.h | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_conf.h | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/conf/storage_encryption_conf.h | 2 +- src/cpu/cpu_powerpc.c | 2 +- src/cpu/cpu_x86.c | 2 +- src/datatypes.c | 2 +- src/driver.c | 2 +- src/esx/esx_device_monitor.c | 2 +- src/esx/esx_driver.c | 2 +- src/esx/esx_interface_driver.c | 2 +- src/esx/esx_network_driver.c | 2 +- src/esx/esx_nwfilter_driver.c | 2 +- src/esx/esx_secret_driver.c | 2 +- src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/esx/esx_util.c | 2 +- src/esx/esx_vi.c | 2 +- src/esx/esx_vi_types.c | 2 +- src/fdstream.c | 2 +- src/hyperv/hyperv_device_monitor.c | 2 +- src/hyperv/hyperv_driver.c | 2 +- src/hyperv/hyperv_interface_driver.c | 2 +- src/hyperv/hyperv_network_driver.c | 2 +- src/hyperv/hyperv_nwfilter_driver.c | 2 +- src/hyperv/hyperv_secret_driver.c | 2 +- src/hyperv/hyperv_storage_driver.c | 2 +- src/hyperv/hyperv_util.c | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_daemon_dispatch.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_sanlock.c | 2 +- src/locking/lock_manager.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_controller.c | 4 +- src/lxc/lxc_driver.c | 2 +- src/lxc/lxc_fuse.h | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_driver.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/nodeinfo.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_bridge_filter.c | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_cgroup.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_process.c | 2 +- src/remote/remote_driver.c | 2 +- src/rpc/virkeepalive.c | 2 +- src/rpc/virnetclient.c | 2 +- src/rpc/virnetclientprogram.c | 2 +- src/rpc/virnetmessage.c | 2 +- src/rpc/virnetserver.c | 2 +- src/rpc/virnetsocket.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/rpc/virnettlscontext.c | 2 +- src/secret/secret_driver.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_selinux.c | 4 +- src/security/virt-aa-helper.c | 2 +- src/storage/parthelper.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_disk.c | 2 +- src/storage/storage_backend_iscsi.c | 2 +- src/storage/storage_backend_rbd.c | 2 +- src/storage/storage_backend_sheepdog.c | 2 +- src/storage/storage_driver.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/iohelper.c | 2 +- src/util/util.c | 3131 -------------------------------- src/util/util.h | 284 --- src/util/uuid.c | 2 +- src/util/viraudit.c | 2 +- src/util/virauth.c | 2 +- src/util/virauthconfig.c | 2 +- src/util/virbitmap.c | 2 +- src/util/vircgroup.c | 2 +- src/util/vircommand.c | 2 +- src/util/vircommand.h | 2 +- src/util/virconf.c | 2 +- src/util/virdnsmasq.c | 2 +- src/util/vireventpoll.c | 2 +- src/util/virhooks.c | 2 +- src/util/virhooks.h | 2 +- src/util/virinitctl.c | 2 +- src/util/virjson.c | 2 +- src/util/virkeycode.h | 2 +- src/util/virkeyfile.c | 2 +- src/util/virlockspace.c | 2 +- src/util/virlog.c | 2 +- src/util/virnetdevbridge.c | 2 +- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevopenvswitch.h | 2 +- src/util/virnetdevtap.c | 2 +- src/util/virnetdevvportprofile.h | 2 +- src/util/virpidfile.c | 2 +- src/util/virprocess.c | 2 +- src/util/virrandom.c | 2 +- src/util/virsexpr.c | 2 +- src/util/virsocketaddr.c | 2 +- src/util/virstatslinux.c | 2 +- src/util/virstoragefile.h | 2 +- src/util/virsysinfo.c | 2 +- src/util/virsysinfo.h | 2 +- src/util/virterror.c | 2 +- src/util/virtime.c | 2 +- src/util/virtypedparam.c | 2 +- src/util/viruri.c | 2 +- src/util/virusb.c | 2 +- src/util/virutil.c | 3131 ++++++++++++++++++++++++++++++++ src/util/virutil.h | 284 +++ src/util/xml.c | 2 +- src/vbox/vbox_MSCOMGlue.c | 2 +- src/vbox/vbox_XPCOMCGlue.c | 2 +- src/vbox/vbox_driver.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/xen/block_stats.c | 2 +- src/xen/xen_driver.c | 2 +- src/xen/xen_hypervisor.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xm_internal.c | 2 +- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 2 +- tests/commandhelper.c | 2 +- tests/commandtest.c | 2 +- tests/esxutilstest.c | 2 +- tests/eventtest.c | 2 +- tests/libvirtdconftest.c | 2 +- tests/nodeinfotest.c | 2 +- tests/openvzutilstest.c | 2 +- tests/qemumonitortest.c | 2 +- tests/qemumonitortestutils.c | 2 +- tests/securityselinuxtest.c | 2 +- tests/testutils.c | 2 +- tests/utiltest.c | 2 +- tests/virauthconfigtest.c | 2 +- tests/virbuftest.c | 2 +- tests/virdrivermoduletest.c | 2 +- tests/virhashtest.c | 2 +- tests/virkeyfiletest.c | 2 +- tests/virlockspacetest.c | 2 +- tests/virnetmessagetest.c | 2 +- tests/virnetsockettest.c | 2 +- tests/virnettlscontexttest.c | 2 +- tests/virshtest.c | 2 +- tests/virstringtest.c | 2 +- tests/virtimetest.c | 2 +- tests/viruritest.c | 2 +- tools/console.c | 2 +- tools/virsh-domain.c | 2 +- tools/virsh-host.c | 2 +- tools/virsh-interface.c | 2 +- tools/virsh-network.c | 2 +- tools/virsh-nodedev.c | 2 +- tools/virsh-nwfilter.c | 2 +- tools/virsh-pool.c | 2 +- tools/virsh-secret.c | 2 +- tools/virsh-snapshot.c | 2 +- tools/virsh-volume.c | 2 +- tools/virsh.c | 2 +- tools/virt-host-validate-common.c | 2 +- 194 files changed, 3616 insertions(+), 3615 deletions(-) delete mode 100644 src/util/util.c delete mode 100644 src/util/util.h create mode 100644 src/util/virutil.c create mode 100644 src/util/virutil.h
diff --git a/cfg.mk b/cfg.mk index 0a66797..a269f77 100644 --- a/cfg.mk +++ b/cfg.mk @@ -745,7 +745,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco # List all syntax-check exemptions: exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$
-_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon +_src1=libvirt|fdstream|qemu/qemu_monitor|util/(vircommand|virutil)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon exclude_file_name_regexp--sc_avoid_write = \ ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$
@@ -764,13 +764,13 @@ exclude_file_name_regexp--sc_po_check = ^(docs/|src/rpc/gendispatch\.pl$$) exclude_file_name_regexp--sc_prohibit_VIR_ERR_NO_MEMORY = \ ^(include/libvirt/virterror\.h|daemon/dispatch\.c|src/util/virterror\.c)$$
-exclude_file_name_regexp--sc_prohibit_access_xok = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_access_xok = ^src/util/virutil\.c$$
exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \ ^python/(libvirt-(qemu-)?override|typewrappers)\.c$$
exclude_file_name_regexp--sc_prohibit_asprintf = \ - ^(bootstrap.conf$$|src/util/util\.c$$|examples/domain-events/events-c/event-test\.c$$) + ^(bootstrap.conf$$|src/util/virutil\.c$$|examples/domain-events/events-c/event-test\.c$$)
exclude_file_name_regexp--sc_prohibit_close = \ (\.p[yl]$$|^docs/|^(src/util/virfile\.c|src/libvirt\.c)$$) @@ -782,10 +782,10 @@ _src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon) exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
-exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/virutil\.c$$
exclude_file_name_regexp--sc_prohibit_internal_functions = \ - ^src/(util/(viralloc|util|virfile)\.[hc]|esx/esx_vi\.c)$$ + ^src/(util/(viralloc|virutil|virfile)\.[hc]|esx/esx_vi\.c)$$
exclude_file_name_regexp--sc_prohibit_newline_at_end_of_diagnostic = \ ^src/rpc/gendispatch\.pl$$ @@ -797,14 +797,14 @@ exclude_file_name_regexp--sc_prohibit_raw_allocation = \ ^(src/util/viralloc\.[ch]|examples/.*)$$
exclude_file_name_regexp--sc_prohibit_readlink = \ - ^src/(util/util|lxc/lxc_container)\.c$$ + ^src/(util/virutil|lxc/lxc_container)\.c$$
-exclude_file_name_regexp--sc_prohibit_setuid = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_setuid = ^src/util/virutil\.c$$
exclude_file_name_regexp--sc_prohibit_sprintf = \ ^(docs/hacking\.html\.in)|(examples/systemtap/.*stp)|(src/dtrace2systemtap\.pl)|(src/rpc/gensystemtap\.pl)$$
-exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/util\.c$$ +exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/virutil\.c$$
exclude_file_name_regexp--sc_prohibit_strtol = \ ^src/(util/virsexpr|(vbox|xen|xenxs)/.*)\.c$$ diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index dc1d2c5..edc899e 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -43,7 +43,7 @@ #include "libvirtd.h" #include "libvirtd-config.h"
-#include "util.h" +#include "virutil.h" #include "uuid.h" #include "remote_driver.h" #include "viralloc.h" diff --git a/daemon/remote.c b/daemon/remote.c index eb75281..0b5a3db 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -35,7 +35,7 @@ #include "datatypes.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "stream.h" #include "uuid.h" #include "libvirt/libvirt-qemu.h" diff --git a/po/POTFILES.in b/po/POTFILES.in index c17c63c..8a24fd4 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/util.c src/util/viraudit.c src/util/virauth.c src/util/virauthconfig.c @@ -180,6 +179,7 @@ src/util/virtime.c src/util/virtypedparam.c src/util/viruri.c src/util/virusb.c +src/util/virutil.c src/util/xml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 644f34d..91e82c6 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virtypedparam.h" #include "ignore-value.h" -#include "util.h" +#include "virutil.h"
#ifndef __CYGWIN__ extern void initlibvirtmod(void); diff --git a/src/Makefile.am b/src/Makefile.am index d8d96f8..1303edd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,7 +54,6 @@ augeastest_DATA = # helper APIs for various purposes UTIL_SOURCES = \ util/uuid.c util/uuid.h \ - util/util.c util/util.h \ util/viralloc.c util/viralloc.h \ util/viratomic.h util/viratomic.c \ util/viraudit.c util/viraudit.h \ @@ -114,7 +113,9 @@ UTIL_SOURCES = \ util/virstring.h util/virstring.c \ util/virtime.h util/virtime.c \ util/virusb.c util/virusb.h \ - util/viruri.h util/viruri.c + util/viruri.h util/viruri.c \ + util/virutil.c util/virutil.h \ + $(NULL)
EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \ $(srcdir)/util/virkeycode-mapgen.py diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index 9ac18e2..e46a594 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -28,7 +28,7 @@ #include "capabilities.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "cpu_conf.h" #include "virterror_internal.h" diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 23941c5..95c6ca1 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -25,7 +25,7 @@
#include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "cpu_conf.h" #include "domain_conf.h" diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 357057d..7bec912 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -24,7 +24,7 @@ #ifndef __VIR_CPU_CONF_H__ # define __VIR_CPU_CONF_H__
-# include "util.h" +# include "virutil.h" # include "virbuffer.h" # include "xml.h" # include "virbitmap.h" diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index c3ca2d6..4efafc4 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -26,7 +26,7 @@ #include "viralloc.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "device_conf.h"
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index c1bf096..52e4ac5 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -28,7 +28,7 @@ # include <libxml/xpath.h>
# include "internal.h" -# include "util.h" +# include "virutil.h" # include "virthread.h" # include "virbuffer.h"
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b3c3557..ab1fe2a 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -38,7 +38,7 @@ #include "verify.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "virlog.h" #include "nwfilter_conf.h" diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 56aece2..df6e376 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -32,7 +32,7 @@ # include "capabilities.h" # include "storage_encryption_conf.h" # include "cpu_conf.h" -# include "util.h" +# include "virutil.h" # include "virthread.h" # include "virhash.h" # include "virsocketaddr.h" diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index 046a8a1..e4b088a 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -30,7 +30,7 @@ #include "viralloc.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h"
#define VIR_FROM_THIS VIR_FROM_INTERFACE diff --git a/src/conf/interface_conf.h b/src/conf/interface_conf.h index d6f98f1..e636c35 100644 --- a/src/conf/interface_conf.h +++ b/src/conf/interface_conf.h @@ -29,7 +29,7 @@ # include <libxml/xpath.h>
# include "internal.h" -# include "util.h" +# include "virutil.h" # include "virthread.h"
/* There is currently 3 types of interfaces */ diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c index 35f067c..e64aeff 100644 --- a/src/conf/netdev_bandwidth_conf.c +++ b/src/conf/netdev_bandwidth_conf.c @@ -24,7 +24,7 @@
#include "netdev_bandwidth_conf.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "domain_conf.h"
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 1932851..42f3593 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -40,7 +40,7 @@ #include "viralloc.h" #include "xml.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "c-ctype.h" #include "virfile.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 045f05d..12819c8 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -33,7 +33,7 @@ #include "node_device_conf.h" #include "viralloc.h" #include "xml.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "uuid.h" #include "virpci.h" diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h index 9860f67..12c36d8 100644 --- a/src/conf/node_device_conf.h +++ b/src/conf/node_device_conf.h @@ -26,7 +26,7 @@ # define __VIR_NODE_DEVICE_CONF_H__
# include "internal.h" -# include "util.h" +# include "virutil.h" # include "virthread.h"
# include <libxml/tree.h> diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h index d597064..2ca44b3 100644 --- a/src/conf/nwfilter_conf.h +++ b/src/conf/nwfilter_conf.h @@ -28,7 +28,7 @@
# include "internal.h"
-# include "util.h" +# include "virutil.h" # include "virhash.h" # include "xml.h" # include "virbuffer.h" diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index 5188c7a..a65cf92 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "secret_conf.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "uuid.h"
diff --git a/src/conf/secret_conf.h b/src/conf/secret_conf.h index 2064286..6079d5b 100644 --- a/src/conf/secret_conf.h +++ b/src/conf/secret_conf.h @@ -24,7 +24,7 @@ # define __VIR_SECRET_CONF_H__
# include "internal.h" -# include "util.h" +# include "virutil.h"
VIR_ENUM_DECL(virSecretUsageType)
diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 5c40e97..810d2bf 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -42,7 +42,7 @@ #include "secret_conf.h" #include "snapshot_conf.h" #include "virstoragefile.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "virfile.h" #include "virterror_internal.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 5cd2393..38bb471 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -41,7 +41,7 @@ #include "xml.h" #include "uuid.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h"
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 573c3db..ad16eca 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -25,7 +25,7 @@ # define __VIR_STORAGE_CONF_H__
# include "internal.h" -# include "util.h" +# include "virutil.h" # include "storage_encryption_conf.h" # include "virthread.h"
diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 8d3ceac..139c37c 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "storage_conf.h" #include "storage_encryption_conf.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "virterror_internal.h" #include "uuid.h" diff --git a/src/conf/storage_encryption_conf.h b/src/conf/storage_encryption_conf.h index 40a8497..57ab1a0 100644 --- a/src/conf/storage_encryption_conf.h +++ b/src/conf/storage_encryption_conf.h @@ -25,7 +25,7 @@
# include "internal.h" # include "virbuffer.h" -# include "util.h" +# include "virutil.h"
# include <libxml/tree.h>
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c index 6b6c325..40a2d88 100644 --- a/src/cpu/cpu_powerpc.c +++ b/src/cpu/cpu_powerpc.c @@ -28,7 +28,7 @@
#include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "cpu.h"
#include "cpu_map.h" diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 93ee111..b932b93 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -27,7 +27,7 @@
#include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "cpu.h" #include "cpu_map.h" #include "cpu_x86.h" diff --git a/src/datatypes.c b/src/datatypes.c index 0907c7d..07aefcc 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -27,7 +27,7 @@ #include "virlog.h" #include "viralloc.h" #include "uuid.h" -#include "util.h" +#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_NONE
diff --git a/src/driver.c b/src/driver.c index 23dc329..0a5fe05 100644 --- a/src/driver.c +++ b/src/driver.c @@ -27,7 +27,7 @@ #include "driver.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "configmake.h"
#define DEFAULT_DRIVER_DIR LIBDIR "/libvirt/connection-driver" diff --git a/src/esx/esx_device_monitor.c b/src/esx/esx_device_monitor.c index 854fc38..7cc6ac0 100644 --- a/src/esx/esx_device_monitor.c +++ b/src/esx/esx_device_monitor.c @@ -25,7 +25,7 @@ #include <config.h>
#include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 0fe9a67..2c0297c 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -28,7 +28,7 @@ #include "domain_conf.h" #include "snapshot_conf.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index fea67ab..524886f 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -25,7 +25,7 @@ #include <config.h>
#include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index fec7e72..0fc2603 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -26,7 +26,7 @@
#include "md5.h" #include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_nwfilter_driver.c b/src/esx/esx_nwfilter_driver.c index 7a05a5a..ecee0fb 100644 --- a/src/esx/esx_nwfilter_driver.c +++ b/src/esx/esx_nwfilter_driver.c @@ -25,7 +25,7 @@ #include <config.h>
#include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_secret_driver.c b/src/esx/esx_secret_driver.c index 2969b19..722d3f7 100644 --- a/src/esx/esx_secret_driver.c +++ b/src/esx/esx_secret_driver.c @@ -24,7 +24,7 @@ #include <config.h>
#include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 5ad885a..3c3ab7d 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -28,7 +28,7 @@
#include "internal.h" #include "md5.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index 4886fc3..c57e070 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -31,7 +31,7 @@
#include "internal.h" #include "md5.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index bcda9df..9b2e576 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -28,7 +28,7 @@
#include "internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 37b6e0f..2cc8002 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -29,7 +29,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "vmx.h" #include "xml.h" diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c index b93223d..d1f91ff 100644 --- a/src/esx/esx_vi_types.c +++ b/src/esx/esx_vi_types.c @@ -31,7 +31,7 @@ #include "datatypes.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "esx_vi.h" #include "esx_vi_types.h"
diff --git a/src/fdstream.c b/src/fdstream.c index 39e92b8..f7f101e 100644 --- a/src/fdstream.c +++ b/src/fdstream.c @@ -37,7 +37,7 @@ #include "datatypes.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "configmake.h"
diff --git a/src/hyperv/hyperv_device_monitor.c b/src/hyperv/hyperv_device_monitor.c index d6edb76..10d559f 100644 --- a/src/hyperv/hyperv_device_monitor.c +++ b/src/hyperv/hyperv_device_monitor.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 749c7f0..d777bd8 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -27,7 +27,7 @@ #include "datatypes.h" #include "domain_conf.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c index 43c7dd7..af37de3 100644 --- a/src/hyperv/hyperv_interface_driver.c +++ b/src/hyperv/hyperv_interface_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index 06b051b..cafc956 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c index 7452b7a..46c57b7 100644 --- a/src/hyperv/hyperv_nwfilter_driver.c +++ b/src/hyperv/hyperv_nwfilter_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c index 04a6ada..ea8fa7e 100644 --- a/src/hyperv/hyperv_secret_driver.c +++ b/src/hyperv/hyperv_secret_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c index b2817a2..7549801 100644 --- a/src/hyperv/hyperv_storage_driver.c +++ b/src/hyperv/hyperv_storage_driver.c @@ -26,7 +26,7 @@ #include "internal.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c index 016d415..69a57c6 100644 --- a/src/hyperv/hyperv_util.c +++ b/src/hyperv/hyperv_util.c @@ -24,7 +24,7 @@
#include "internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "uuid.h" diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index 69e7283..f4afdce 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -29,7 +29,7 @@ #include "datatypes.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "virbuffer.h" #include "hyperv_private.h" diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index 3d90c57..df9923e 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -33,7 +33,7 @@
#include "lock_daemon.h" #include "lock_daemon_config.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c index 78c9726..def7c2f 100644 --- a/src/locking/lock_daemon_dispatch.c +++ b/src/locking/lock_daemon_dispatch.c @@ -24,7 +24,7 @@
#include "rpc/virnetserver.h" #include "rpc/virnetserverclient.h" -#include "util.h" +#include "virutil.h" #include "virlog.h"
#include "lock_daemon.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index cee530d..547db85 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -26,7 +26,7 @@ #include "viralloc.h" #include "virlog.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virterror_internal.h" #include "rpc/virnetclient.h" diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index e520444..511543a 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -40,7 +40,7 @@ #include "virlog.h" #include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "md5.h" #include "virconf.h" diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c index f938b04..d73e184 100644 --- a/src/locking/lock_manager.c +++ b/src/locking/lock_manager.c @@ -25,7 +25,7 @@ #include "lock_driver_nop.h" #include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "uuid.h"
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index f3c6e19..050a4c1 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -56,7 +56,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "lxc_container.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virnetdevveth.h" #include "uuid.h" diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 6b6ec82..a8e99f2 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -54,7 +54,7 @@
#include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h"
#include "lxc_conf.h" #include "lxc_container.h" @@ -64,7 +64,7 @@ #include "virnetdev.h" #include "virnetdevveth.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virpidfile.h" #include "vircommand.h"
Why do we have this include twice? One is sufficient ....
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 57c1767..e513b76 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -44,7 +44,7 @@ #include "lxc_driver.h" #include "lxc_process.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virnetdevbridge.h" #include "virnetdevveth.h" #include "nodeinfo.h" diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h index 9878017..93964a4 100644 --- a/src/lxc/lxc_fuse.h +++ b/src/lxc/lxc_fuse.h @@ -32,7 +32,7 @@ # endif
# include "lxc_conf.h" -# include "util.h" +# include "virutil.h" # include "viralloc.h"
struct virLXCMeminfo { diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 2db9197..dbbd49c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -52,7 +52,7 @@ #include "driver.h" #include "virbuffer.h" #include "virpidfile.h" -#include "util.h" +#include "virutil.h" #include "vircommand.h" #include "viralloc.h" #include "uuid.h" diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index d914816..6cc1837 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -37,7 +37,7 @@ #include "node_device_conf.h" #include "node_device_hal.h" #include "node_device_driver.h" -#include "util.h" +#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_NODEDEV
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 7289a72..d350955 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -35,7 +35,7 @@ #include "virlog.h" #include "viralloc.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "virpci.h"
diff --git a/src/nodeinfo.c b/src/nodeinfo.c index b14e63b..65f4431 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -42,7 +42,7 @@ #include "viralloc.h" #include "nodeinfo.h" #include "physmem.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" #include "count-one-bits.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 6e0f6eb..b0c9c5f 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -49,7 +49,7 @@ #include "uuid.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "nodeinfo.h" #include "virfile.h" #include "vircommand.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index a35a6b1..a407193 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -50,7 +50,7 @@ #include "openvz_driver.h" #include "openvz_util.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "openvz_conf.h" #include "nodeinfo.h" #include "viralloc.h" diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 07c1463..87d098e 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -44,7 +44,7 @@ #include "datatypes.h" #include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "vircommand.h" #include "configmake.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index ad56686..25b96b4 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -45,7 +45,7 @@
#include "internal.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "datatypes.h" #include "virbuffer.h" #include "viralloc.h" diff --git a/src/qemu/qemu_bridge_filter.c b/src/qemu/qemu_bridge_filter.c index 08a9f1a..6d84f47 100644 --- a/src/qemu/qemu_bridge_filter.c +++ b/src/qemu/qemu_bridge_filter.c @@ -25,7 +25,7 @@ #include "virebtables.h" #include "qemu_conf.h" #include "qemu_driver.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virlog.h"
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 46f8540..7a27183 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index b47fb78..9db7ad9 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -30,7 +30,7 @@ #include "virlog.h" #include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "domain_audit.h"
#define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 464288f..23ccffe 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "virlog.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "uuid.h" #include "c-ctype.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index d6bc1fc..be88d77 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -43,7 +43,7 @@ #include "uuid.h" #include "virbuffer.h" #include "virconf.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "datatypes.h" #include "xml.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 170f15d..15b773b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -63,7 +63,7 @@ #include "virlog.h" #include "datatypes.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "nodeinfo.h" #include "virstatslinux.h" #include "capabilities.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index a77beb6..1e83e3c 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -39,7 +39,7 @@ #include "virlog.h" #include "virterror_internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "datatypes.h" #include "fdstream.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 794596b..d4eaa9e 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -57,7 +57,7 @@ #include "virhooks.h" #include "virfile.h" #include "virpidfile.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "nodeinfo.h" #include "domain_audit.h" diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 2edf6e6..ac7dc87 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -39,7 +39,7 @@ #include "remote_protocol.h" #include "qemu_protocol.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "vircommand.h" #include "intprops.h" diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index 5c14e14..18be350 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -26,7 +26,7 @@ #include "virthread.h" #include "virfile.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virnetsocket.h" #include "virkeepaliveprotocol.h" diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 85787f0..9347f0b 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -34,7 +34,7 @@ #include "virthread.h" #include "virfile.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c index 00948e0..eff4a4c 100644 --- a/src/rpc/virnetclientprogram.c +++ b/src/rpc/virnetclientprogram.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virthread.h"
diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c index f273811..b2da65b 100644 --- a/src/rpc/virnetmessage.c +++ b/src/rpc/virnetmessage.c @@ -28,7 +28,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "virfile.h" -#include "util.h" +#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_RPC
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index b48af5e..47a6293 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virthread.h" #include "virthreadpool.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virnetservermdns.h" #include "virdbus.h" diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 442850a..a959c30 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -41,7 +41,7 @@
#include "c-ctype.h" #include "virnetsocket.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index 663b7cd..ad8bd48 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -31,7 +31,7 @@ #include "virlog.h" #include "configmake.h" #include "virthread.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virobject.h"
diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 1ff40cf..b01de8c 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -32,7 +32,7 @@
#include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virthread.h" #include "configmake.h" diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 672ff54..8dfd921 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -37,7 +37,7 @@ #include "secret_conf.h" #include "secret_driver.h" #include "virthread.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "virterror_internal.h" #include "virfile.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index d28189f..4027cdf 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -38,7 +38,7 @@ #include "internal.h"
#include "security_apparmor.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index f9752ef..3104f42 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -25,7 +25,7 @@
#include "security_dac.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "virpci.h" diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 8918257..ccba258 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -34,7 +34,7 @@ #include "security_driver.h" #include "security_selinux.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "virpci.h" @@ -43,7 +43,7 @@ #include "virfile.h" #include "virhash.h" #include "virrandom.h" -#include "util.h" +#include "virutil.h" #include "virconf.h"
Same applies here
#define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 4945f7c..5cfa3ff 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -41,7 +41,7 @@
#include "internal.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircommand.h"
diff --git a/src/storage/parthelper.c b/src/storage/parthelper.c index 5417ced..83f8279 100644 --- a/src/storage/parthelper.c +++ b/src/storage/parthelper.c @@ -41,7 +41,7 @@ #include <unistd.h> #include <locale.h>
-#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "configmake.h"
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 9b98dbb..29272f1 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -47,7 +47,7 @@
#include "datatypes.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "internal.h" #include "secret_conf.h" diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c index 8759b3a..aceb82b 100644 --- a/src/storage/storage_backend_disk.c +++ b/src/storage/storage_backend_disk.c @@ -29,7 +29,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "storage_backend_disk.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircommand.h" #include "configmake.h" diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index ecb8f8e..e91c4b1 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -37,7 +37,7 @@ #include "virterror_internal.h" #include "storage_backend_scsi.h" #include "storage_backend_iscsi.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index e1f07ab..ffa3234 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -25,7 +25,7 @@ #include "virterror_internal.h" #include "storage_backend_rbd.h" #include "storage_conf.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "base64.h" diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c index d3b9d87..1046ac9 100644 --- a/src/storage/storage_backend_sheepdog.c +++ b/src/storage/storage_backend_sheepdog.c @@ -30,7 +30,7 @@ #include "storage_backend_sheepdog.h" #include "storage_conf.h" #include "vircommand.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h"
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index aebf8bb..d93617c 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -39,7 +39,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "driver.h" -#include "util.h" +#include "virutil.h" #include "storage_driver.h" #include "storage_conf.h" #include "viralloc.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 185bb3b..da76367 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -36,7 +36,7 @@ #include "datatypes.h" #include "test_driver.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "capabilities.h" #include "viralloc.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 6da311b..b2057e8 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -39,7 +39,7 @@ #include "uuid.h" #include "virbuffer.h" #include "virconf.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "nodeinfo.h" #include "virlog.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index b20998f..05fb7f2 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -47,7 +47,7 @@ #include "uml_driver.h" #include "uml_conf.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "nodeinfo.h" #include "virstatslinux.h" #include "capabilities.h" diff --git a/src/util/iohelper.c b/src/util/iohelper.c index dcb5c14..40b04f9 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -33,7 +33,7 @@ #include <stdio.h> #include <stdlib.h>
-#include "util.h" +#include "virutil.h" #include "virthread.h" #include "virfile.h" #include "viralloc.h" diff --git a/src/util/util.c b/src/util/util.c deleted file mode 100644 index c7d4aa5..0000000 --- a/src/util/util.c +++ /dev/null @@ -1,3131 +0,0 @@ -/* - * utils.c: common, generic utility functions - * - * Copyright (C) 2006-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <poll.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/wait.h> -#if HAVE_MMAP -# include <sys/mman.h> -#endif -#include <string.h> -#include <signal.h> -#include <termios.h> -#include <pty.h> -#include <locale.h> - -#if HAVE_LIBDEVMAPPER_H -# include <libdevmapper.h> -#endif - -#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 -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -# include <mntent.h> -#endif - -#ifdef WIN32 -# ifdef HAVE_WINSOCK2_H -# include <winsock2.h> -# endif -# include <windows.h> -# include <shlobj.h> -#endif - -#include "c-ctype.h" -#include "dirname.h" -#include "virterror_internal.h" -#include "virlog.h" -#include "virbuffer.h" -#include "util.h" -#include "virstoragefile.h" -#include "viralloc.h" -#include "virthread.h" -#include "verify.h" -#include "virfile.h" -#include "vircommand.h" -#include "nonblocking.h" -#include "passfd.h" -#include "virprocess.h" - -#ifndef NSIG -# define NSIG 32 -#endif - -verify(sizeof(gid_t) <= sizeof(unsigned int) && - sizeof(uid_t) <= sizeof(unsigned int)); - -#define VIR_FROM_THIS VIR_FROM_NONE - -/* Like read(), but restarts after EINTR */ -ssize_t -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, off_t offset, off_t len) -{ - int ret = posix_fallocate(fd, offset, len); - if (ret == 0) - return 0; - errno = ret; - return -1; -} -#else - -# ifdef HAVE_MMAP -int safezero(int fd, 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 -1; - - buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); - if (buf == MAP_FAILED) - return -1; - - memset(buf, 0, len); - munmap(buf, len); - - return 0; -} - -# else /* HAVE_MMAP */ - -int safezero(int fd, off_t offset, off_t len) -{ - int r; - char *buf; - unsigned long long remain, bytes; - - if (lseek(fd, offset, SEEK_SET) < 0) - return -1; - - /* 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) { - errno = ENOMEM; - return -1; - } - - while (remain) { - if (bytes > remain) - bytes = remain; - - r = safewrite(fd, buf, bytes); - if (r < 0) { - VIR_FREE(buf); - return -1; - } - - /* safewrite() guarantees all data will be written */ - remain -= bytes; - } - VIR_FREE(buf); - return 0; -} -# endif /* HAVE_MMAP */ -#endif /* HAVE_POSIX_FALLOCATE */ - -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; -} - -#ifndef WIN32 - -int virSetInherit(int fd, bool inherit) { - int fflags; - if ((fflags = fcntl(fd, F_GETFD)) < 0) - return -1; - if (inherit) - fflags &= ~FD_CLOEXEC; - else - fflags |= FD_CLOEXEC; - if ((fcntl(fd, F_SETFD, fflags)) < 0) - return -1; - return 0; -} - -#else /* WIN32 */ - -int virSetInherit(int fd ATTRIBUTE_UNUSED, bool inherit ATTRIBUTE_UNUSED) -{ - /* FIXME: Currently creating child processes is not supported on - * Win32, so there is no point in failing calls that are only relevant - * when creating child processes. So just pretend that we changed the - * inheritance property of the given fd as requested. */ - return 0; -} - -#endif /* WIN32 */ - -int virSetBlocking(int fd, bool blocking) { - return set_nonblocking_flag(fd, !blocking); -} - -int virSetNonBlock(int fd) { - return virSetBlocking(fd, false); -} - -int virSetCloseExec(int fd) -{ - return virSetInherit(fd, false); -} - -int -virPipeReadUntilEOF(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; - fds[0].revents = 0; - finished[0] = 0; - fds[1].fd = errfd; - fds[1].events = POLLIN; - fds[1].revents = 0; - 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; - - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Unknown poll response.")); - goto error; - } - - got = read(fds[i].fd, data, sizeof(data)); - - if (got == sizeof(data)) - finished[i] = 0; - - 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(); - goto error; - } - memmove(*buf+size, data, got); - (*buf)[size+got] = '\0'; - } - continue; - - pollerr: - virReportSystemError(errno, - "%s", _("poll error")); - goto error; - } - - return 0; - -error: - VIR_FREE(*outbuf); - VIR_FREE(*errbuf); - return -1; -} - -/* 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 * -saferead_lim(int fd, size_t max_len, size_t *length) -{ - char *buf = NULL; - size_t alloc = 0; - size_t size = 0; - int save_errno; - - for (;;) { - int count; - int 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 = saferead(fd, buf + size, requested); - size += count; - - if (count != requested || requested == 0) { - save_errno = errno; - if (count < 0) - break; - buf[size] = '\0'; - *length = size; - return buf; - } - } - - VIR_FREE(buf); - errno = save_errno; - return NULL; -} - -/* A wrapper around saferead_lim that maps a failure due to - exceeding the maximum size limitation to EOVERFLOW. */ -int -virFileReadLimFD(int fd, int maxlen, char **buf) -{ - size_t len; - char *s; - - if (maxlen <= 0) { - errno = EINVAL; - return -1; - } - s = saferead_lim(fd, 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; -} - -int virFileReadAll(const char *path, int maxlen, char **buf) -{ - int fd = open(path, O_RDONLY); - if (fd < 0) { - virReportSystemError(errno, _("Failed to open file '%s'"), path); - return -1; - } - - int len = virFileReadLimFD(fd, maxlen, buf); - VIR_FORCE_CLOSE(fd); - if (len < 0) { - virReportSystemError(errno, _("Failed to read file '%s'"), path); - return -1; - } - - return len; -} - -/* Truncate @path and write @str to it. If @mode is 0, ensure that - @path exists; otherwise, use @mode if @path must be created. - Return 0 for success, nonzero for failure. - Be careful to preserve any errno value upon failure. */ -int virFileWriteStr(const char *path, const char *str, mode_t mode) -{ - int fd; - - if (mode) - fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode); - else - fd = open(path, O_WRONLY|O_TRUNC); - if (fd == -1) - return -1; - - if (safewrite(fd, str, strlen(str)) < 0) { - VIR_FORCE_CLOSE(fd); - return -1; - } - - /* Use errno from failed close only if there was no write error. */ - if (VIR_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 STRCASEEQ(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)); -} - - - -static int -virFileResolveLinkHelper(const char *linkpath, - bool intermediatePaths, - char **resultpath) -{ - struct stat st; - - *resultpath = NULL; - - /* We don't need the full canonicalization of intermediate - * directories, if linkpath is absolute and the basename is - * already a non-symlink. */ - if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) { - if (lstat(linkpath, &st) < 0) - return -1; - - if (!S_ISLNK(st.st_mode)) { - if (!(*resultpath = strdup(linkpath))) - return -1; - return 0; - } - } - - *resultpath = canonicalize_file_name(linkpath); - - return *resultpath == NULL ? -1 : 0; -} - -/* - * Attempt to resolve a symbolic link, returning an - * absolute path where only the last component is guaranteed - * not to be a symlink. - * - * Return 0 if path was not a symbolic, or the link was - * resolved. Return -1 with errno set upon error - */ -int virFileResolveLink(const char *linkpath, - char **resultpath) -{ - return virFileResolveLinkHelper(linkpath, false, resultpath); -} - -/* - * Attempt to resolve a symbolic link, returning an - * absolute path where every component is guaranteed - * not to be a symlink. - * - * Return 0 if path was not a symbolic, or the link was - * resolved. Return -1 with errno set upon error - */ -int virFileResolveAllLinks(const char *linkpath, - char **resultpath) -{ - return virFileResolveLinkHelper(linkpath, true, resultpath); -} - -/* - * Check whether the given file is a link. - * Returns 1 in case of the file being a link, 0 in case it is not - * a link and the negative errno in all other cases. - */ -int virFileIsLink(const char *linkpath) -{ - struct stat st; - - if (lstat(linkpath, &st) < 0) - return -errno; - - return S_ISLNK(st.st_mode) != 0; -} - - -/* - * Finds a requested executable 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 *path = NULL; - char *pathiter; - char *pathseg; - char *fullpath = NULL; - - if (file == NULL) - return NULL; - - /* if we are passed an absolute path (starting with /), return a - * copy of that path, after validating that it is executable - */ - if (IS_ABSOLUTE_FILE_NAME(file)) { - if (virFileIsExecutable(file)) - return strdup(file); - else - return NULL; - } - - /* If we are passed an anchored path (containing a /), then there - * is no path search - it must exist in the current directory - */ - if (strchr(file, '/')) { - if (virFileIsExecutable(file)) - ignore_value(virFileAbsPath(file, &path)); - return path; - } - - /* copy PATH env so we can tweak it */ - path = getenv("PATH"); - - if (path == NULL || (path = strdup(path)) == NULL) - return NULL; - - /* for each path segment, append the file to search for and test for - * it. return it if found. - */ - pathiter = path; - while ((pathseg = strsep(&pathiter, ":")) != NULL) { - if (virAsprintf(&fullpath, "%s/%s", pathseg, file) < 0 || - virFileIsExecutable(fullpath)) - break; - VIR_FREE(fullpath); - } - - VIR_FREE(path); - return fullpath; -} - -bool virFileIsDir(const char *path) -{ - struct stat s; - return (stat(path, &s) == 0) && S_ISDIR(s.st_mode); -} - -bool virFileExists(const char *path) -{ - return access(path, F_OK) == 0; -} - -/* Check that a file is regular and has executable bits. If false is - * returned, errno is valid. - * - * Note: In the presence of ACLs, this may return true for a file that - * would actually fail with EACCES for a given user, or false for a - * file that the user could actually execute, but setups with ACLs - * that weird are unusual. */ -bool -virFileIsExecutable(const char *file) -{ - struct stat sb; - - /* We would also want to check faccessat if we cared about ACLs, - * but we don't. */ - if (stat(file, &sb) < 0) - return false; - if (S_ISREG(sb.st_mode) && (sb.st_mode & 0111) != 0) - return true; - errno = S_ISDIR(sb.st_mode) ? EISDIR : EACCES; - return false; -} - -#ifndef WIN32 -/* Check that a file is accessible under certain - * user & gid. - * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK. - * see 'man access' for more details. - * Returns 0 on success, -1 on fail with errno set. - */ -int -virFileAccessibleAs(const char *path, int mode, - uid_t uid, gid_t gid) -{ - pid_t pid = 0; - int status, ret = 0; - int forkRet = 0; - - if (uid == getuid() && - gid == getgid()) - return access(path, mode); - - forkRet = virFork(&pid); - - if (pid < 0) { - return -1; - } - - if (pid) { /* parent */ - if (virProcessWait(pid, &status) < 0) { - /* virProcessWait() already - * reported error */ - return -1; - } - - if (!WIFEXITED(status)) { - errno = EINTR; - return -1; - } - - if (status) { - errno = WEXITSTATUS(status); - return -1; - } - - return 0; - } - - /* child. - * Return positive value here. Parent - * will change it to negative one. */ - - if (forkRet < 0) { - ret = errno; - goto childerror; - } - - if (virSetUIDGID(uid, gid) < 0) { - ret = errno; - goto childerror; - } - - if (access(path, mode) < 0) - ret = errno; - -childerror: - if ((ret & 0xFF) != ret) { - VIR_WARN("unable to pass desired return value %d", ret); - ret = 0xFF; - } - - _exit(ret); -} - -/* virFileOpenForceOwnerMode() - an internal utility function called - * only by virFileOpenAs(). Sets the owner and mode of the file - * opened as "fd" if it's not correct AND the flags say it should be - * forced. */ -static int -virFileOpenForceOwnerMode(const char *path, int fd, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) -{ - int ret = 0; - struct stat st; - - if (!(flags & (VIR_FILE_OPEN_FORCE_OWNER | VIR_FILE_OPEN_FORCE_MODE))) - return 0; - - if (fstat(fd, &st) == -1) { - ret = -errno; - virReportSystemError(errno, _("stat of '%s' failed"), path); - return ret; - } - /* NB: uid:gid are never "-1" (default) at this point - the caller - * has always changed -1 to the value of get[gu]id(). - */ - if ((flags & VIR_FILE_OPEN_FORCE_OWNER) && - ((st.st_uid != uid) || (st.st_gid != gid)) && - (fchown(fd, uid, gid) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot chown '%s' to (%u, %u)"), - path, (unsigned int) uid, - (unsigned int) gid); - return ret; - } - if ((flags & VIR_FILE_OPEN_FORCE_MODE) && - ((mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != - (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) && - (fchmod(fd, mode) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot set mode of '%s' to %04o"), - path, mode); - return ret; - } - return ret; -} - -/* virFileOpenForked() - an internal utility function called only by - * virFileOpenAs(). It forks, then the child does setuid+setgid to - * given uid:gid and attempts to open the file, while the parent just - * calls recvfd to get the open fd back from the child. returns the - * fd, or -errno if there is an error. */ -static int -virFileOpenForked(const char *path, int openflags, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) -{ - pid_t pid; - int waitret, status, ret = 0; - int fd = -1; - int pair[2] = { -1, -1 }; - int forkRet; - - /* parent is running as root, but caller requested that the - * file be opened as some other user and/or group). The - * following dance avoids problems caused by root-squashing - * NFS servers. */ - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { - ret = -errno; - virReportSystemError(errno, - _("failed to create socket needed for '%s'"), - path); - return ret; - } - - forkRet = virFork(&pid); - if (pid < 0) - return -errno; - - if (pid == 0) { - - /* child */ - - VIR_FORCE_CLOSE(pair[0]); /* preserves errno */ - if (forkRet < 0) { - /* error encountered and logged in virFork() after the fork. */ - ret = -errno; - goto childerror; - } - - /* set desired uid/gid, then attempt to create the file */ - - if (virSetUIDGID(uid, gid) < 0) { - ret = -errno; - goto childerror; - } - - if ((fd = open(path, openflags, mode)) < 0) { - ret = -errno; - virReportSystemError(errno, - _("child process failed to create file '%s'"), - path); - goto childerror; - } - - /* File is successfully open. Set permissions if requested. */ - ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); - if (ret < 0) - goto childerror; - - do { - ret = sendfd(pair[1], fd); - } while (ret < 0 && errno == EINTR); - - if (ret < 0) { - ret = -errno; - virReportSystemError(errno, "%s", - _("child process failed to send fd to parent")); - goto childerror; - } - - childerror: - /* ret tracks -errno on failure, but exit value must be positive. - * If the child exits with EACCES, then the parent tries again. */ - /* XXX This makes assumptions about errno being < 255, which is - * not true on Hurd. */ - VIR_FORCE_CLOSE(pair[1]); - if (ret < 0) { - VIR_FORCE_CLOSE(fd); - } - ret = -ret; - if ((ret & 0xff) != ret) { - VIR_WARN("unable to pass desired return value %d", ret); - ret = 0xff; - } - _exit(ret); - } - - /* parent */ - - VIR_FORCE_CLOSE(pair[1]); - - do { - fd = recvfd(pair[0], 0); - } while (fd < 0 && errno == EINTR); - VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */ - - if (fd < 0 && errno != EACCES) { - ret = -errno; - while (waitpid(pid, NULL, 0) == -1 && errno == EINTR); - return ret; - } - - /* wait for child to complete, and retrieve its exit code */ - while ((waitret = waitpid(pid, &status, 0) == -1) - && (errno == EINTR)); - if (waitret == -1) { - ret = -errno; - virReportSystemError(errno, - _("failed to wait for child creating '%s'"), - path); - VIR_FORCE_CLOSE(fd); - return ret; - } - if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES || - fd == -1) { - /* fall back to the simpler method, which works better in - * some cases */ - VIR_FORCE_CLOSE(fd); - if (flags & VIR_FILE_OPEN_NOFORK) { - /* If we had already tried opening w/o fork+setuid and - * failed, no sense trying again. Just set return the - * original errno that we got at that time (by - * definition, always either EACCES or EPERM - EACCES - * is close enough). - */ - return -EACCES; - } - if ((fd = open(path, openflags, mode)) < 0) - return -errno; - ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); - if (ret < 0) { - VIR_FORCE_CLOSE(fd); - return ret; - } - } - return fd; -} - -/** - * virFileOpenAs: - * @path: file to open or create - * @openflags: flags to pass to open - * @mode: mode to use on creation or when forcing permissions - * @uid: uid that should own file on creation - * @gid: gid that should own file - * @flags: bit-wise or of VIR_FILE_OPEN_* flags - * - * Open @path, and return an fd to the open file. @openflags contains - * the flags normally passed to open(2), while those in @flags are - * used internally. If @flags includes VIR_FILE_OPEN_NOFORK, then try - * opening the file while executing with the current uid:gid - * (i.e. don't fork+setuid+setgid before the call to open()). If - * @flags includes VIR_FILE_OPEN_FORK, then try opening the file while - * the effective user id is @uid (by forking a child process); this - * allows one to bypass root-squashing NFS issues; NOFORK is always - * tried before FORK (the absence of both flags is treated identically - * to (VIR_FILE_OPEN_NOFORK | VIR_FILE_OPEN_FORK)). If @flags includes - * VIR_FILE_OPEN_FORCE_OWNER, then ensure that @path is owned by - * uid:gid before returning (even if it already existed with a - * different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE, - * ensure it has those permissions before returning (again, even if - * the file already existed with different permissions). The return - * value (if non-negative) is the file descriptor, left open. Returns - * -errno on failure. */ -int -virFileOpenAs(const char *path, int openflags, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) -{ - int ret = 0, fd = -1; - - /* allow using -1 to mean "current value" */ - if (uid == (uid_t) -1) - uid = getuid(); - if (gid == (gid_t) -1) - gid = getgid(); - - /* treat absence of both flags as presence of both for simpler - * calling. */ - if (!(flags & (VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK))) - flags |= VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK; - - if ((flags & VIR_FILE_OPEN_NOFORK) - || (getuid() != 0) - || ((uid == 0) && (gid == 0))) { - - if ((fd = open(path, openflags, mode)) < 0) { - ret = -errno; - } else { - ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); - if (ret < 0) - goto error; - } - } - - /* If we either 1) didn't try opening as current user at all, or - * 2) failed, and errno/virStorageFileIsSharedFS indicate we might - * be successful if we try as a different uid, then try doing - * fork+setuid+setgid before opening. - */ - if ((fd < 0) && (flags & VIR_FILE_OPEN_FORK)) { - - if (ret < 0) { - /* An open(2) that failed due to insufficient permissions - * could return one or the other of these depending on OS - * version and circumstances. Any other errno indicates a - * problem that couldn't be remedied by fork+setuid - * anyway. */ - if (ret != -EACCES && ret != -EPERM) - goto error; - - /* On Linux we can also verify the FS-type of the - * directory. (this is a NOP on other platforms). */ - switch (virStorageFileIsSharedFS(path)) { - case 1: - /* it was on a network share, so we'll re-try */ - break; - case -1: - /* failure detecting fstype */ - virReportSystemError(errno, _("couldn't determine fs type " - "of mount containing '%s'"), path); - goto error; - case 0: - default: - /* file isn't on a recognized network FS */ - goto error; - } - } - - /* passed all prerequisites - retry the open w/fork+setuid */ - if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) { - ret = fd; - fd = -1; - goto error; - } - } - - /* File is successfully opened */ - - return fd; - -error: - if (fd < 0) { - /* whoever failed the open last has already set ret = -errno */ - virReportSystemError(-ret, openflags & O_CREAT - ? _("failed to create file '%s'") - : _("failed to open file '%s'"), - path); - } else { - /* some other failure after the open succeeded */ - VIR_FORCE_CLOSE(fd); - } - return ret; -} - -/* return -errno on failure, or 0 on success */ -static int virDirCreateNoFork(const char *path, mode_t mode, uid_t uid, gid_t gid, - unsigned int flags) { - int ret = 0; - struct stat st; - - if ((mkdir(path, mode) < 0) - && !((errno == EEXIST) && (flags & VIR_DIR_CREATE_ALLOW_EXIST))) { - ret = -errno; - virReportSystemError(errno, _("failed to create directory '%s'"), - path); - goto error; - } - - if (stat(path, &st) == -1) { - ret = -errno; - virReportSystemError(errno, _("stat of '%s' failed"), path); - goto error; - } - if (((st.st_uid != uid) || (st.st_gid != gid)) - && (chown(path, uid, gid) < 0)) { - ret = -errno; - virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"), - path, (unsigned int) uid, (unsigned int) gid); - goto error; - } - if ((flags & VIR_DIR_CREATE_FORCE_PERMS) - && (chmod(path, mode) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot set mode of '%s' to %04o"), - path, mode); - goto error; - } -error: - return ret; -} - -/* return -errno on failure, or 0 on success */ -int virDirCreate(const char *path, mode_t mode, - uid_t uid, gid_t gid, unsigned int flags) { - struct stat st; - pid_t pid; - int waitret; - int status, ret = 0; - - /* allow using -1 to mean "current value" */ - if (uid == (uid_t) -1) - uid = getuid(); - if (gid == (gid_t) -1) - gid = getgid(); - - if ((!(flags & VIR_DIR_CREATE_AS_UID)) - || (getuid() != 0) - || ((uid == 0) && (gid == 0)) - || ((flags & VIR_DIR_CREATE_ALLOW_EXIST) && (stat(path, &st) >= 0))) { - return virDirCreateNoFork(path, mode, uid, gid, flags); - } - - int forkRet = virFork(&pid); - - if (pid < 0) { - ret = -errno; - return ret; - } - - if (pid) { /* parent */ - /* wait for child to complete, and retrieve its exit code */ - while ((waitret = waitpid(pid, &status, 0) == -1) && (errno == EINTR)); - if (waitret == -1) { - ret = -errno; - virReportSystemError(errno, - _("failed to wait for child creating '%s'"), - path); - goto parenterror; - } - if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) { - /* fall back to the simpler method, which works better in - * some cases */ - return virDirCreateNoFork(path, mode, uid, gid, flags); - } -parenterror: - return ret; - } - - /* child */ - - if (forkRet < 0) { - /* error encountered and logged in virFork() after the fork. */ - goto childerror; - } - - /* set desired uid/gid, then attempt to create the directory */ - - if (virSetUIDGID(uid, gid) < 0) { - ret = -errno; - goto childerror; - } - if (mkdir(path, mode) < 0) { - ret = -errno; - if (ret != -EACCES) { - /* in case of EACCES, the parent will retry */ - virReportSystemError(errno, _("child failed to create directory '%s'"), - path); - } - goto childerror; - } - /* check if group was set properly by creating after - * setgid. If not, try doing it with chown */ - if (stat(path, &st) == -1) { - ret = -errno; - virReportSystemError(errno, - _("stat of '%s' failed"), path); - goto childerror; - } - if ((st.st_gid != gid) && (chown(path, -1, gid) < 0)) { - ret = -errno; - virReportSystemError(errno, - _("cannot chown '%s' to group %u"), - path, (unsigned int) gid); - goto childerror; - } - if ((flags & VIR_DIR_CREATE_FORCE_PERMS) - && chmod(path, mode) < 0) { - virReportSystemError(errno, - _("cannot set mode of '%s' to %04o"), - path, mode); - goto childerror; - } -childerror: - _exit(ret); -} - -#else /* WIN32 */ - -int -virFileAccessibleAs(const char *path, - int mode, - uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED) -{ - - VIR_WARN("Ignoring uid/gid due to WIN32"); - - return access(path, mode); -} - -/* return -errno on failure, or 0 on success */ -int virFileOpenAs(const char *path ATTRIBUTE_UNUSED, - int openflags ATTRIBUTE_UNUSED, - mode_t mode ATTRIBUTE_UNUSED, - uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED, - unsigned int flags_unused ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virFileOpenAs is not implemented for WIN32")); - - return -ENOSYS; -} - -int virDirCreate(const char *path ATTRIBUTE_UNUSED, - mode_t mode ATTRIBUTE_UNUSED, - uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED, - unsigned int flags_unused ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virDirCreate is not implemented for WIN32")); - - return -ENOSYS; -} -#endif /* WIN32 */ - -static int virFileMakePathHelper(char *path, mode_t mode) -{ - struct stat st; - char *p; - - VIR_DEBUG("path=%s mode=0%o", path, mode); - - if (stat(path, &st) >= 0) { - if (S_ISDIR(st.st_mode)) - return 0; - - errno = ENOTDIR; - return -1; - } - - if (errno != ENOENT) - return -1; - - if ((p = strrchr(path, '/')) == NULL) { - errno = EINVAL; - return -1; - } - - if (p != path) { - *p = '\0'; - - if (virFileMakePathHelper(path, mode) < 0) - return -1; - - *p = '/'; - } - - if (mkdir(path, mode) < 0 && errno != EEXIST) - return -1; - - return 0; -} - -/** - * Creates the given directory with mode 0777 if it's not already existing. - * - * Returns 0 on success, or -1 if an error occurred (in which case, errno - * is set appropriately). - */ -int virFileMakePath(const char *path) -{ - return virFileMakePathWithMode(path, 0777); -} - -int -virFileMakePathWithMode(const char *path, - mode_t mode) -{ - int ret = -1; - char *tmp; - - if ((tmp = strdup(path)) == NULL) - goto cleanup; - - ret = virFileMakePathHelper(tmp, mode); - -cleanup: - VIR_FREE(tmp); - return ret; -} - -/* Build up a fully qualified path for a config file to be - * associated with a persistent guest or network */ -char * -virFileBuildPath(const char *dir, const char *name, const char *ext) -{ - char *path; - - if (ext == NULL) { - if (virAsprintf(&path, "%s/%s", dir, name) < 0) { - virReportOOMError(); - return NULL; - } - } else { - if (virAsprintf(&path, "%s/%s%s", dir, name, ext) < 0) { - virReportOOMError(); - return NULL; - } - } - - return path; -} - -/* Open a non-blocking master side of a pty. If ttyName is not NULL, - * then populate it with the name of the slave. If rawmode is set, - * also put the master side into raw mode before returning. */ -#ifndef WIN32 -int virFileOpenTty(int *ttymaster, - char **ttyName, - int rawmode) -{ - /* XXX A word of caution - on some platforms (Solaris and HP-UX), - * additional ioctl() calls are needs after opening the slave - * before it will cause isatty() to return true. Should we make - * virFileOpenTty also return the opened slave fd, so the caller - * doesn't have to worry about that mess? */ - int ret = -1; - int slave = -1; - char *name = NULL; - - /* Unfortunately, we can't use the name argument of openpty, since - * there is no guarantee on how large the buffer has to be. - * Likewise, we can't use the termios argument: we have to use - * read-modify-write since there is no portable way to initialize - * a struct termios without use of tcgetattr. */ - if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0) - return -1; - - /* What a shame that openpty cannot atomically set FD_CLOEXEC, but - * that using posix_openpt/grantpt/unlockpt/ptsname is not - * thread-safe, and that ptsname_r is not portable. */ - if (virSetNonBlock(*ttymaster) < 0 || - virSetCloseExec(*ttymaster) < 0) - goto cleanup; - - /* While Linux supports tcgetattr on either the master or the - * slave, Solaris requires it to be on the slave. */ - if (rawmode) { - struct termios ttyAttr; - if (tcgetattr(slave, &ttyAttr) < 0) - goto cleanup; - - cfmakeraw(&ttyAttr); - - if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0) - goto cleanup; - } - - /* ttyname_r on the slave is required by POSIX, while ptsname_r on - * the master is a glibc extension, and the POSIX ptsname is not - * thread-safe. Since openpty gave us both descriptors, guess - * which way we will determine the name? :) */ - if (ttyName) { - /* Initial guess of 64 is generally sufficient; rely on ERANGE - * to tell us if we need to grow. */ - size_t len = 64; - int rc; - - if (VIR_ALLOC_N(name, len) < 0) - goto cleanup; - - while ((rc = ttyname_r(slave, name, len)) == ERANGE) { - if (VIR_RESIZE_N(name, len, len, len) < 0) - goto cleanup; - } - if (rc != 0) { - errno = rc; - goto cleanup; - } - *ttyName = name; - name = NULL; - } - - ret = 0; - -cleanup: - if (ret != 0) - VIR_FORCE_CLOSE(*ttymaster); - VIR_FORCE_CLOSE(slave); - VIR_FREE(name); - - return ret; -} -#else /* WIN32 */ -int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED, - char **ttyName ATTRIBUTE_UNUSED, - int rawmode ATTRIBUTE_UNUSED) -{ - /* mingw completely lacks pseudo-terminals, and the gnulib - * replacements are not (yet) license compatible. */ - errno = ENOSYS; - return -1; -} -#endif /* WIN32 */ - -bool virFileIsAbsPath(const char *path) -{ - if (!path) - return false; - - if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) - return true; - -#ifdef WIN32 - if (c_isalpha(path[0]) && - path[1] == ':' && - VIR_FILE_IS_DIR_SEPARATOR(path[2])) - return true; -#endif - - return false; -} - - -const char *virFileSkipRoot(const char *path) -{ -#ifdef WIN32 - /* Skip \\server\share or //server/share */ - if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) && - VIR_FILE_IS_DIR_SEPARATOR(path[1]) && - path[2] && - !VIR_FILE_IS_DIR_SEPARATOR(path[2])) - { - const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR); - const char *q = strchr(path + 2, '/'); - - if (p == NULL || (q != NULL && q < p)) - p = q; - - if (p && p > path + 2 && p[1]) { - path = p + 1; - - while (path[0] && - !VIR_FILE_IS_DIR_SEPARATOR(path[0])) - path++; - - /* Possibly skip a backslash after the share name */ - if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) - path++; - - return path; - } - } -#endif - - /* Skip initial slashes */ - if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) { - while (VIR_FILE_IS_DIR_SEPARATOR(path[0])) - path++; - - return path; - } - -#ifdef WIN32 - /* Skip X:\ */ - if (c_isalpha(path[0]) && - path[1] == ':' && - VIR_FILE_IS_DIR_SEPARATOR(path[2])) - return path + 3; -#endif - - return path; -} - - - -/* - * Creates an absolute path for a potentially relative path. - * Return 0 if the path was not relative, or on success. - * Return -1 on error. - * - * You must free the result. - */ -int virFileAbsPath(const char *path, char **abspath) -{ - char *buf; - - if (path[0] == '/') { - if (!(*abspath = strdup(path))) - return -1; - } else { - buf = getcwd(NULL, 0); - if (buf == NULL) - return -1; - - if (virAsprintf(abspath, "%s/%s", buf, path) < 0) { - VIR_FREE(buf); - return -1; - } - VIR_FREE(buf); - } - - return 0; -} - -/* Remove spurious / characters from a path. The result must be freed */ -char * -virFileSanitizePath(const char *path) -{ - const char *cur = path; - char *cleanpath; - int idx = 0; - - cleanpath = strdup(path); - if (!cleanpath) { - virReportOOMError(); - return NULL; - } - - /* Need to sanitize: - * // -> // - * /// -> / - * /../foo -> /../foo - * /foo///bar/ -> /foo/bar - */ - - /* Starting with // is valid posix, but ///foo == /foo */ - if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') { - idx = 2; - cur += 2; - } - - /* Sanitize path in place */ - while (*cur != '\0') { - if (*cur != '/') { - cleanpath[idx++] = *cur++; - continue; - } - - /* Skip all extra / */ - while (*++cur == '/') - continue; - - /* Don't add a trailing / */ - if (idx != 0 && *cur == '\0') - break; - - cleanpath[idx++] = '/'; - } - cleanpath[idx] = '\0'; - - return cleanpath; -} - -/* 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); /* exempt from syntax-check */ - 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); /* exempt from syntax-check */ - 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 a "long" value. */ -int -virStrToLong_l(char const *s, char **end_ptr, int base, long *result) -{ - long int val; - char *p; - int err; - - errno = 0; - val = strtol(s, &p, base); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - if (end_ptr) - *end_ptr = p; - if (err) - return -1; - *result = val; - return 0; -} - -/* Just like virStrToLong_i, above, but produce an "unsigned long" value. */ -int -virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result) -{ - unsigned long int val; - char *p; - int err; - - errno = 0; - val = strtoul(s, &p, base); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - if (end_ptr) - *end_ptr = p; - if (err) - return -1; - *result = val; - return 0; -} - -/* Just like virStrToLong_i, above, but produce a "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); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - 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); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - 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); /* exempt from syntax-check */ - err = (errno || (!end_ptr && *p) || p == s); - if (end_ptr) - *end_ptr = p; - if (err) - return -1; - *result = val; - return 0; -} - -/* Convert C from hexadecimal character to integer. */ -int -virHexToBin(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; - } -} - -/* Scale an integer VALUE in-place by an optional case-insensitive - * SUFFIX, defaulting to SCALE if suffix is NULL or empty (scale is - * typically 1 or 1024). Recognized suffixes include 'b' or 'bytes', - * as well as power-of-two scaling via binary abbreviations ('KiB', - * 'MiB', ...) or their one-letter counterpart ('k', 'M', ...), and - * power-of-ten scaling via SI abbreviations ('KB', 'MB', ...). - * Ensure that the result does not exceed LIMIT. Return 0 on success, - * -1 with error message raised on failure. */ -int -virScaleInteger(unsigned long long *value, const char *suffix, - unsigned long long scale, unsigned long long limit) -{ - if (!suffix || !*suffix) { - if (!scale) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid scale %llu"), scale); - return -1; - } - suffix = ""; - } else if (STRCASEEQ(suffix, "b") || STRCASEEQ(suffix, "byte") || - STRCASEEQ(suffix, "bytes")) { - scale = 1; - } else { - int base; - - if (!suffix[1] || STRCASEEQ(suffix + 1, "iB")) { - base = 1024; - } else if (c_tolower(suffix[1]) == 'b' && !suffix[2]) { - base = 1000; - } else { - virReportError(VIR_ERR_INVALID_ARG, - _("unknown suffix '%s'"), suffix); - return -1; - } - scale = 1; - switch (c_tolower(*suffix)) { - case 'e': - scale *= base; - /* fallthrough */ - case 'p': - scale *= base; - /* fallthrough */ - case 't': - scale *= base; - /* fallthrough */ - case 'g': - scale *= base; - /* fallthrough */ - case 'm': - scale *= base; - /* fallthrough */ - case 'k': - scale *= base; - break; - default: - virReportError(VIR_ERR_INVALID_ARG, - _("unknown suffix '%s'"), suffix); - return -1; - } - } - - if (*value && *value >= (limit / scale)) { - virReportError(VIR_ERR_OVERFLOW, _("value too large: %llu%s"), - *value, suffix); - return -1; - } - *value *= scale; - return 0; -} - -/** - * virSkipSpaces: - * @str: pointer to the char pointer used - * - * Skip potential blanks, this includes space tabs, line feed, - * carriage returns. - */ -void -virSkipSpaces(const char **str) -{ - const char *cur = *str; - - while (c_isspace(*cur)) - cur++; - *str = cur; -} - -/** - * virSkipSpacesAndBackslash: - * @str: pointer to the char pointer used - * - * Like virSkipSpaces, but also skip backslashes erroneously emitted - * by xend - */ -void -virSkipSpacesAndBackslash(const char **str) -{ - const char *cur = *str; - - while (c_isspace(*cur) || *cur == '\\') - cur++; - *str = cur; -} - -/** - * virTrimSpaces: - * @str: string to modify to remove all trailing spaces - * @endp: track the end of the string - * - * If @endp is NULL on entry, then all spaces prior to the trailing - * NUL in @str are removed, by writing NUL into the appropriate - * location. If @endp is non-NULL but points to a NULL pointer, - * then all spaces prior to the trailing NUL in @str are removed, - * NUL is written to the new string end, and endp is set to the - * location of the (new) string end. If @endp is non-NULL and - * points to a non-NULL pointer, then that pointer is used as - * the end of the string, endp is set to the (new) location, but - * no NUL pointer is written into the string. - */ -void -virTrimSpaces(char *str, char **endp) -{ - char *end; - - if (!endp || !*endp) - end = str + strlen(str); - else - end = *endp; - while (end > str && c_isspace(end[-1])) - end--; - if (endp) { - if (!*endp) - *end = '\0'; - *endp = end; - } else { - *end = '\0'; - } -} - -/** - * virSkipSpacesBackwards: - * @str: start of string - * @endp: on entry, *endp must be NULL or a location within @str, on exit, - * will be adjusted to skip trailing spaces, or to NULL if @str had nothing - * but spaces. - */ -void -virSkipSpacesBackwards(const char *str, char **endp) -{ - /* Casting away const is safe, since virTrimSpaces does not - * modify string with this particular usage. */ - char *s = (char*) str; - - if (!*endp) - *endp = s + strlen(s); - virTrimSpaces(s, endp); - if (s == *endp) - *endp = NULL; -} - -/** - * 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; -} - - -/** - * virParseVersionString: - * @str: const char pointer to the version string - * @version: unsigned long pointer to output the version number - * @allowMissing: true to treat 3 like 3.0.0, false to error out on - * missing minor or micro - * - * Parse an unsigned version number from a version string. Expecting - * 'major.minor.micro' format, ignoring an optional suffix. - * - * The major, minor and micro numbers are encoded into a single version number: - * - * 1000000 * major + 1000 * minor + micro - * - * Returns the 0 for success, -1 for error. - */ -int -virParseVersionString(const char *str, unsigned long *version, - bool allowMissing) -{ - unsigned int major, minor = 0, micro = 0; - char *tmp; - - if (virStrToLong_ui(str, &tmp, 10, &major) < 0) - return -1; - - if (!allowMissing && *tmp != '.') - return -1; - - if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, &minor) < 0) - return -1; - - if (!allowMissing && *tmp != '.') - return -1; - - if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, µ) < 0) - return -1; - - if (major > UINT_MAX / 1000000 || minor > 999 || micro > 999) - return -1; - - *version = 1000000 * major + 1000 * minor + micro; - - return 0; -} - -/** - * virVasprintf - * - * like glibc's vasprintf but makes sure *strp == NULL on failure - */ -int -virVasprintf(char **strp, const char *fmt, va_list list) -{ - int ret; - - if ((ret = vasprintf(strp, fmt, list)) == -1) - *strp = NULL; - - 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); - ret = virVasprintf(strp, fmt, ap); - va_end(ap); - return ret; -} - -/** - * virStrncpy - * - * A safe version of strncpy. The last parameter is the number of bytes - * available in the destination string, *not* the number of bytes you want - * to copy. If the destination is not large enough to hold all n of the - * src string bytes plus a \0, NULL is returned and no data is copied. - * If the destination is large enough to hold the n bytes plus \0, then the - * string is copied and a pointer to the destination string is returned. - */ -char * -virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) -{ - char *ret; - - if (n > (destbytes - 1)) - return NULL; - - ret = strncpy(dest, src, n); - /* strncpy NULL terminates iff the last character is \0. Therefore - * force the last byte to be \0 - */ - dest[n] = '\0'; - - return ret; -} - -/** - * virStrcpy - * - * A safe version of strcpy. The last parameter is the number of bytes - * available in the destination string, *not* the number of bytes you want - * to copy. If the destination is not large enough to hold all n of the - * src string bytes plus a \0, NULL is returned and no data is copied. - * If the destination is large enough to hold the source plus \0, then the - * string is copied and a pointer to the destination string is returned. - */ -char * -virStrcpy(char *dest, const char *src, size_t destbytes) -{ - return virStrncpy(dest, src, strlen(src), destbytes); -} - -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; -} - -/* In case thread-safe locales are available */ -#if HAVE_NEWLOCALE - -static locale_t virLocale; - -static int -virLocaleOnceInit(void) -{ - virLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0); - if (!virLocale) - return -1; - return 0; -} - -VIR_ONCE_GLOBAL_INIT(virLocale) -#endif - -/** - * virDoubleToStr - * - * converts double to string with C locale (thread-safe). - * - * Returns -1 on error, size of the string otherwise. - */ -int -virDoubleToStr(char **strp, double number) -{ - int ret = -1; - -#if HAVE_NEWLOCALE - - locale_t old_loc; - - if (virLocaleInitialize() < 0) - goto error; - - old_loc = uselocale(virLocale); - ret = virAsprintf(strp, "%lf", number); - uselocale(old_loc); - -#else - - char *radix, *tmp; - struct lconv *lc; - - if ((ret = virAsprintf(strp, "%lf", number) < 0)) - goto error; - - lc = localeconv(); - radix = lc->decimal_point; - tmp = strstr(*strp, radix); - if (tmp) { - *tmp = '.'; - if (strlen(radix) > 1) - memmove(tmp + 1, tmp + strlen(radix), strlen(*strp) - (tmp - *strp)); - } - -#endif /* HAVE_NEWLOCALE */ - error: - return ret; -} - - -/** - * Format @val as a base-10 decimal number, in the - * buffer @buf of size @buflen. To allocate a suitable - * sized buffer, the INT_BUFLEN(int) macro should be - * used - * - * Returns pointer to start of the number in @buf - */ -char * -virFormatIntDecimal(char *buf, size_t buflen, int val) -{ - char *p = buf + buflen - 1; - *p = '\0'; - if (val >= 0) { - do { - *--p = '0' + (val % 10); - val /= 10; - } while (val != 0); - } else { - do { - *--p = '0' - (val % 10); - val /= 10; - } while (val != 0); - *--p = '-'; - } - return p; -} - - -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]+[0-9]*$/ - * into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26) - * Note that any trailing string of digits is simply ignored. - * @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", "ubd"}; - 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++) { - if (!c_islower(*ptr)) - break; - - idx = (idx + (i < 1 ? 0 : 1)) * 26; - idx += *ptr - 'a'; - ptr++; - } - - /* Count the trailing digits. */ - size_t n_digits = strspn(ptr, "0123456789"); - if (ptr[n_digits] != '\0') - return -1; - - return idx; -} - -char *virIndexToDiskName(int idx, const char *prefix) -{ - char *name = NULL; - int i, k, offset; - - if (idx < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Disk index %d is negative"), idx); - return NULL; - } - - for (i = 0, k = idx; k >= 0; ++i, k = k / 26 - 1) { } - - offset = strlen(prefix); - - if (VIR_ALLOC_N(name, offset + i + 1)) { - virReportOOMError(); - return NULL; - } - - strcpy(name, prefix); - name[offset + i] = '\0'; - - for (i = i - 1, k = idx; k >= 0; --i, k = k / 26 - 1) { - name[offset + i] = 'a' + (k % 26); - } - - return name; -} - -#ifndef AI_CANONIDN -# define AI_CANONIDN 0 -#endif - -/* Who knew getting a hostname could be so delicate. In Linux (and Unices - * in general), many things depend on "hostname" returning a value that will - * resolve one way or another. In the modern world where networks frequently - * come and go this is often being hard-coded to resolve to "localhost". If - * it *doesn't* resolve to localhost, then we would prefer to have the FQDN. - * That leads us to 3 possibilities: - * - * 1) gethostname() returns an FQDN (not localhost) - we return the string - * as-is, it's all of the information we want - * 2) gethostname() returns "localhost" - we return localhost; doing further - * work to try to resolve it is pointless - * 3) gethostname() returns a shortened hostname - in this case, we want to - * try to resolve this to a fully-qualified name. Therefore we pass it - * to getaddrinfo(). There are two possible responses: - * a) getaddrinfo() resolves to a FQDN - return the FQDN - * b) getaddrinfo() fails or resolves to localhost - in this case, the - * data we got from gethostname() is actually more useful than what - * we got from getaddrinfo(). Return the value from gethostname() - * and hope for the best. - */ -char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED) -{ - int r; - char hostname[HOST_NAME_MAX+1], *result; - struct addrinfo hints, *info; - - r = gethostname(hostname, sizeof(hostname)); - if (r == -1) { - virReportSystemError(errno, - "%s", _("failed to determine host name")); - return NULL; - } - NUL_TERMINATE(hostname); - - if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) { - /* in this case, gethostname returned localhost (meaning we can't - * do any further canonicalization), or it returned an FQDN (and - * we don't need to do any further canonicalization). Return the - * string as-is; it's up to callers to check whether "localhost" - * is allowed. - */ - result = strdup(hostname); - goto check_and_return; - } - - /* otherwise, it's a shortened, non-localhost, hostname. Attempt to - * canonicalize the hostname by running it through getaddrinfo - */ - - 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) { - VIR_WARN("getaddrinfo failed for '%s': %s", - hostname, gai_strerror(r)); - result = strdup(hostname); - goto check_and_return; - } - - /* Tell static analyzers about getaddrinfo semantics. */ - sa_assert(info); - - if (info->ai_canonname == NULL || - STRPREFIX(info->ai_canonname, "localhost")) - /* in this case, we tried to canonicalize and we ended up back with - * localhost. Ignore the canonicalized name and just return the - * original hostname - */ - result = strdup(hostname); - else - /* Caller frees this string. */ - result = strdup(info->ai_canonname); - - freeaddrinfo(info); - -check_and_return: - if (result == NULL) - virReportOOMError(); - return result; -} - -#ifdef HAVE_GETPWUID_R -enum { - VIR_USER_ENT_DIRECTORY, - VIR_USER_ENT_NAME, -}; - -static char *virGetUserEnt(uid_t uid, - int field) -{ - char *strbuf; - char *ret; - struct passwd pwbuf; - struct passwd *pw = NULL; - long val = sysconf(_SC_GETPW_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - 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. - */ - while ((rc = getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - VIR_FREE(strbuf); - return NULL; - } - } - if (rc != 0 || pw == NULL) { - virReportSystemError(rc, - _("Failed to find user record for uid '%u'"), - (unsigned int) 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(); - - return ret; -} - -static char *virGetGroupEnt(gid_t gid) -{ - char *strbuf; - char *ret; - struct group grbuf; - struct group *gr = NULL; - long val = sysconf(_SC_GETGR_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - return NULL; - } - - /* - * From the manpage (terrifying but true): - * - * ERRORS - * 0 or ENOENT or ESRCH or EBADF or EPERM or ... - * The given name or gid was not found. - */ - while ((rc = getgrgid_r(gid, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - VIR_FREE(strbuf); - return NULL; - } - } - if (rc != 0 || gr == NULL) { - virReportSystemError(rc, - _("Failed to find group record for gid '%u'"), - (unsigned int) gid); - VIR_FREE(strbuf); - return NULL; - } - - ret = strdup(gr->gr_name); - - VIR_FREE(strbuf); - if (!ret) - virReportOOMError(); - - return ret; -} - -char *virGetUserDirectory(void) -{ - return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); -} - -static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir) -{ - const char *path = getenv(xdgenvname); - char *ret = NULL; - char *home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); - - if (path && path[0]) { - if (virAsprintf(&ret, "%s/libvirt", path) < 0) - goto no_memory; - } else { - if (virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir) < 0) - goto no_memory; - } - - cleanup: - VIR_FREE(home); - return ret; - no_memory: - virReportOOMError(); - goto cleanup; -} - -char *virGetUserConfigDirectory(void) -{ - return virGetXDGDirectory("XDG_CONFIG_HOME", ".config"); -} - -char *virGetUserCacheDirectory(void) -{ - return virGetXDGDirectory("XDG_CACHE_HOME", ".cache"); -} - -char *virGetUserRuntimeDirectory(void) -{ - const char *path = getenv("XDG_RUNTIME_DIR"); - - if (!path || !path[0]) { - return virGetUserCacheDirectory(); - } else { - char *ret; - - if (virAsprintf(&ret, "%s/libvirt", path) < 0) { - virReportOOMError(); - return NULL; - } - - return ret; - } -} - -char *virGetUserName(uid_t uid) -{ - return virGetUserEnt(uid, VIR_USER_ENT_NAME); -} - -char *virGetGroupName(gid_t gid) -{ - return virGetGroupEnt(gid); -} - -/* Search in the password database for a user id that matches the user name - * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. - */ -static int -virGetUserIDByName(const char *name, uid_t *uid) -{ - char *strbuf = NULL; - struct passwd pwbuf; - struct passwd *pw = NULL; - long val = sysconf(_SC_GETPW_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - int ret = -1; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - - while ((rc = getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - } - - if (!pw) { - if (rc != 0) { - char buf[1024]; - /* log the possible error from getpwnam_r. Unfortunately error - * reporting from this function is bad and we can't really - * rely on it, so we just report that the user wasn't found */ - VIR_WARN("User record for user '%s' was not found: %s", - name, virStrerror(rc, buf, sizeof(buf))); - } - - ret = 1; - goto cleanup; - } - - *uid = pw->pw_uid; - ret = 0; - -cleanup: - VIR_FREE(strbuf); - - return ret; -} - -/* Try to match a user id based on `user`. The default behavior is to parse - * `user` first as a user name and then as a user id. However if `user` - * contains a leading '+', the rest of the string is always parsed as a uid. - * - * Returns 0 on success and -1 otherwise. - */ -int -virGetUserID(const char *user, uid_t *uid) -{ - unsigned int uint_uid; - - if (*user == '+') { - user++; - } else { - int rc = virGetUserIDByName(user, uid); - if (rc <= 0) - return rc; - } - - if (virStrToLong_ui(user, NULL, 10, &uint_uid) < 0 || - ((uid_t) uint_uid) != uint_uid) { - virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse user '%s'"), - user); - return -1; - } - - *uid = uint_uid; - - return 0; -} - -/* Search in the group database for a group id that matches the group name - * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. - */ -static int -virGetGroupIDByName(const char *name, gid_t *gid) -{ - char *strbuf = NULL; - struct group grbuf; - struct group *gr = NULL; - long val = sysconf(_SC_GETGR_R_SIZE_MAX); - size_t strbuflen = val; - int rc; - int ret = -1; - - /* sysconf is a hint; if it fails, fall back to a reasonable size */ - if (val < 0) - strbuflen = 1024; - - if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - - while ((rc = getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { - if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { - virReportOOMError(); - goto cleanup; - } - } - - if (!gr) { - if (rc != 0) { - char buf[1024]; - /* log the possible error from getgrnam_r. Unfortunately error - * reporting from this function is bad and we can't really - * rely on it, so we just report that the user wasn't found */ - VIR_WARN("Group record for user '%s' was not found: %s", - name, virStrerror(rc, buf, sizeof(buf))); - } - - ret = 1; - goto cleanup; - } - - *gid = gr->gr_gid; - ret = 0; - -cleanup: - VIR_FREE(strbuf); - - return ret; -} - -/* Try to match a group id based on `group`. The default behavior is to parse - * `group` first as a group name and then as a group id. However if `group` - * contains a leading '+', the rest of the string is always parsed as a guid. - * - * Returns 0 on success and -1 otherwise. - */ -int -virGetGroupID(const char *group, gid_t *gid) -{ - unsigned int uint_gid; - - if (*group == '+') { - group++; - } else { - int rc = virGetGroupIDByName(group, gid); - if (rc <= 0) - return rc; - } - - if (virStrToLong_ui(group, NULL, 10, &uint_gid) < 0 || - ((gid_t) uint_gid) != uint_gid) { - virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse group '%s'"), - group); - return -1; - } - - *gid = uint_gid; - - return 0; -} - -/* Set the real and effective uid and gid to the given values, and call - * initgroups so that the process has all the assumed group membership of - * that uid. return 0 on success, -1 on failure (the original system error - * remains in errno). - */ -int -virSetUIDGID(uid_t uid, gid_t gid) -{ - int err; - char *buf = NULL; - - if (gid > 0) { - if (setregid(gid, gid) < 0) { - virReportSystemError(err = errno, - _("cannot change to '%d' group"), - (unsigned int) gid); - goto error; - } - } - - if (uid > 0) { -# ifdef HAVE_INITGROUPS - struct passwd pwd, *pwd_result; - size_t bufsize; - int rc; - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize == -1) - bufsize = 16384; - - if (VIR_ALLOC_N(buf, bufsize) < 0) { - virReportOOMError(); - err = ENOMEM; - goto error; - } - while ((rc = getpwuid_r(uid, &pwd, buf, bufsize, - &pwd_result)) == ERANGE) { - if (VIR_RESIZE_N(buf, bufsize, bufsize, bufsize) < 0) { - virReportOOMError(); - err = ENOMEM; - goto error; - } - } - - if (rc) { - virReportSystemError(err = rc, _("cannot getpwuid_r(%d)"), - (unsigned int) uid); - goto error; - } - - if (!pwd_result) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("getpwuid_r failed to retrieve data " - "for uid '%d'"), - (unsigned int) uid); - err = EINVAL; - goto error; - } - - if (initgroups(pwd.pw_name, pwd.pw_gid) < 0) { - virReportSystemError(err = errno, - _("cannot initgroups(\"%s\", %d)"), - pwd.pw_name, (unsigned int) pwd.pw_gid); - goto error; - } -# endif - if (setreuid(uid, uid) < 0) { - virReportSystemError(err = errno, - _("cannot change to uid to '%d'"), - (unsigned int) uid); - goto error; - } - } - - VIR_FREE(buf); - return 0; - -error: - VIR_FREE(buf); - errno = err; - return -1; -} - -#else /* ! HAVE_GETPWUID_R */ - -# ifdef WIN32 -/* These methods are adapted from GLib2 under terms of LGPLv2+ */ -static int -virGetWin32SpecialFolder(int csidl, char **path) -{ - char buf[MAX_PATH+1]; - LPITEMIDLIST pidl = NULL; - int ret = 0; - - *path = NULL; - - if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK) { - if (SHGetPathFromIDList(pidl, buf)) { - if (!(*path = strdup(buf))) { - virReportOOMError(); - ret = -1; - } - } - CoTaskMemFree(pidl); - } - return ret; -} - -static int -virGetWin32DirectoryRoot(char **path) -{ - char windowsdir[MAX_PATH]; - int ret = 0; - - *path = NULL; - - if (GetWindowsDirectory(windowsdir, ARRAY_CARDINALITY(windowsdir))) - { - const char *tmp; - /* Usually X:\Windows, but in terminal server environments - * might be an UNC path, AFAIK. - */ - tmp = virFileSkipRoot(windowsdir); - if (VIR_FILE_IS_DIR_SEPARATOR(tmp[-1]) && - tmp[-2] != ':') - tmp--; - - windowsdir[tmp - windowsdir] = '\0'; - } else { - strcpy(windowsdir, "C:\\"); - } - - if (!(*path = strdup(windowsdir))) { - virReportOOMError(); - ret = -1; - } - - return ret; -} - - - -char * -virGetUserDirectory(void) -{ - const char *dir; - char *ret; - - dir = getenv("HOME"); - - /* Only believe HOME if it is an absolute path and exists */ - if (dir) { - if (!virFileIsAbsPath(dir) || - !virFileExists(dir)) - dir = NULL; - } - - /* In case HOME is Unix-style (it happens), convert it to - * Windows style. - */ - if (dir) { - char *p; - while ((p = strchr(dir, '/')) != NULL) - *p = '\\'; - } - - if (!dir) - /* USERPROFILE is probably the closest equivalent to $HOME? */ - dir = getenv("USERPROFILE"); - - if (dir) { - if (!(ret = strdup(dir))) { - virReportOOMError(); - return NULL; - } - } - - if (!ret && - virGetWin32SpecialFolder(CSIDL_PROFILE, &ret) < 0) - return NULL; - - if (!ret && - virGetWin32DirectoryRoot(&ret) < 0) - return NULL; - - if (!ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine home directory")); - return NULL; - } - - return ret; -} - -char * -virGetUserConfigDirectory(void) -{ - char *ret; - if (virGetWin32SpecialFolder(CSIDL_LOCAL_APPDATA, &ret) < 0) - return NULL; - - if (!ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine config directory")); - return NULL; - } - return ret; -} - -char * -virGetUserCacheDirectory(void) -{ - char *ret; - if (virGetWin32SpecialFolder(CSIDL_INTERNET_CACHE, &ret) < 0) - return NULL; - - if (!ret) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Unable to determine config directory")); - return NULL; - } - return ret; -} - -char * -virGetUserRuntimeDirectory(void) -{ - return virGetUserCacheDirectory(); -} -# else /* !HAVE_GETPWUID_R && !WIN32 */ -char * -virGetUserDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserDirectory is not available")); - - return NULL; -} - -char * -virGetUserConfigDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserConfigDirectory is not available")); - - return NULL; -} - -char * -virGetUserCacheDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserCacheDirectory is not available")); - - return NULL; -} - -char * -virGetUserRuntimeDirectory(void) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserRuntimeDirectory is not available")); - - return NULL; -} -# endif /* ! HAVE_GETPWUID_R && ! WIN32 */ - -char * -virGetUserName(uid_t uid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserName is not available")); - - return NULL; -} - -int virGetUserID(const char *name ATTRIBUTE_UNUSED, - uid_t *uid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetUserID is not available")); - - return 0; -} - - -int virGetGroupID(const char *name ATTRIBUTE_UNUSED, - gid_t *gid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetGroupID is not available")); - - return 0; -} - -int -virSetUIDGID(uid_t uid ATTRIBUTE_UNUSED, - gid_t gid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virSetUIDGID is not available")); - return -1; -} - -char * -virGetGroupName(gid_t gid ATTRIBUTE_UNUSED) -{ - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("virGetGroupName is not available")); - - return NULL; -} -#endif /* HAVE_GETPWUID_R */ - - -#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R -/* 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; -} - -#else /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ - -char * -virFileFindMountPoint(const char *type ATTRIBUTE_UNUSED) -{ - errno = ENOSYS; - - return NULL; -} - -#endif /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ - -#if defined(UDEVADM) || defined(UDEVSETTLE) -void virFileWaitForDevices(void) -{ -# 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. - */ - if (virRun(settleprog, &exitstatus) < 0) - {} -} -#else -void virFileWaitForDevices(void) {} -#endif - -int virBuildPathInternal(char **path, ...) -{ - char *path_component = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - va_list ap; - int ret = 0; - - va_start(ap, path); - - path_component = va_arg(ap, char *); - virBufferAdd(&buf, path_component, -1); - - while ((path_component = va_arg(ap, char *)) != NULL) - { - virBufferAddChar(&buf, '/'); - virBufferAdd(&buf, path_component, -1); - } - - va_end(ap); - - *path = virBufferContentAndReset(&buf); - if (*path == NULL) { - ret = -1; - } - - return ret; -} - -#if HAVE_LIBDEVMAPPER_H -bool -virIsDevMapperDevice(const char *dev_name) -{ - struct stat buf; - - if (!stat(dev_name, &buf) && - S_ISBLK(buf.st_mode) && - dm_is_dm_major(major(buf.st_rdev))) - return true; - - return false; -} -#else -bool virIsDevMapperDevice(const char *dev_name ATTRIBUTE_UNUSED) -{ - return false; -} -#endif - -bool -virValidateWWN(const char *wwn) { - int i; - - for (i = 0; wwn[i]; i++) - if (!c_isxdigit(wwn[i])) - break; - - if (i != 16 || wwn[i]) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Malformed wwn: %s")); - return false; - } - - return true; -} - -bool -virStrIsPrint(const char *str) -{ - int i; - - for (i = 0; str[i]; i++) - if (!c_isprint(str[i])) - return false; - - return true; -} diff --git a/src/util/util.h b/src/util/util.h deleted file mode 100644 index 6d5dd03..0000000 --- a/src/util/util.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * utils.h: common, generic utility functions - * - * Copyright (C) 2010-2012 Red Hat, Inc. - * 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, see - * <http://www.gnu.org/licenses/>. - * - * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com> - */ - -#ifndef __VIR_UTIL_H__ -# define __VIR_UTIL_H__ - -# include "verify.h" -# include "internal.h" -# include <unistd.h> -# include <sys/select.h> -# include <sys/types.h> -# include <stdarg.h> - -# ifndef MIN -# define MIN(a, b) ((a) < (b) ? (a) : (b)) -# endif -# ifndef MAX -# define MAX(a, b) ((a) > (b) ? (a) : (b)) -# endif - -ssize_t saferead(int fd, void *buf, size_t count) ATTRIBUTE_RETURN_CHECK; -ssize_t safewrite(int fd, const void *buf, size_t count) - ATTRIBUTE_RETURN_CHECK; -int safezero(int fd, off_t offset, off_t len) - ATTRIBUTE_RETURN_CHECK; - -int virSetBlocking(int fd, bool blocking) ATTRIBUTE_RETURN_CHECK; -int virSetNonBlock(int fd) ATTRIBUTE_RETURN_CHECK; -int virSetInherit(int fd, bool inherit) ATTRIBUTE_RETURN_CHECK; -int virSetCloseExec(int fd) ATTRIBUTE_RETURN_CHECK; - -int virPipeReadUntilEOF(int outfd, int errfd, - char **outbuf, char **errbuf); - -int virSetUIDGID(uid_t uid, gid_t gid); - -int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; - -int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; - -int virFileWriteStr(const char *path, const char *str, mode_t mode) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; - -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) ATTRIBUTE_RETURN_CHECK; - -int virFileLinkPointsTo(const char *checkLink, - const char *checkDest); - -int virFileResolveLink(const char *linkpath, - char **resultpath) ATTRIBUTE_RETURN_CHECK; -int virFileResolveAllLinks(const char *linkpath, - char **resultpath) ATTRIBUTE_RETURN_CHECK; - -int virFileIsLink(const char *linkpath) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -char *virFindFileInPath(const char *file); - -bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1); -bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1); -bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1); - -char *virFileSanitizePath(const char *path); - -enum { - VIR_FILE_OPEN_NONE = 0, - VIR_FILE_OPEN_NOFORK = (1 << 0), - VIR_FILE_OPEN_FORK = (1 << 1), - VIR_FILE_OPEN_FORCE_MODE = (1 << 2), - VIR_FILE_OPEN_FORCE_OWNER = (1 << 3), -}; -int virFileAccessibleAs(const char *path, int mode, - uid_t uid, gid_t gid) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; -int virFileOpenAs(const char *path, int openflags, mode_t mode, - uid_t uid, gid_t gid, - unsigned int flags) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -enum { - VIR_DIR_CREATE_NONE = 0, - VIR_DIR_CREATE_AS_UID = (1 << 0), - VIR_DIR_CREATE_FORCE_PERMS = (1 << 1), - VIR_DIR_CREATE_ALLOW_EXIST = (1 << 2), -}; -int virDirCreate(const char *path, mode_t mode, uid_t uid, gid_t gid, - unsigned int flags) ATTRIBUTE_RETURN_CHECK; -int virFileMakePath(const char *path) ATTRIBUTE_RETURN_CHECK; -int virFileMakePathWithMode(const char *path, - mode_t mode) ATTRIBUTE_RETURN_CHECK; - -char *virFileBuildPath(const char *dir, - const char *name, - const char *ext) ATTRIBUTE_RETURN_CHECK; - - -# ifdef WIN32 -/* On Win32, the canonical directory separator is the backslash, and - * the search path separator is the semicolon. Note that also the - * (forward) slash works as directory separator. - */ -# define VIR_FILE_DIR_SEPARATOR '\\' -# define VIR_FILE_DIR_SEPARATOR_S "\\" -# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR || (c) == '/') -# define VIR_FILE_PATH_SEPARATOR ';' -# define VIR_FILE_PATH_SEPARATOR_S ";" - -# else /* !WIN32 */ - -# define VIR_FILE_DIR_SEPARATOR '/' -# define VIR_FILE_DIR_SEPARATOR_S "/" -# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR) -# define VIR_FILE_PATH_SEPARATOR ':' -# define VIR_FILE_PATH_SEPARATOR_S ":" - -# endif /* !WIN32 */ - -bool virFileIsAbsPath(const char *path); -int virFileAbsPath(const char *path, - char **abspath) ATTRIBUTE_RETURN_CHECK; -const char *virFileSkipRoot(const char *path); - -int virFileOpenTty(int *ttymaster, - char **ttyName, - int rawmode); - -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_l(char const *s, - char **end_ptr, - int base, - long *result); -int virStrToLong_ul(char const *s, - char **end_ptr, - int base, - unsigned long *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 virScaleInteger(unsigned long long *value, const char *suffix, - unsigned long long scale, unsigned long long limit) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -int virHexToBin(unsigned char c); - -void virSkipSpaces(const char **str) ATTRIBUTE_NONNULL(1); -void virSkipSpacesAndBackslash(const char **str) ATTRIBUTE_NONNULL(1); -void virTrimSpaces(char *str, char **endp) ATTRIBUTE_NONNULL(1); -void virSkipSpacesBackwards(const char *str, char **endp) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -int virParseNumber(const char **str); -int virParseVersionString(const char *str, unsigned long *version, - bool allowMissing); -int virAsprintf(char **strp, const char *fmt, ...) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); -int virVasprintf(char **strp, const char *fmt, va_list list) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 0); -char *virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) - ATTRIBUTE_RETURN_CHECK; -char *virStrcpy(char *dest, const char *src, size_t destbytes) - ATTRIBUTE_RETURN_CHECK; -# define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest)) - -int virDoubleToStr(char **strp, double number) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -char *virFormatIntDecimal(char *buf, size_t buflen, int val) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; - -int virDiskNameToIndex(const char* str); -char *virIndexToDiskName(int idx, const char *prefix); - -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__ }; \ - verify(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_GETEUID -static inline int geteuid (void) { return 0; } -# endif - -# ifndef HAVE_GETGID -static inline int getgid (void) { return 0; } -# endif - -char *virGetHostname(virConnectPtr conn); - -char *virGetUserDirectory(void); -char *virGetUserConfigDirectory(void); -char *virGetUserCacheDirectory(void); -char *virGetUserRuntimeDirectory(void); -char *virGetUserName(uid_t uid); -char *virGetGroupName(gid_t gid); -int virGetUserID(const char *name, - uid_t *uid) ATTRIBUTE_RETURN_CHECK; -int virGetGroupID(const char *name, - gid_t *gid) ATTRIBUTE_RETURN_CHECK; - -char *virFileFindMountPoint(const char *type); - -void virFileWaitForDevices(void); - -# define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL) -int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL; - -bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1); - -bool virValidateWWN(const char *wwn); - -bool virStrIsPrint(const char *str); -#endif /* __VIR_UTIL_H__ */ diff --git a/src/util/uuid.c b/src/util/uuid.c index 5232ba9..57cfaa6 100644 --- a/src/util/uuid.c +++ b/src/util/uuid.c @@ -35,7 +35,7 @@
#include "c-ctype.h" #include "internal.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virlog.h" #include "viralloc.h" diff --git a/src/util/viraudit.c b/src/util/viraudit.c index a807b76..05189d5 100644 --- a/src/util/viraudit.c +++ b/src/util/viraudit.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "viraudit.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "viralloc.h"
diff --git a/src/util/virauth.c b/src/util/virauth.c index c4c5676..cbb16ec 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -25,7 +25,7 @@ #include <stdlib.h>
#include "virauth.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "datatypes.h" diff --git a/src/util/virauthconfig.c b/src/util/virauthconfig.c index a0f0be5..d60f7bf 100644 --- a/src/util/virauthconfig.c +++ b/src/util/virauthconfig.c @@ -26,7 +26,7 @@
#include "virkeyfile.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h"
diff --git a/src/util/virbitmap.c b/src/util/virbitmap.c index cb9606b..b4ba3ef 100644 --- a/src/util/virbitmap.c +++ b/src/util/virbitmap.c @@ -33,7 +33,7 @@ #include "virbitmap.h" #include "viralloc.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "count-one-bits.h"
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c index 5c628cc..48cba93 100644 --- a/src/util/vircgroup.c +++ b/src/util/vircgroup.c @@ -38,7 +38,7 @@ #include <dirent.h>
#include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircgroup.h" #include "virlog.h" diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 6e17a8d..d059586 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -36,7 +36,7 @@ #include "vircommand.h" #include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virfile.h" #include "virpidfile.h" diff --git a/src/util/vircommand.h b/src/util/vircommand.h index 4c88165..9b7117d 100644 --- a/src/util/vircommand.h +++ b/src/util/vircommand.h @@ -23,7 +23,7 @@ # define __VIR_COMMAND_H__
# include "internal.h" -# include "util.h" +# include "virutil.h" # include "virbuffer.h"
typedef struct _virCommand virCommand; diff --git a/src/util/virconf.c b/src/util/virconf.c index 2f6d60e..7e4c8c1 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virbuffer.h" #include "virconf.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "virlog.h" #include "viralloc.h" diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c index 918610a..6b9abd9 100644 --- a/src/util/virdnsmasq.c +++ b/src/util/virdnsmasq.c @@ -41,7 +41,7 @@ #include "datatypes.h" #include "virbitmap.h" #include "virdnsmasq.h" -#include "util.h" +#include "virutil.h" #include "vircommand.h" #include "viralloc.h" #include "virterror_internal.h" diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index 1180fda..afb0e05 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -35,7 +35,7 @@ #include "virlog.h" #include "vireventpoll.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virterror_internal.h" #include "virtime.h" diff --git a/src/util/virhooks.c b/src/util/virhooks.c index ad3a371..54a869a 100644 --- a/src/util/virhooks.c +++ b/src/util/virhooks.c @@ -32,7 +32,7 @@
#include "virterror_internal.h" #include "virhooks.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/util/virhooks.h b/src/util/virhooks.h index 0ca376f..56573df 100644 --- a/src/util/virhooks.h +++ b/src/util/virhooks.h @@ -25,7 +25,7 @@ # define __VIR_HOOKS_H__
# include "internal.h" -# include "util.h" +# include "virutil.h"
enum virHookDriverType { VIR_HOOK_DRIVER_DAEMON = 0, /* Daemon related events */ diff --git a/src/util/virinitctl.c b/src/util/virinitctl.c index 91a948f..f8ac673 100644 --- a/src/util/virinitctl.c +++ b/src/util/virinitctl.c @@ -29,7 +29,7 @@ #include "internal.h" #include "virinitctl.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h"
diff --git a/src/util/virjson.c b/src/util/virjson.c index 4fa5363..4c9797c 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -27,7 +27,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h"
#if HAVE_YAJL # include <yajl/yajl_gen.h> diff --git a/src/util/virkeycode.h b/src/util/virkeycode.h index 1522f77..a2e1391 100644 --- a/src/util/virkeycode.h +++ b/src/util/virkeycode.h @@ -22,7 +22,7 @@ #ifndef __VIR_UTIL_VIRTKEYCODE_H__ # define __VIR_UTIL_VIRTKEYCODE_H__
-# include "util.h" +# include "virutil.h" # include "libvirt/libvirt.h"
VIR_ENUM_DECL(virKeycodeSet); diff --git a/src/util/virkeyfile.c b/src/util/virkeyfile.c index fc61cf5..99e5cd7 100644 --- a/src/util/virkeyfile.c +++ b/src/util/virkeyfile.c @@ -28,7 +28,7 @@ #include "c-ctype.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virhash.h" #include "virkeyfile.h" #include "virterror_internal.h" diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c index 961e171..81a1d81 100644 --- a/src/util/virlockspace.c +++ b/src/util/virlockspace.c @@ -25,7 +25,7 @@ #include "virlog.h" #include "viralloc.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virhash.h" #include "virthread.h" diff --git a/src/util/virlog.c b/src/util/virlog.c index 0c6c13a..43a59b4 100644 --- a/src/util/virlog.c +++ b/src/util/virlog.c @@ -43,7 +43,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virbuffer.h" #include "virthread.h" #include "virfile.h" diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index eb341a2..4de88e3 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -24,7 +24,7 @@
#include "virnetdevbridge.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "viralloc.h" #include "intprops.h" diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 0f7107b..953d76b 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -29,7 +29,7 @@
#include "virnetdevmacvlan.h" #include "virmacaddr.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_NET diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h index 147cd6f..3216ea0 100644 --- a/src/util/virnetdevopenvswitch.h +++ b/src/util/virnetdevopenvswitch.h @@ -25,7 +25,7 @@ # define __VIR_NETDEV_OPENVSWITCH_H__
# include "internal.h" -# include "util.h" +# include "virutil.h" # include "virnetdevvportprofile.h" # include "virnetdevvlan.h"
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 339d636..3565bbd 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h"
#include <sys/ioctl.h> #include <net/if.h> diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h index c4585a8..cc106b8 100644 --- a/src/util/virnetdevvportprofile.h +++ b/src/util/virnetdevvportprofile.h @@ -25,7 +25,7 @@
# include "internal.h" # include "uuid.h" -# include "util.h" +# include "virutil.h" # include "virmacaddr.h"
# define LIBVIRT_IFLA_VF_PORT_PROFILE_MAX 40 diff --git a/src/util/virpidfile.c b/src/util/virpidfile.c index 3b3322b..29097e3 100644 --- a/src/util/virpidfile.c +++ b/src/util/virpidfile.c @@ -30,7 +30,7 @@ #include "virpidfile.h" #include "virfile.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "intprops.h" #include "virlog.h" #include "virterror_internal.h" diff --git a/src/util/virprocess.c b/src/util/virprocess.c index 155e4e2..b276643 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -31,7 +31,7 @@ #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" -#include "util.h" +#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_NONE
diff --git a/src/util/virrandom.c b/src/util/virrandom.c index 1dd96cf..1b6de6b 100644 --- a/src/util/virrandom.c +++ b/src/util/virrandom.c @@ -29,7 +29,7 @@ #include "virrandom.h" #include "virthread.h" #include "count-one-bits.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virlog.h"
diff --git a/src/util/virsexpr.c b/src/util/virsexpr.c index 80c24c4..8b70404 100644 --- a/src/util/virsexpr.c +++ b/src/util/virsexpr.c @@ -19,7 +19,7 @@
#include "virterror_internal.h" #include "virsexpr.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h"
#define VIR_FROM_THIS VIR_FROM_SEXPR diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 488ff4b..0f2f23d 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -25,7 +25,7 @@
#include "virsocketaddr.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h"
#include <netdb.h>
diff --git a/src/util/virstatslinux.c b/src/util/virstatslinux.c index 9359db9..135df75 100644 --- a/src/util/virstatslinux.c +++ b/src/util/virstatslinux.c @@ -34,7 +34,7 @@
# include "virterror_internal.h" # include "datatypes.h" -# include "util.h" +# include "virutil.h" # include "virstatslinux.h" # include "viralloc.h" # include "virfile.h" diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 6fbd275..abf319a 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -24,7 +24,7 @@ #ifndef __VIR_STORAGE_FILE_H__ # define __VIR_STORAGE_FILE_H__
-# include "util.h" +# include "virutil.h"
enum virStorageFileFormat { VIR_STORAGE_FILE_AUTO_SAFE = -2, diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c index 13d3c22..88e4f5c 100644 --- a/src/util/virsysinfo.c +++ b/src/util/virsysinfo.c @@ -32,7 +32,7 @@
#include "virterror_internal.h" #include "virsysinfo.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "viralloc.h" #include "vircommand.h" diff --git a/src/util/virsysinfo.h b/src/util/virsysinfo.h index 0b1f000..dded51b 100644 --- a/src/util/virsysinfo.h +++ b/src/util/virsysinfo.h @@ -25,7 +25,7 @@ # define __VIR_SYSINFOS_H__
# include "internal.h" -# include "util.h" +# include "virutil.h" # include "virbuffer.h"
enum virSysinfoType { diff --git a/src/util/virterror.c b/src/util/virterror.c index 6c773d3..a586738 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -32,7 +32,7 @@ #include "virlog.h" #include "viralloc.h" #include "virthread.h" -#include "util.h" +#include "virutil.h"
virThreadLocal virLastErr;
diff --git a/src/util/virtime.c b/src/util/virtime.c index f9fc282..c614380 100644 --- a/src/util/virtime.c +++ b/src/util/virtime.c @@ -37,7 +37,7 @@ #include <sys/time.h>
#include "virtime.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virterror_internal.h"
diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index e08530e..60fb485 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -25,7 +25,7 @@ #include <stdarg.h>
#include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/viruri.c b/src/util/viruri.c index f48079d..e59cd5a 100644 --- a/src/util/viruri.c +++ b/src/util/viruri.c @@ -23,7 +23,7 @@ #include "viruri.h"
#include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "virbuffer.h"
diff --git a/src/util/virusb.c b/src/util/virusb.c index 9786e86..c053c44 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -34,7 +34,7 @@ #include "virusb.h" #include "virlog.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h"
#define USB_SYSFS "/sys/bus/usb" diff --git a/src/util/virutil.c b/src/util/virutil.c new file mode 100644 index 0000000..9fb1c6f --- /dev/null +++ b/src/util/virutil.c @@ -0,0 +1,3131 @@ +/* + * utils.c: common, generic utility functions + * + * Copyright (C) 2006-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * 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 <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <poll.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#if HAVE_MMAP +# include <sys/mman.h> +#endif +#include <string.h> +#include <signal.h> +#include <termios.h> +#include <pty.h> +#include <locale.h> + +#if HAVE_LIBDEVMAPPER_H +# include <libdevmapper.h> +#endif + +#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 +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +# include <mntent.h> +#endif + +#ifdef WIN32 +# ifdef HAVE_WINSOCK2_H +# include <winsock2.h> +# endif +# include <windows.h> +# include <shlobj.h> +#endif + +#include "c-ctype.h" +#include "dirname.h" +#include "virterror_internal.h" +#include "virlog.h" +#include "virbuffer.h" +#include "virutil.h" +#include "virstoragefile.h" +#include "viralloc.h" +#include "virthread.h" +#include "verify.h" +#include "virfile.h" +#include "vircommand.h" +#include "nonblocking.h" +#include "passfd.h" +#include "virprocess.h" + +#ifndef NSIG +# define NSIG 32 +#endif + +verify(sizeof(gid_t) <= sizeof(unsigned int) && + sizeof(uid_t) <= sizeof(unsigned int)); + +#define VIR_FROM_THIS VIR_FROM_NONE + +/* Like read(), but restarts after EINTR */ +ssize_t +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, off_t offset, off_t len) +{ + int ret = posix_fallocate(fd, offset, len); + if (ret == 0) + return 0; + errno = ret; + return -1; +} +#else + +# ifdef HAVE_MMAP +int safezero(int fd, 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 -1; + + buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); + if (buf == MAP_FAILED) + return -1; + + memset(buf, 0, len); + munmap(buf, len); + + return 0; +} + +# else /* HAVE_MMAP */ + +int safezero(int fd, off_t offset, off_t len) +{ + int r; + char *buf; + unsigned long long remain, bytes; + + if (lseek(fd, offset, SEEK_SET) < 0) + return -1; + + /* 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) { + errno = ENOMEM; + return -1; + } + + while (remain) { + if (bytes > remain) + bytes = remain; + + r = safewrite(fd, buf, bytes); + if (r < 0) { + VIR_FREE(buf); + return -1; + } + + /* safewrite() guarantees all data will be written */ + remain -= bytes; + } + VIR_FREE(buf); + return 0; +} +# endif /* HAVE_MMAP */ +#endif /* HAVE_POSIX_FALLOCATE */ + +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; +} + +#ifndef WIN32 + +int virSetInherit(int fd, bool inherit) { + int fflags; + if ((fflags = fcntl(fd, F_GETFD)) < 0) + return -1; + if (inherit) + fflags &= ~FD_CLOEXEC; + else + fflags |= FD_CLOEXEC; + if ((fcntl(fd, F_SETFD, fflags)) < 0) + return -1; + return 0; +} + +#else /* WIN32 */ + +int virSetInherit(int fd ATTRIBUTE_UNUSED, bool inherit ATTRIBUTE_UNUSED) +{ + /* FIXME: Currently creating child processes is not supported on + * Win32, so there is no point in failing calls that are only relevant + * when creating child processes. So just pretend that we changed the + * inheritance property of the given fd as requested. */ + return 0; +} + +#endif /* WIN32 */ + +int virSetBlocking(int fd, bool blocking) { + return set_nonblocking_flag(fd, !blocking); +} + +int virSetNonBlock(int fd) { + return virSetBlocking(fd, false); +} + +int virSetCloseExec(int fd) +{ + return virSetInherit(fd, false); +} + +int +virPipeReadUntilEOF(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; + fds[0].revents = 0; + finished[0] = 0; + fds[1].fd = errfd; + fds[1].events = POLLIN; + fds[1].revents = 0; + 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; + + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Unknown poll response.")); + goto error; + } + + got = read(fds[i].fd, data, sizeof(data)); + + if (got == sizeof(data)) + finished[i] = 0; + + 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(); + goto error; + } + memmove(*buf+size, data, got); + (*buf)[size+got] = '\0'; + } + continue; + + pollerr: + virReportSystemError(errno, + "%s", _("poll error")); + goto error; + } + + return 0; + +error: + VIR_FREE(*outbuf); + VIR_FREE(*errbuf); + return -1; +} + +/* 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 * +saferead_lim(int fd, size_t max_len, size_t *length) +{ + char *buf = NULL; + size_t alloc = 0; + size_t size = 0; + int save_errno; + + for (;;) { + int count; + int 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 = saferead(fd, buf + size, requested); + size += count; + + if (count != requested || requested == 0) { + save_errno = errno; + if (count < 0) + break; + buf[size] = '\0'; + *length = size; + return buf; + } + } + + VIR_FREE(buf); + errno = save_errno; + return NULL; +} + +/* A wrapper around saferead_lim that maps a failure due to + exceeding the maximum size limitation to EOVERFLOW. */ +int +virFileReadLimFD(int fd, int maxlen, char **buf) +{ + size_t len; + char *s; + + if (maxlen <= 0) { + errno = EINVAL; + return -1; + } + s = saferead_lim(fd, 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; +} + +int virFileReadAll(const char *path, int maxlen, char **buf) +{ + int fd = open(path, O_RDONLY); + if (fd < 0) { + virReportSystemError(errno, _("Failed to open file '%s'"), path); + return -1; + } + + int len = virFileReadLimFD(fd, maxlen, buf); + VIR_FORCE_CLOSE(fd); + if (len < 0) { + virReportSystemError(errno, _("Failed to read file '%s'"), path); + return -1; + } + + return len; +} + +/* Truncate @path and write @str to it. If @mode is 0, ensure that + @path exists; otherwise, use @mode if @path must be created. + Return 0 for success, nonzero for failure. + Be careful to preserve any errno value upon failure. */ +int virFileWriteStr(const char *path, const char *str, mode_t mode) +{ + int fd; + + if (mode) + fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, mode); + else + fd = open(path, O_WRONLY|O_TRUNC); + if (fd == -1) + return -1; + + if (safewrite(fd, str, strlen(str)) < 0) { + VIR_FORCE_CLOSE(fd); + return -1; + } + + /* Use errno from failed close only if there was no write error. */ + if (VIR_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 STRCASEEQ(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)); +} + + + +static int +virFileResolveLinkHelper(const char *linkpath, + bool intermediatePaths, + char **resultpath) +{ + struct stat st; + + *resultpath = NULL; + + /* We don't need the full canonicalization of intermediate + * directories, if linkpath is absolute and the basename is + * already a non-symlink. */ + if (IS_ABSOLUTE_FILE_NAME(linkpath) && !intermediatePaths) { + if (lstat(linkpath, &st) < 0) + return -1; + + if (!S_ISLNK(st.st_mode)) { + if (!(*resultpath = strdup(linkpath))) + return -1; + return 0; + } + } + + *resultpath = canonicalize_file_name(linkpath); + + return *resultpath == NULL ? -1 : 0; +} + +/* + * Attempt to resolve a symbolic link, returning an + * absolute path where only the last component is guaranteed + * not to be a symlink. + * + * Return 0 if path was not a symbolic, or the link was + * resolved. Return -1 with errno set upon error + */ +int virFileResolveLink(const char *linkpath, + char **resultpath) +{ + return virFileResolveLinkHelper(linkpath, false, resultpath); +} + +/* + * Attempt to resolve a symbolic link, returning an + * absolute path where every component is guaranteed + * not to be a symlink. + * + * Return 0 if path was not a symbolic, or the link was + * resolved. Return -1 with errno set upon error + */ +int virFileResolveAllLinks(const char *linkpath, + char **resultpath) +{ + return virFileResolveLinkHelper(linkpath, true, resultpath); +} + +/* + * Check whether the given file is a link. + * Returns 1 in case of the file being a link, 0 in case it is not + * a link and the negative errno in all other cases. + */ +int virFileIsLink(const char *linkpath) +{ + struct stat st; + + if (lstat(linkpath, &st) < 0) + return -errno; + + return S_ISLNK(st.st_mode) != 0; +} + + +/* + * Finds a requested executable 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 *path = NULL; + char *pathiter; + char *pathseg; + char *fullpath = NULL; + + if (file == NULL) + return NULL; + + /* if we are passed an absolute path (starting with /), return a + * copy of that path, after validating that it is executable + */ + if (IS_ABSOLUTE_FILE_NAME(file)) { + if (virFileIsExecutable(file)) + return strdup(file); + else + return NULL; + } + + /* If we are passed an anchored path (containing a /), then there + * is no path search - it must exist in the current directory + */ + if (strchr(file, '/')) { + if (virFileIsExecutable(file)) + ignore_value(virFileAbsPath(file, &path)); + return path; + } + + /* copy PATH env so we can tweak it */ + path = getenv("PATH"); + + if (path == NULL || (path = strdup(path)) == NULL) + return NULL; + + /* for each path segment, append the file to search for and test for + * it. return it if found. + */ + pathiter = path; + while ((pathseg = strsep(&pathiter, ":")) != NULL) { + if (virAsprintf(&fullpath, "%s/%s", pathseg, file) < 0 || + virFileIsExecutable(fullpath)) + break; + VIR_FREE(fullpath); + } + + VIR_FREE(path); + return fullpath; +} + +bool virFileIsDir(const char *path) +{ + struct stat s; + return (stat(path, &s) == 0) && S_ISDIR(s.st_mode); +} + +bool virFileExists(const char *path) +{ + return access(path, F_OK) == 0; +} + +/* Check that a file is regular and has executable bits. If false is + * returned, errno is valid. + * + * Note: In the presence of ACLs, this may return true for a file that + * would actually fail with EACCES for a given user, or false for a + * file that the user could actually execute, but setups with ACLs + * that weird are unusual. */ +bool +virFileIsExecutable(const char *file) +{ + struct stat sb; + + /* We would also want to check faccessat if we cared about ACLs, + * but we don't. */ + if (stat(file, &sb) < 0) + return false; + if (S_ISREG(sb.st_mode) && (sb.st_mode & 0111) != 0) + return true; + errno = S_ISDIR(sb.st_mode) ? EISDIR : EACCES; + return false; +} + +#ifndef WIN32 +/* Check that a file is accessible under certain + * user & gid. + * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK. + * see 'man access' for more details. + * Returns 0 on success, -1 on fail with errno set. + */ +int +virFileAccessibleAs(const char *path, int mode, + uid_t uid, gid_t gid) +{ + pid_t pid = 0; + int status, ret = 0; + int forkRet = 0; + + if (uid == getuid() && + gid == getgid()) + return access(path, mode); + + forkRet = virFork(&pid); + + if (pid < 0) { + return -1; + } + + if (pid) { /* parent */ + if (virProcessWait(pid, &status) < 0) { + /* virProcessWait() already + * reported error */ + return -1; + } + + if (!WIFEXITED(status)) { + errno = EINTR; + return -1; + } + + if (status) { + errno = WEXITSTATUS(status); + return -1; + } + + return 0; + } + + /* child. + * Return positive value here. Parent + * will change it to negative one. */ + + if (forkRet < 0) { + ret = errno; + goto childerror; + } + + if (virSetUIDGID(uid, gid) < 0) { + ret = errno; + goto childerror; + } + + if (access(path, mode) < 0) + ret = errno; + +childerror: + if ((ret & 0xFF) != ret) { + VIR_WARN("unable to pass desired return value %d", ret); + ret = 0xFF; + } + + _exit(ret); +} + +/* virFileOpenForceOwnerMode() - an internal utility function called + * only by virFileOpenAs(). Sets the owner and mode of the file + * opened as "fd" if it's not correct AND the flags say it should be + * forced. */ +static int +virFileOpenForceOwnerMode(const char *path, int fd, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) +{ + int ret = 0; + struct stat st; + + if (!(flags & (VIR_FILE_OPEN_FORCE_OWNER | VIR_FILE_OPEN_FORCE_MODE))) + return 0; + + if (fstat(fd, &st) == -1) { + ret = -errno; + virReportSystemError(errno, _("stat of '%s' failed"), path); + return ret; + } + /* NB: uid:gid are never "-1" (default) at this point - the caller + * has always changed -1 to the value of get[gu]id(). + */ + if ((flags & VIR_FILE_OPEN_FORCE_OWNER) && + ((st.st_uid != uid) || (st.st_gid != gid)) && + (fchown(fd, uid, gid) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot chown '%s' to (%u, %u)"), + path, (unsigned int) uid, + (unsigned int) gid); + return ret; + } + if ((flags & VIR_FILE_OPEN_FORCE_MODE) && + ((mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != + (st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) && + (fchmod(fd, mode) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot set mode of '%s' to %04o"), + path, mode); + return ret; + } + return ret; +} + +/* virFileOpenForked() - an internal utility function called only by + * virFileOpenAs(). It forks, then the child does setuid+setgid to + * given uid:gid and attempts to open the file, while the parent just + * calls recvfd to get the open fd back from the child. returns the + * fd, or -errno if there is an error. */ +static int +virFileOpenForked(const char *path, int openflags, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) +{ + pid_t pid; + int waitret, status, ret = 0; + int fd = -1; + int pair[2] = { -1, -1 }; + int forkRet; + + /* parent is running as root, but caller requested that the + * file be opened as some other user and/or group). The + * following dance avoids problems caused by root-squashing + * NFS servers. */ + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { + ret = -errno; + virReportSystemError(errno, + _("failed to create socket needed for '%s'"), + path); + return ret; + } + + forkRet = virFork(&pid); + if (pid < 0) + return -errno; + + if (pid == 0) { + + /* child */ + + VIR_FORCE_CLOSE(pair[0]); /* preserves errno */ + if (forkRet < 0) { + /* error encountered and logged in virFork() after the fork. */ + ret = -errno; + goto childerror; + } + + /* set desired uid/gid, then attempt to create the file */ + + if (virSetUIDGID(uid, gid) < 0) { + ret = -errno; + goto childerror; + } + + if ((fd = open(path, openflags, mode)) < 0) { + ret = -errno; + virReportSystemError(errno, + _("child process failed to create file '%s'"), + path); + goto childerror; + } + + /* File is successfully open. Set permissions if requested. */ + ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); + if (ret < 0) + goto childerror; + + do { + ret = sendfd(pair[1], fd); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + ret = -errno; + virReportSystemError(errno, "%s", + _("child process failed to send fd to parent")); + goto childerror; + } + + childerror: + /* ret tracks -errno on failure, but exit value must be positive. + * If the child exits with EACCES, then the parent tries again. */ + /* XXX This makes assumptions about errno being < 255, which is + * not true on Hurd. */ + VIR_FORCE_CLOSE(pair[1]); + if (ret < 0) { + VIR_FORCE_CLOSE(fd); + } + ret = -ret; + if ((ret & 0xff) != ret) { + VIR_WARN("unable to pass desired return value %d", ret); + ret = 0xff; + } + _exit(ret); + } + + /* parent */ + + VIR_FORCE_CLOSE(pair[1]); + + do { + fd = recvfd(pair[0], 0); + } while (fd < 0 && errno == EINTR); + VIR_FORCE_CLOSE(pair[0]); /* NB: this preserves errno */ + + if (fd < 0 && errno != EACCES) { + ret = -errno; + while (waitpid(pid, NULL, 0) == -1 && errno == EINTR); + return ret; + } + + /* wait for child to complete, and retrieve its exit code */ + while ((waitret = waitpid(pid, &status, 0) == -1) + && (errno == EINTR)); + if (waitret == -1) { + ret = -errno; + virReportSystemError(errno, + _("failed to wait for child creating '%s'"), + path); + VIR_FORCE_CLOSE(fd); + return ret; + } + if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES || + fd == -1) { + /* fall back to the simpler method, which works better in + * some cases */ + VIR_FORCE_CLOSE(fd); + if (flags & VIR_FILE_OPEN_NOFORK) { + /* If we had already tried opening w/o fork+setuid and + * failed, no sense trying again. Just set return the + * original errno that we got at that time (by + * definition, always either EACCES or EPERM - EACCES + * is close enough). + */ + return -EACCES; + } + if ((fd = open(path, openflags, mode)) < 0) + return -errno; + ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); + if (ret < 0) { + VIR_FORCE_CLOSE(fd); + return ret; + } + } + return fd; +} + +/** + * virFileOpenAs: + * @path: file to open or create + * @openflags: flags to pass to open + * @mode: mode to use on creation or when forcing permissions + * @uid: uid that should own file on creation + * @gid: gid that should own file + * @flags: bit-wise or of VIR_FILE_OPEN_* flags + * + * Open @path, and return an fd to the open file. @openflags contains + * the flags normally passed to open(2), while those in @flags are + * used internally. If @flags includes VIR_FILE_OPEN_NOFORK, then try + * opening the file while executing with the current uid:gid + * (i.e. don't fork+setuid+setgid before the call to open()). If + * @flags includes VIR_FILE_OPEN_FORK, then try opening the file while + * the effective user id is @uid (by forking a child process); this + * allows one to bypass root-squashing NFS issues; NOFORK is always + * tried before FORK (the absence of both flags is treated identically + * to (VIR_FILE_OPEN_NOFORK | VIR_FILE_OPEN_FORK)). If @flags includes + * VIR_FILE_OPEN_FORCE_OWNER, then ensure that @path is owned by + * uid:gid before returning (even if it already existed with a + * different owner). If @flags includes VIR_FILE_OPEN_FORCE_MODE, + * ensure it has those permissions before returning (again, even if + * the file already existed with different permissions). The return + * value (if non-negative) is the file descriptor, left open. Returns + * -errno on failure. */ +int +virFileOpenAs(const char *path, int openflags, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) +{ + int ret = 0, fd = -1; + + /* allow using -1 to mean "current value" */ + if (uid == (uid_t) -1) + uid = getuid(); + if (gid == (gid_t) -1) + gid = getgid(); + + /* treat absence of both flags as presence of both for simpler + * calling. */ + if (!(flags & (VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK))) + flags |= VIR_FILE_OPEN_NOFORK|VIR_FILE_OPEN_FORK; + + if ((flags & VIR_FILE_OPEN_NOFORK) + || (getuid() != 0) + || ((uid == 0) && (gid == 0))) { + + if ((fd = open(path, openflags, mode)) < 0) { + ret = -errno; + } else { + ret = virFileOpenForceOwnerMode(path, fd, mode, uid, gid, flags); + if (ret < 0) + goto error; + } + } + + /* If we either 1) didn't try opening as current user at all, or + * 2) failed, and errno/virStorageFileIsSharedFS indicate we might + * be successful if we try as a different uid, then try doing + * fork+setuid+setgid before opening. + */ + if ((fd < 0) && (flags & VIR_FILE_OPEN_FORK)) { + + if (ret < 0) { + /* An open(2) that failed due to insufficient permissions + * could return one or the other of these depending on OS + * version and circumstances. Any other errno indicates a + * problem that couldn't be remedied by fork+setuid + * anyway. */ + if (ret != -EACCES && ret != -EPERM) + goto error; + + /* On Linux we can also verify the FS-type of the + * directory. (this is a NOP on other platforms). */ + switch (virStorageFileIsSharedFS(path)) { + case 1: + /* it was on a network share, so we'll re-try */ + break; + case -1: + /* failure detecting fstype */ + virReportSystemError(errno, _("couldn't determine fs type " + "of mount containing '%s'"), path); + goto error; + case 0: + default: + /* file isn't on a recognized network FS */ + goto error; + } + } + + /* passed all prerequisites - retry the open w/fork+setuid */ + if ((fd = virFileOpenForked(path, openflags, mode, uid, gid, flags)) < 0) { + ret = fd; + fd = -1; + goto error; + } + } + + /* File is successfully opened */ + + return fd; + +error: + if (fd < 0) { + /* whoever failed the open last has already set ret = -errno */ + virReportSystemError(-ret, openflags & O_CREAT + ? _("failed to create file '%s'") + : _("failed to open file '%s'"), + path); + } else { + /* some other failure after the open succeeded */ + VIR_FORCE_CLOSE(fd); + } + return ret; +} + +/* return -errno on failure, or 0 on success */ +static int virDirCreateNoFork(const char *path, mode_t mode, uid_t uid, gid_t gid, + unsigned int flags) { + int ret = 0; + struct stat st; + + if ((mkdir(path, mode) < 0) + && !((errno == EEXIST) && (flags & VIR_DIR_CREATE_ALLOW_EXIST))) { + ret = -errno; + virReportSystemError(errno, _("failed to create directory '%s'"), + path); + goto error; + } + + if (stat(path, &st) == -1) { + ret = -errno; + virReportSystemError(errno, _("stat of '%s' failed"), path); + goto error; + } + if (((st.st_uid != uid) || (st.st_gid != gid)) + && (chown(path, uid, gid) < 0)) { + ret = -errno; + virReportSystemError(errno, _("cannot chown '%s' to (%u, %u)"), + path, (unsigned int) uid, (unsigned int) gid); + goto error; + } + if ((flags & VIR_DIR_CREATE_FORCE_PERMS) + && (chmod(path, mode) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot set mode of '%s' to %04o"), + path, mode); + goto error; + } +error: + return ret; +} + +/* return -errno on failure, or 0 on success */ +int virDirCreate(const char *path, mode_t mode, + uid_t uid, gid_t gid, unsigned int flags) { + struct stat st; + pid_t pid; + int waitret; + int status, ret = 0; + + /* allow using -1 to mean "current value" */ + if (uid == (uid_t) -1) + uid = getuid(); + if (gid == (gid_t) -1) + gid = getgid(); + + if ((!(flags & VIR_DIR_CREATE_AS_UID)) + || (getuid() != 0) + || ((uid == 0) && (gid == 0)) + || ((flags & VIR_DIR_CREATE_ALLOW_EXIST) && (stat(path, &st) >= 0))) { + return virDirCreateNoFork(path, mode, uid, gid, flags); + } + + int forkRet = virFork(&pid); + + if (pid < 0) { + ret = -errno; + return ret; + } + + if (pid) { /* parent */ + /* wait for child to complete, and retrieve its exit code */ + while ((waitret = waitpid(pid, &status, 0) == -1) && (errno == EINTR)); + if (waitret == -1) { + ret = -errno; + virReportSystemError(errno, + _("failed to wait for child creating '%s'"), + path); + goto parenterror; + } + if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) { + /* fall back to the simpler method, which works better in + * some cases */ + return virDirCreateNoFork(path, mode, uid, gid, flags); + } +parenterror: + return ret; + } + + /* child */ + + if (forkRet < 0) { + /* error encountered and logged in virFork() after the fork. */ + goto childerror; + } + + /* set desired uid/gid, then attempt to create the directory */ + + if (virSetUIDGID(uid, gid) < 0) { + ret = -errno; + goto childerror; + } + if (mkdir(path, mode) < 0) { + ret = -errno; + if (ret != -EACCES) { + /* in case of EACCES, the parent will retry */ + virReportSystemError(errno, _("child failed to create directory '%s'"), + path); + } + goto childerror; + } + /* check if group was set properly by creating after + * setgid. If not, try doing it with chown */ + if (stat(path, &st) == -1) { + ret = -errno; + virReportSystemError(errno, + _("stat of '%s' failed"), path); + goto childerror; + } + if ((st.st_gid != gid) && (chown(path, -1, gid) < 0)) { + ret = -errno; + virReportSystemError(errno, + _("cannot chown '%s' to group %u"), + path, (unsigned int) gid); + goto childerror; + } + if ((flags & VIR_DIR_CREATE_FORCE_PERMS) + && chmod(path, mode) < 0) { + virReportSystemError(errno, + _("cannot set mode of '%s' to %04o"), + path, mode); + goto childerror; + } +childerror: + _exit(ret); +} + +#else /* WIN32 */ + +int +virFileAccessibleAs(const char *path, + int mode, + uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED) +{ + + VIR_WARN("Ignoring uid/gid due to WIN32"); + + return access(path, mode); +} + +/* return -errno on failure, or 0 on success */ +int virFileOpenAs(const char *path ATTRIBUTE_UNUSED, + int openflags ATTRIBUTE_UNUSED, + mode_t mode ATTRIBUTE_UNUSED, + uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED, + unsigned int flags_unused ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virFileOpenAs is not implemented for WIN32")); + + return -ENOSYS; +} + +int virDirCreate(const char *path ATTRIBUTE_UNUSED, + mode_t mode ATTRIBUTE_UNUSED, + uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED, + unsigned int flags_unused ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virDirCreate is not implemented for WIN32")); + + return -ENOSYS; +} +#endif /* WIN32 */ + +static int virFileMakePathHelper(char *path, mode_t mode) +{ + struct stat st; + char *p; + + VIR_DEBUG("path=%s mode=0%o", path, mode); + + if (stat(path, &st) >= 0) { + if (S_ISDIR(st.st_mode)) + return 0; + + errno = ENOTDIR; + return -1; + } + + if (errno != ENOENT) + return -1; + + if ((p = strrchr(path, '/')) == NULL) { + errno = EINVAL; + return -1; + } + + if (p != path) { + *p = '\0'; + + if (virFileMakePathHelper(path, mode) < 0) + return -1; + + *p = '/'; + } + + if (mkdir(path, mode) < 0 && errno != EEXIST) + return -1; + + return 0; +} + +/** + * Creates the given directory with mode 0777 if it's not already existing. + * + * Returns 0 on success, or -1 if an error occurred (in which case, errno + * is set appropriately). + */ +int virFileMakePath(const char *path) +{ + return virFileMakePathWithMode(path, 0777); +} + +int +virFileMakePathWithMode(const char *path, + mode_t mode) +{ + int ret = -1; + char *tmp; + + if ((tmp = strdup(path)) == NULL) + goto cleanup; + + ret = virFileMakePathHelper(tmp, mode); + +cleanup: + VIR_FREE(tmp); + return ret; +} + +/* Build up a fully qualified path for a config file to be + * associated with a persistent guest or network */ +char * +virFileBuildPath(const char *dir, const char *name, const char *ext) +{ + char *path; + + if (ext == NULL) { + if (virAsprintf(&path, "%s/%s", dir, name) < 0) { + virReportOOMError(); + return NULL; + } + } else { + if (virAsprintf(&path, "%s/%s%s", dir, name, ext) < 0) { + virReportOOMError(); + return NULL; + } + } + + return path; +} + +/* Open a non-blocking master side of a pty. If ttyName is not NULL, + * then populate it with the name of the slave. If rawmode is set, + * also put the master side into raw mode before returning. */ +#ifndef WIN32 +int virFileOpenTty(int *ttymaster, + char **ttyName, + int rawmode) +{ + /* XXX A word of caution - on some platforms (Solaris and HP-UX), + * additional ioctl() calls are needs after opening the slave + * before it will cause isatty() to return true. Should we make + * virFileOpenTty also return the opened slave fd, so the caller + * doesn't have to worry about that mess? */ + int ret = -1; + int slave = -1; + char *name = NULL; + + /* Unfortunately, we can't use the name argument of openpty, since + * there is no guarantee on how large the buffer has to be. + * Likewise, we can't use the termios argument: we have to use + * read-modify-write since there is no portable way to initialize + * a struct termios without use of tcgetattr. */ + if (openpty(ttymaster, &slave, NULL, NULL, NULL) < 0) + return -1; + + /* What a shame that openpty cannot atomically set FD_CLOEXEC, but + * that using posix_openpt/grantpt/unlockpt/ptsname is not + * thread-safe, and that ptsname_r is not portable. */ + if (virSetNonBlock(*ttymaster) < 0 || + virSetCloseExec(*ttymaster) < 0) + goto cleanup; + + /* While Linux supports tcgetattr on either the master or the + * slave, Solaris requires it to be on the slave. */ + if (rawmode) { + struct termios ttyAttr; + if (tcgetattr(slave, &ttyAttr) < 0) + goto cleanup; + + cfmakeraw(&ttyAttr); + + if (tcsetattr(slave, TCSADRAIN, &ttyAttr) < 0) + goto cleanup; + } + + /* ttyname_r on the slave is required by POSIX, while ptsname_r on + * the master is a glibc extension, and the POSIX ptsname is not + * thread-safe. Since openpty gave us both descriptors, guess + * which way we will determine the name? :) */ + if (ttyName) { + /* Initial guess of 64 is generally sufficient; rely on ERANGE + * to tell us if we need to grow. */ + size_t len = 64; + int rc; + + if (VIR_ALLOC_N(name, len) < 0) + goto cleanup; + + while ((rc = ttyname_r(slave, name, len)) == ERANGE) { + if (VIR_RESIZE_N(name, len, len, len) < 0) + goto cleanup; + } + if (rc != 0) { + errno = rc; + goto cleanup; + } + *ttyName = name; + name = NULL; + } + + ret = 0; + +cleanup: + if (ret != 0) + VIR_FORCE_CLOSE(*ttymaster); + VIR_FORCE_CLOSE(slave); + VIR_FREE(name); + + return ret; +} +#else /* WIN32 */ +int virFileOpenTty(int *ttymaster ATTRIBUTE_UNUSED, + char **ttyName ATTRIBUTE_UNUSED, + int rawmode ATTRIBUTE_UNUSED) +{ + /* mingw completely lacks pseudo-terminals, and the gnulib + * replacements are not (yet) license compatible. */ + errno = ENOSYS; + return -1; +} +#endif /* WIN32 */ + +bool virFileIsAbsPath(const char *path) +{ + if (!path) + return false; + + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + return true; + +#ifdef WIN32 + if (c_isalpha(path[0]) && + path[1] == ':' && + VIR_FILE_IS_DIR_SEPARATOR(path[2])) + return true; +#endif + + return false; +} + + +const char *virFileSkipRoot(const char *path) +{ +#ifdef WIN32 + /* Skip \\server\share or //server/share */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0]) && + VIR_FILE_IS_DIR_SEPARATOR(path[1]) && + path[2] && + !VIR_FILE_IS_DIR_SEPARATOR(path[2])) + { + const char *p = strchr(path + 2, VIR_FILE_DIR_SEPARATOR); + const char *q = strchr(path + 2, '/'); + + if (p == NULL || (q != NULL && q < p)) + p = q; + + if (p && p > path + 2 && p[1]) { + path = p + 1; + + while (path[0] && + !VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + /* Possibly skip a backslash after the share name */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + return path; + } + } +#endif + + /* Skip initial slashes */ + if (VIR_FILE_IS_DIR_SEPARATOR(path[0])) { + while (VIR_FILE_IS_DIR_SEPARATOR(path[0])) + path++; + + return path; + } + +#ifdef WIN32 + /* Skip X:\ */ + if (c_isalpha(path[0]) && + path[1] == ':' && + VIR_FILE_IS_DIR_SEPARATOR(path[2])) + return path + 3; +#endif + + return path; +} + + + +/* + * Creates an absolute path for a potentially relative path. + * Return 0 if the path was not relative, or on success. + * Return -1 on error. + * + * You must free the result. + */ +int virFileAbsPath(const char *path, char **abspath) +{ + char *buf; + + if (path[0] == '/') { + if (!(*abspath = strdup(path))) + return -1; + } else { + buf = getcwd(NULL, 0); + if (buf == NULL) + return -1; + + if (virAsprintf(abspath, "%s/%s", buf, path) < 0) { + VIR_FREE(buf); + return -1; + } + VIR_FREE(buf); + } + + return 0; +} + +/* Remove spurious / characters from a path. The result must be freed */ +char * +virFileSanitizePath(const char *path) +{ + const char *cur = path; + char *cleanpath; + int idx = 0; + + cleanpath = strdup(path); + if (!cleanpath) { + virReportOOMError(); + return NULL; + } + + /* Need to sanitize: + * // -> // + * /// -> / + * /../foo -> /../foo + * /foo///bar/ -> /foo/bar + */ + + /* Starting with // is valid posix, but ///foo == /foo */ + if (cur[0] == '/' && cur[1] == '/' && cur[2] != '/') { + idx = 2; + cur += 2; + } + + /* Sanitize path in place */ + while (*cur != '\0') { + if (*cur != '/') { + cleanpath[idx++] = *cur++; + continue; + } + + /* Skip all extra / */ + while (*++cur == '/') + continue; + + /* Don't add a trailing / */ + if (idx != 0 && *cur == '\0') + break; + + cleanpath[idx++] = '/'; + } + cleanpath[idx] = '\0'; + + return cleanpath; +} + +/* 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); /* exempt from syntax-check */ + 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); /* exempt from syntax-check */ + 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 a "long" value. */ +int +virStrToLong_l(char const *s, char **end_ptr, int base, long *result) +{ + long int val; + char *p; + int err; + + errno = 0; + val = strtol(s, &p, base); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + if (end_ptr) + *end_ptr = p; + if (err) + return -1; + *result = val; + return 0; +} + +/* Just like virStrToLong_i, above, but produce an "unsigned long" value. */ +int +virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result) +{ + unsigned long int val; + char *p; + int err; + + errno = 0; + val = strtoul(s, &p, base); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + if (end_ptr) + *end_ptr = p; + if (err) + return -1; + *result = val; + return 0; +} + +/* Just like virStrToLong_i, above, but produce a "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); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + 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); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + 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); /* exempt from syntax-check */ + err = (errno || (!end_ptr && *p) || p == s); + if (end_ptr) + *end_ptr = p; + if (err) + return -1; + *result = val; + return 0; +} + +/* Convert C from hexadecimal character to integer. */ +int +virHexToBin(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; + } +} + +/* Scale an integer VALUE in-place by an optional case-insensitive + * SUFFIX, defaulting to SCALE if suffix is NULL or empty (scale is + * typically 1 or 1024). Recognized suffixes include 'b' or 'bytes', + * as well as power-of-two scaling via binary abbreviations ('KiB', + * 'MiB', ...) or their one-letter counterpart ('k', 'M', ...), and + * power-of-ten scaling via SI abbreviations ('KB', 'MB', ...). + * Ensure that the result does not exceed LIMIT. Return 0 on success, + * -1 with error message raised on failure. */ +int +virScaleInteger(unsigned long long *value, const char *suffix, + unsigned long long scale, unsigned long long limit) +{ + if (!suffix || !*suffix) { + if (!scale) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid scale %llu"), scale); + return -1; + } + suffix = ""; + } else if (STRCASEEQ(suffix, "b") || STRCASEEQ(suffix, "byte") || + STRCASEEQ(suffix, "bytes")) { + scale = 1; + } else { + int base; + + if (!suffix[1] || STRCASEEQ(suffix + 1, "iB")) { + base = 1024; + } else if (c_tolower(suffix[1]) == 'b' && !suffix[2]) { + base = 1000; + } else { + virReportError(VIR_ERR_INVALID_ARG, + _("unknown suffix '%s'"), suffix); + return -1; + } + scale = 1; + switch (c_tolower(*suffix)) { + case 'e': + scale *= base; + /* fallthrough */ + case 'p': + scale *= base; + /* fallthrough */ + case 't': + scale *= base; + /* fallthrough */ + case 'g': + scale *= base; + /* fallthrough */ + case 'm': + scale *= base; + /* fallthrough */ + case 'k': + scale *= base; + break; + default: + virReportError(VIR_ERR_INVALID_ARG, + _("unknown suffix '%s'"), suffix); + return -1; + } + } + + if (*value && *value >= (limit / scale)) { + virReportError(VIR_ERR_OVERFLOW, _("value too large: %llu%s"), + *value, suffix); + return -1; + } + *value *= scale; + return 0; +} + +/** + * virSkipSpaces: + * @str: pointer to the char pointer used + * + * Skip potential blanks, this includes space tabs, line feed, + * carriage returns. + */ +void +virSkipSpaces(const char **str) +{ + const char *cur = *str; + + while (c_isspace(*cur)) + cur++; + *str = cur; +} + +/** + * virSkipSpacesAndBackslash: + * @str: pointer to the char pointer used + * + * Like virSkipSpaces, but also skip backslashes erroneously emitted + * by xend + */ +void +virSkipSpacesAndBackslash(const char **str) +{ + const char *cur = *str; + + while (c_isspace(*cur) || *cur == '\\') + cur++; + *str = cur; +} + +/** + * virTrimSpaces: + * @str: string to modify to remove all trailing spaces + * @endp: track the end of the string + * + * If @endp is NULL on entry, then all spaces prior to the trailing + * NUL in @str are removed, by writing NUL into the appropriate + * location. If @endp is non-NULL but points to a NULL pointer, + * then all spaces prior to the trailing NUL in @str are removed, + * NUL is written to the new string end, and endp is set to the + * location of the (new) string end. If @endp is non-NULL and + * points to a non-NULL pointer, then that pointer is used as + * the end of the string, endp is set to the (new) location, but + * no NUL pointer is written into the string. + */ +void +virTrimSpaces(char *str, char **endp) +{ + char *end; + + if (!endp || !*endp) + end = str + strlen(str); + else + end = *endp; + while (end > str && c_isspace(end[-1])) + end--; + if (endp) { + if (!*endp) + *end = '\0'; + *endp = end; + } else { + *end = '\0'; + } +} + +/** + * virSkipSpacesBackwards: + * @str: start of string + * @endp: on entry, *endp must be NULL or a location within @str, on exit, + * will be adjusted to skip trailing spaces, or to NULL if @str had nothing + * but spaces. + */ +void +virSkipSpacesBackwards(const char *str, char **endp) +{ + /* Casting away const is safe, since virTrimSpaces does not + * modify string with this particular usage. */ + char *s = (char*) str; + + if (!*endp) + *endp = s + strlen(s); + virTrimSpaces(s, endp); + if (s == *endp) + *endp = NULL; +} + +/** + * 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; +} + + +/** + * virParseVersionString: + * @str: const char pointer to the version string + * @version: unsigned long pointer to output the version number + * @allowMissing: true to treat 3 like 3.0.0, false to error out on + * missing minor or micro + * + * Parse an unsigned version number from a version string. Expecting + * 'major.minor.micro' format, ignoring an optional suffix. + * + * The major, minor and micro numbers are encoded into a single version number: + * + * 1000000 * major + 1000 * minor + micro + * + * Returns the 0 for success, -1 for error. + */ +int +virParseVersionString(const char *str, unsigned long *version, + bool allowMissing) +{ + unsigned int major, minor = 0, micro = 0; + char *tmp; + + if (virStrToLong_ui(str, &tmp, 10, &major) < 0) + return -1; + + if (!allowMissing && *tmp != '.') + return -1; + + if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, &minor) < 0) + return -1; + + if (!allowMissing && *tmp != '.') + return -1; + + if ((*tmp == '.') && virStrToLong_ui(tmp + 1, &tmp, 10, µ) < 0) + return -1; + + if (major > UINT_MAX / 1000000 || minor > 999 || micro > 999) + return -1; + + *version = 1000000 * major + 1000 * minor + micro; + + return 0; +} + +/** + * virVasprintf + * + * like glibc's vasprintf but makes sure *strp == NULL on failure + */ +int +virVasprintf(char **strp, const char *fmt, va_list list) +{ + int ret; + + if ((ret = vasprintf(strp, fmt, list)) == -1) + *strp = NULL; + + 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); + ret = virVasprintf(strp, fmt, ap); + va_end(ap); + return ret; +} + +/** + * virStrncpy + * + * A safe version of strncpy. The last parameter is the number of bytes + * available in the destination string, *not* the number of bytes you want + * to copy. If the destination is not large enough to hold all n of the + * src string bytes plus a \0, NULL is returned and no data is copied. + * If the destination is large enough to hold the n bytes plus \0, then the + * string is copied and a pointer to the destination string is returned. + */ +char * +virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) +{ + char *ret; + + if (n > (destbytes - 1)) + return NULL; + + ret = strncpy(dest, src, n); + /* strncpy NULL terminates iff the last character is \0. Therefore + * force the last byte to be \0 + */ + dest[n] = '\0'; + + return ret; +} + +/** + * virStrcpy + * + * A safe version of strcpy. The last parameter is the number of bytes + * available in the destination string, *not* the number of bytes you want + * to copy. If the destination is not large enough to hold all n of the + * src string bytes plus a \0, NULL is returned and no data is copied. + * If the destination is large enough to hold the source plus \0, then the + * string is copied and a pointer to the destination string is returned. + */ +char * +virStrcpy(char *dest, const char *src, size_t destbytes) +{ + return virStrncpy(dest, src, strlen(src), destbytes); +} + +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; +} + +/* In case thread-safe locales are available */ +#if HAVE_NEWLOCALE + +static locale_t virLocale; + +static int +virLocaleOnceInit(void) +{ + virLocale = newlocale(LC_ALL_MASK, "C", (locale_t)0); + if (!virLocale) + return -1; + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virLocale) +#endif + +/** + * virDoubleToStr + * + * converts double to string with C locale (thread-safe). + * + * Returns -1 on error, size of the string otherwise. + */ +int +virDoubleToStr(char **strp, double number) +{ + int ret = -1; + +#if HAVE_NEWLOCALE + + locale_t old_loc; + + if (virLocaleInitialize() < 0) + goto error; + + old_loc = uselocale(virLocale); + ret = virAsprintf(strp, "%lf", number); + uselocale(old_loc); + +#else + + char *radix, *tmp; + struct lconv *lc; + + if ((ret = virAsprintf(strp, "%lf", number) < 0)) + goto error; + + lc = localeconv(); + radix = lc->decimal_point; + tmp = strstr(*strp, radix); + if (tmp) { + *tmp = '.'; + if (strlen(radix) > 1) + memmove(tmp + 1, tmp + strlen(radix), strlen(*strp) - (tmp - *strp)); + } + +#endif /* HAVE_NEWLOCALE */ + error: + return ret; +} + + +/** + * Format @val as a base-10 decimal number, in the + * buffer @buf of size @buflen. To allocate a suitable + * sized buffer, the INT_BUFLEN(int) macro should be + * used + * + * Returns pointer to start of the number in @buf + */ +char * +virFormatIntDecimal(char *buf, size_t buflen, int val) +{ + char *p = buf + buflen - 1; + *p = '\0'; + if (val >= 0) { + do { + *--p = '0' + (val % 10); + val /= 10; + } while (val != 0); + } else { + do { + *--p = '0' - (val % 10); + val /= 10; + } while (val != 0); + *--p = '-'; + } + return p; +} + + +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]+[0-9]*$/ + * into the corresponding index (e.g. sda => 0, hdz => 25, vdaa => 26) + * Note that any trailing string of digits is simply ignored. + * @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", "ubd"}; + 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++) { + if (!c_islower(*ptr)) + break; + + idx = (idx + (i < 1 ? 0 : 1)) * 26; + idx += *ptr - 'a'; + ptr++; + } + + /* Count the trailing digits. */ + size_t n_digits = strspn(ptr, "0123456789"); + if (ptr[n_digits] != '\0') + return -1; + + return idx; +} + +char *virIndexToDiskName(int idx, const char *prefix) +{ + char *name = NULL; + int i, k, offset; + + if (idx < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Disk index %d is negative"), idx); + return NULL; + } + + for (i = 0, k = idx; k >= 0; ++i, k = k / 26 - 1) { } + + offset = strlen(prefix); + + if (VIR_ALLOC_N(name, offset + i + 1)) { + virReportOOMError(); + return NULL; + } + + strcpy(name, prefix); + name[offset + i] = '\0'; + + for (i = i - 1, k = idx; k >= 0; --i, k = k / 26 - 1) { + name[offset + i] = 'a' + (k % 26); + } + + return name; +} + +#ifndef AI_CANONIDN +# define AI_CANONIDN 0 +#endif + +/* Who knew getting a hostname could be so delicate. In Linux (and Unices + * in general), many things depend on "hostname" returning a value that will + * resolve one way or another. In the modern world where networks frequently + * come and go this is often being hard-coded to resolve to "localhost". If + * it *doesn't* resolve to localhost, then we would prefer to have the FQDN. + * That leads us to 3 possibilities: + * + * 1) gethostname() returns an FQDN (not localhost) - we return the string + * as-is, it's all of the information we want + * 2) gethostname() returns "localhost" - we return localhost; doing further + * work to try to resolve it is pointless + * 3) gethostname() returns a shortened hostname - in this case, we want to + * try to resolve this to a fully-qualified name. Therefore we pass it + * to getaddrinfo(). There are two possible responses: + * a) getaddrinfo() resolves to a FQDN - return the FQDN + * b) getaddrinfo() fails or resolves to localhost - in this case, the + * data we got from gethostname() is actually more useful than what + * we got from getaddrinfo(). Return the value from gethostname() + * and hope for the best. + */ +char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED) +{ + int r; + char hostname[HOST_NAME_MAX+1], *result; + struct addrinfo hints, *info; + + r = gethostname(hostname, sizeof(hostname)); + if (r == -1) { + virReportSystemError(errno, + "%s", _("failed to determine host name")); + return NULL; + } + NUL_TERMINATE(hostname); + + if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) { + /* in this case, gethostname returned localhost (meaning we can't + * do any further canonicalization), or it returned an FQDN (and + * we don't need to do any further canonicalization). Return the + * string as-is; it's up to callers to check whether "localhost" + * is allowed. + */ + result = strdup(hostname); + goto check_and_return; + } + + /* otherwise, it's a shortened, non-localhost, hostname. Attempt to + * canonicalize the hostname by running it through getaddrinfo + */ + + 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) { + VIR_WARN("getaddrinfo failed for '%s': %s", + hostname, gai_strerror(r)); + result = strdup(hostname); + goto check_and_return; + } + + /* Tell static analyzers about getaddrinfo semantics. */ + sa_assert(info); + + if (info->ai_canonname == NULL || + STRPREFIX(info->ai_canonname, "localhost")) + /* in this case, we tried to canonicalize and we ended up back with + * localhost. Ignore the canonicalized name and just return the + * original hostname + */ + result = strdup(hostname); + else + /* Caller frees this string. */ + result = strdup(info->ai_canonname); + + freeaddrinfo(info); + +check_and_return: + if (result == NULL) + virReportOOMError(); + return result; +} + +#ifdef HAVE_GETPWUID_R +enum { + VIR_USER_ENT_DIRECTORY, + VIR_USER_ENT_NAME, +}; + +static char *virGetUserEnt(uid_t uid, + int field) +{ + char *strbuf; + char *ret; + struct passwd pwbuf; + struct passwd *pw = NULL; + long val = sysconf(_SC_GETPW_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + 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. + */ + while ((rc = getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + VIR_FREE(strbuf); + return NULL; + } + } + if (rc != 0 || pw == NULL) { + virReportSystemError(rc, + _("Failed to find user record for uid '%u'"), + (unsigned int) 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(); + + return ret; +} + +static char *virGetGroupEnt(gid_t gid) +{ + char *strbuf; + char *ret; + struct group grbuf; + struct group *gr = NULL; + long val = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + return NULL; + } + + /* + * From the manpage (terrifying but true): + * + * ERRORS + * 0 or ENOENT or ESRCH or EBADF or EPERM or ... + * The given name or gid was not found. + */ + while ((rc = getgrgid_r(gid, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + VIR_FREE(strbuf); + return NULL; + } + } + if (rc != 0 || gr == NULL) { + virReportSystemError(rc, + _("Failed to find group record for gid '%u'"), + (unsigned int) gid); + VIR_FREE(strbuf); + return NULL; + } + + ret = strdup(gr->gr_name); + + VIR_FREE(strbuf); + if (!ret) + virReportOOMError(); + + return ret; +} + +char *virGetUserDirectory(void) +{ + return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); +} + +static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir) +{ + const char *path = getenv(xdgenvname); + char *ret = NULL; + char *home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY); + + if (path && path[0]) { + if (virAsprintf(&ret, "%s/libvirt", path) < 0) + goto no_memory; + } else { + if (virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir) < 0) + goto no_memory; + } + + cleanup: + VIR_FREE(home); + return ret; + no_memory: + virReportOOMError(); + goto cleanup; +} + +char *virGetUserConfigDirectory(void) +{ + return virGetXDGDirectory("XDG_CONFIG_HOME", ".config"); +} + +char *virGetUserCacheDirectory(void) +{ + return virGetXDGDirectory("XDG_CACHE_HOME", ".cache"); +} + +char *virGetUserRuntimeDirectory(void) +{ + const char *path = getenv("XDG_RUNTIME_DIR"); + + if (!path || !path[0]) { + return virGetUserCacheDirectory(); + } else { + char *ret; + + if (virAsprintf(&ret, "%s/libvirt", path) < 0) { + virReportOOMError(); + return NULL; + } + + return ret; + } +} + +char *virGetUserName(uid_t uid) +{ + return virGetUserEnt(uid, VIR_USER_ENT_NAME); +} + +char *virGetGroupName(gid_t gid) +{ + return virGetGroupEnt(gid); +} + +/* Search in the password database for a user id that matches the user name + * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. + */ +static int +virGetUserIDByName(const char *name, uid_t *uid) +{ + char *strbuf = NULL; + struct passwd pwbuf; + struct passwd *pw = NULL; + long val = sysconf(_SC_GETPW_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + int ret = -1; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + + while ((rc = getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + if (!pw) { + if (rc != 0) { + char buf[1024]; + /* log the possible error from getpwnam_r. Unfortunately error + * reporting from this function is bad and we can't really + * rely on it, so we just report that the user wasn't found */ + VIR_WARN("User record for user '%s' was not found: %s", + name, virStrerror(rc, buf, sizeof(buf))); + } + + ret = 1; + goto cleanup; + } + + *uid = pw->pw_uid; + ret = 0; + +cleanup: + VIR_FREE(strbuf); + + return ret; +} + +/* Try to match a user id based on `user`. The default behavior is to parse + * `user` first as a user name and then as a user id. However if `user` + * contains a leading '+', the rest of the string is always parsed as a uid. + * + * Returns 0 on success and -1 otherwise. + */ +int +virGetUserID(const char *user, uid_t *uid) +{ + unsigned int uint_uid; + + if (*user == '+') { + user++; + } else { + int rc = virGetUserIDByName(user, uid); + if (rc <= 0) + return rc; + } + + if (virStrToLong_ui(user, NULL, 10, &uint_uid) < 0 || + ((uid_t) uint_uid) != uint_uid) { + virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse user '%s'"), + user); + return -1; + } + + *uid = uint_uid; + + return 0; +} + +/* Search in the group database for a group id that matches the group name + * `name`. Returns 0 on success, -1 on failure or 1 if name cannot be found. + */ +static int +virGetGroupIDByName(const char *name, gid_t *gid) +{ + char *strbuf = NULL; + struct group grbuf; + struct group *gr = NULL; + long val = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t strbuflen = val; + int rc; + int ret = -1; + + /* sysconf is a hint; if it fails, fall back to a reasonable size */ + if (val < 0) + strbuflen = 1024; + + if (VIR_ALLOC_N(strbuf, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + + while ((rc = getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr)) == ERANGE) { + if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0) { + virReportOOMError(); + goto cleanup; + } + } + + if (!gr) { + if (rc != 0) { + char buf[1024]; + /* log the possible error from getgrnam_r. Unfortunately error + * reporting from this function is bad and we can't really + * rely on it, so we just report that the user wasn't found */ + VIR_WARN("Group record for user '%s' was not found: %s", + name, virStrerror(rc, buf, sizeof(buf))); + } + + ret = 1; + goto cleanup; + } + + *gid = gr->gr_gid; + ret = 0; + +cleanup: + VIR_FREE(strbuf); + + return ret; +} + +/* Try to match a group id based on `group`. The default behavior is to parse + * `group` first as a group name and then as a group id. However if `group` + * contains a leading '+', the rest of the string is always parsed as a guid. + * + * Returns 0 on success and -1 otherwise. + */ +int +virGetGroupID(const char *group, gid_t *gid) +{ + unsigned int uint_gid; + + if (*group == '+') { + group++; + } else { + int rc = virGetGroupIDByName(group, gid); + if (rc <= 0) + return rc; + } + + if (virStrToLong_ui(group, NULL, 10, &uint_gid) < 0 || + ((gid_t) uint_gid) != uint_gid) { + virReportError(VIR_ERR_INVALID_ARG, _("Failed to parse group '%s'"), + group); + return -1; + } + + *gid = uint_gid; + + return 0; +} + +/* Set the real and effective uid and gid to the given values, and call + * initgroups so that the process has all the assumed group membership of + * that uid. return 0 on success, -1 on failure (the original system error + * remains in errno). + */ +int +virSetUIDGID(uid_t uid, gid_t gid) +{ + int err; + char *buf = NULL; + + if (gid > 0) { + if (setregid(gid, gid) < 0) { + virReportSystemError(err = errno, + _("cannot change to '%d' group"), + (unsigned int) gid); + goto error; + } + } + + if (uid > 0) { +# ifdef HAVE_INITGROUPS + struct passwd pwd, *pwd_result; + size_t bufsize; + int rc; + + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + if (bufsize == -1) + bufsize = 16384; + + if (VIR_ALLOC_N(buf, bufsize) < 0) { + virReportOOMError(); + err = ENOMEM; + goto error; + } + while ((rc = getpwuid_r(uid, &pwd, buf, bufsize, + &pwd_result)) == ERANGE) { + if (VIR_RESIZE_N(buf, bufsize, bufsize, bufsize) < 0) { + virReportOOMError(); + err = ENOMEM; + goto error; + } + } + + if (rc) { + virReportSystemError(err = rc, _("cannot getpwuid_r(%d)"), + (unsigned int) uid); + goto error; + } + + if (!pwd_result) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("getpwuid_r failed to retrieve data " + "for uid '%d'"), + (unsigned int) uid); + err = EINVAL; + goto error; + } + + if (initgroups(pwd.pw_name, pwd.pw_gid) < 0) { + virReportSystemError(err = errno, + _("cannot initgroups(\"%s\", %d)"), + pwd.pw_name, (unsigned int) pwd.pw_gid); + goto error; + } +# endif + if (setreuid(uid, uid) < 0) { + virReportSystemError(err = errno, + _("cannot change to uid to '%d'"), + (unsigned int) uid); + goto error; + } + } + + VIR_FREE(buf); + return 0; + +error: + VIR_FREE(buf); + errno = err; + return -1; +} + +#else /* ! HAVE_GETPWUID_R */ + +# ifdef WIN32 +/* These methods are adapted from GLib2 under terms of LGPLv2+ */ +static int +virGetWin32SpecialFolder(int csidl, char **path) +{ + char buf[MAX_PATH+1]; + LPITEMIDLIST pidl = NULL; + int ret = 0; + + *path = NULL; + + if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK) { + if (SHGetPathFromIDList(pidl, buf)) { + if (!(*path = strdup(buf))) { + virReportOOMError(); + ret = -1; + } + } + CoTaskMemFree(pidl); + } + return ret; +} + +static int +virGetWin32DirectoryRoot(char **path) +{ + char windowsdir[MAX_PATH]; + int ret = 0; + + *path = NULL; + + if (GetWindowsDirectory(windowsdir, ARRAY_CARDINALITY(windowsdir))) + { + const char *tmp; + /* Usually X:\Windows, but in terminal server environments + * might be an UNC path, AFAIK. + */ + tmp = virFileSkipRoot(windowsdir); + if (VIR_FILE_IS_DIR_SEPARATOR(tmp[-1]) && + tmp[-2] != ':') + tmp--; + + windowsdir[tmp - windowsdir] = '\0'; + } else { + strcpy(windowsdir, "C:\\"); + } + + if (!(*path = strdup(windowsdir))) { + virReportOOMError(); + ret = -1; + } + + return ret; +} + + + +char * +virGetUserDirectory(void) +{ + const char *dir; + char *ret; + + dir = getenv("HOME"); + + /* Only believe HOME if it is an absolute path and exists */ + if (dir) { + if (!virFileIsAbsPath(dir) || + !virFileExists(dir)) + dir = NULL; + } + + /* In case HOME is Unix-style (it happens), convert it to + * Windows style. + */ + if (dir) { + char *p; + while ((p = strchr(dir, '/')) != NULL) + *p = '\\'; + } + + if (!dir) + /* USERPROFILE is probably the closest equivalent to $HOME? */ + dir = getenv("USERPROFILE"); + + if (dir) { + if (!(ret = strdup(dir))) { + virReportOOMError(); + return NULL; + } + } + + if (!ret && + virGetWin32SpecialFolder(CSIDL_PROFILE, &ret) < 0) + return NULL; + + if (!ret && + virGetWin32DirectoryRoot(&ret) < 0) + return NULL; + + if (!ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine home directory")); + return NULL; + } + + return ret; +} + +char * +virGetUserConfigDirectory(void) +{ + char *ret; + if (virGetWin32SpecialFolder(CSIDL_LOCAL_APPDATA, &ret) < 0) + return NULL; + + if (!ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine config directory")); + return NULL; + } + return ret; +} + +char * +virGetUserCacheDirectory(void) +{ + char *ret; + if (virGetWin32SpecialFolder(CSIDL_INTERNET_CACHE, &ret) < 0) + return NULL; + + if (!ret) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to determine config directory")); + return NULL; + } + return ret; +} + +char * +virGetUserRuntimeDirectory(void) +{ + return virGetUserCacheDirectory(); +} +# else /* !HAVE_GETPWUID_R && !WIN32 */ +char * +virGetUserDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserDirectory is not available")); + + return NULL; +} + +char * +virGetUserConfigDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserConfigDirectory is not available")); + + return NULL; +} + +char * +virGetUserCacheDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserCacheDirectory is not available")); + + return NULL; +} + +char * +virGetUserRuntimeDirectory(void) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserRuntimeDirectory is not available")); + + return NULL; +} +# endif /* ! HAVE_GETPWUID_R && ! WIN32 */ + +char * +virGetUserName(uid_t uid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserName is not available")); + + return NULL; +} + +int virGetUserID(const char *name ATTRIBUTE_UNUSED, + uid_t *uid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetUserID is not available")); + + return 0; +} + + +int virGetGroupID(const char *name ATTRIBUTE_UNUSED, + gid_t *gid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetGroupID is not available")); + + return 0; +} + +int +virSetUIDGID(uid_t uid ATTRIBUTE_UNUSED, + gid_t gid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virSetUIDGID is not available")); + return -1; +} + +char * +virGetGroupName(gid_t gid ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("virGetGroupName is not available")); + + return NULL; +} +#endif /* HAVE_GETPWUID_R */ + + +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R +/* 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; +} + +#else /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ + +char * +virFileFindMountPoint(const char *type ATTRIBUTE_UNUSED) +{ + errno = ENOSYS; + + return NULL; +} + +#endif /* defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R */ + +#if defined(UDEVADM) || defined(UDEVSETTLE) +void virFileWaitForDevices(void) +{ +# 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. + */ + if (virRun(settleprog, &exitstatus) < 0) + {} +} +#else +void virFileWaitForDevices(void) {} +#endif + +int virBuildPathInternal(char **path, ...) +{ + char *path_component = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + va_list ap; + int ret = 0; + + va_start(ap, path); + + path_component = va_arg(ap, char *); + virBufferAdd(&buf, path_component, -1); + + while ((path_component = va_arg(ap, char *)) != NULL) + { + virBufferAddChar(&buf, '/'); + virBufferAdd(&buf, path_component, -1); + } + + va_end(ap); + + *path = virBufferContentAndReset(&buf); + if (*path == NULL) { + ret = -1; + } + + return ret; +} + +#if HAVE_LIBDEVMAPPER_H +bool +virIsDevMapperDevice(const char *dev_name) +{ + struct stat buf; + + if (!stat(dev_name, &buf) && + S_ISBLK(buf.st_mode) && + dm_is_dm_major(major(buf.st_rdev))) + return true; + + return false; +} +#else +bool virIsDevMapperDevice(const char *dev_name ATTRIBUTE_UNUSED) +{ + return false; +} +#endif + +bool +virValidateWWN(const char *wwn) { + int i; + + for (i = 0; wwn[i]; i++) + if (!c_isxdigit(wwn[i])) + break; + + if (i != 16 || wwn[i]) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed wwn: %s")); + return false; + } + + return true; +} + +bool +virStrIsPrint(const char *str) +{ + int i; + + for (i = 0; str[i]; i++) + if (!c_isprint(str[i])) + return false; + + return true; +} diff --git a/src/util/virutil.h b/src/util/virutil.h new file mode 100644 index 0000000..6d5dd03 --- /dev/null +++ b/src/util/virutil.h @@ -0,0 +1,284 @@ +/* + * utils.h: common, generic utility functions + * + * Copyright (C) 2010-2012 Red Hat, Inc. + * 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, see + * <http://www.gnu.org/licenses/>. + * + * File created Jul 18, 2007 - Shuveb Hussain <shuveb@binarykarma.com> + */ + +#ifndef __VIR_UTIL_H__ +# define __VIR_UTIL_H__ + +# include "verify.h" +# include "internal.h" +# include <unistd.h> +# include <sys/select.h> +# include <sys/types.h> +# include <stdarg.h> + +# ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +# endif +# ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +# endif + +ssize_t saferead(int fd, void *buf, size_t count) ATTRIBUTE_RETURN_CHECK; +ssize_t safewrite(int fd, const void *buf, size_t count) + ATTRIBUTE_RETURN_CHECK; +int safezero(int fd, off_t offset, off_t len) + ATTRIBUTE_RETURN_CHECK; + +int virSetBlocking(int fd, bool blocking) ATTRIBUTE_RETURN_CHECK; +int virSetNonBlock(int fd) ATTRIBUTE_RETURN_CHECK; +int virSetInherit(int fd, bool inherit) ATTRIBUTE_RETURN_CHECK; +int virSetCloseExec(int fd) ATTRIBUTE_RETURN_CHECK; + +int virPipeReadUntilEOF(int outfd, int errfd, + char **outbuf, char **errbuf); + +int virSetUIDGID(uid_t uid, gid_t gid); + +int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; + +int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK; + +int virFileWriteStr(const char *path, const char *str, mode_t mode) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +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) ATTRIBUTE_RETURN_CHECK; + +int virFileLinkPointsTo(const char *checkLink, + const char *checkDest); + +int virFileResolveLink(const char *linkpath, + char **resultpath) ATTRIBUTE_RETURN_CHECK; +int virFileResolveAllLinks(const char *linkpath, + char **resultpath) ATTRIBUTE_RETURN_CHECK; + +int virFileIsLink(const char *linkpath) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +char *virFindFileInPath(const char *file); + +bool virFileIsDir (const char *file) ATTRIBUTE_NONNULL(1); +bool virFileExists(const char *file) ATTRIBUTE_NONNULL(1); +bool virFileIsExecutable(const char *file) ATTRIBUTE_NONNULL(1); + +char *virFileSanitizePath(const char *path); + +enum { + VIR_FILE_OPEN_NONE = 0, + VIR_FILE_OPEN_NOFORK = (1 << 0), + VIR_FILE_OPEN_FORK = (1 << 1), + VIR_FILE_OPEN_FORCE_MODE = (1 << 2), + VIR_FILE_OPEN_FORCE_OWNER = (1 << 3), +}; +int virFileAccessibleAs(const char *path, int mode, + uid_t uid, gid_t gid) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; +int virFileOpenAs(const char *path, int openflags, mode_t mode, + uid_t uid, gid_t gid, + unsigned int flags) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +enum { + VIR_DIR_CREATE_NONE = 0, + VIR_DIR_CREATE_AS_UID = (1 << 0), + VIR_DIR_CREATE_FORCE_PERMS = (1 << 1), + VIR_DIR_CREATE_ALLOW_EXIST = (1 << 2), +}; +int virDirCreate(const char *path, mode_t mode, uid_t uid, gid_t gid, + unsigned int flags) ATTRIBUTE_RETURN_CHECK; +int virFileMakePath(const char *path) ATTRIBUTE_RETURN_CHECK; +int virFileMakePathWithMode(const char *path, + mode_t mode) ATTRIBUTE_RETURN_CHECK; + +char *virFileBuildPath(const char *dir, + const char *name, + const char *ext) ATTRIBUTE_RETURN_CHECK; + + +# ifdef WIN32 +/* On Win32, the canonical directory separator is the backslash, and + * the search path separator is the semicolon. Note that also the + * (forward) slash works as directory separator. + */ +# define VIR_FILE_DIR_SEPARATOR '\\' +# define VIR_FILE_DIR_SEPARATOR_S "\\" +# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR || (c) == '/') +# define VIR_FILE_PATH_SEPARATOR ';' +# define VIR_FILE_PATH_SEPARATOR_S ";" + +# else /* !WIN32 */ + +# define VIR_FILE_DIR_SEPARATOR '/' +# define VIR_FILE_DIR_SEPARATOR_S "/" +# define VIR_FILE_IS_DIR_SEPARATOR(c) ((c) == VIR_FILE_DIR_SEPARATOR) +# define VIR_FILE_PATH_SEPARATOR ':' +# define VIR_FILE_PATH_SEPARATOR_S ":" + +# endif /* !WIN32 */ + +bool virFileIsAbsPath(const char *path); +int virFileAbsPath(const char *path, + char **abspath) ATTRIBUTE_RETURN_CHECK; +const char *virFileSkipRoot(const char *path); + +int virFileOpenTty(int *ttymaster, + char **ttyName, + int rawmode); + +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_l(char const *s, + char **end_ptr, + int base, + long *result); +int virStrToLong_ul(char const *s, + char **end_ptr, + int base, + unsigned long *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 virScaleInteger(unsigned long long *value, const char *suffix, + unsigned long long scale, unsigned long long limit) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +int virHexToBin(unsigned char c); + +void virSkipSpaces(const char **str) ATTRIBUTE_NONNULL(1); +void virSkipSpacesAndBackslash(const char **str) ATTRIBUTE_NONNULL(1); +void virTrimSpaces(char *str, char **endp) ATTRIBUTE_NONNULL(1); +void virSkipSpacesBackwards(const char *str, char **endp) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int virParseNumber(const char **str); +int virParseVersionString(const char *str, unsigned long *version, + bool allowMissing); +int virAsprintf(char **strp, const char *fmt, ...) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3); +int virVasprintf(char **strp, const char *fmt, va_list list) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 0); +char *virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) + ATTRIBUTE_RETURN_CHECK; +char *virStrcpy(char *dest, const char *src, size_t destbytes) + ATTRIBUTE_RETURN_CHECK; +# define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest)) + +int virDoubleToStr(char **strp, double number) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +char *virFormatIntDecimal(char *buf, size_t buflen, int val) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +int virDiskNameToIndex(const char* str); +char *virIndexToDiskName(int idx, const char *prefix); + +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__ }; \ + verify(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_GETEUID +static inline int geteuid (void) { return 0; } +# endif + +# ifndef HAVE_GETGID +static inline int getgid (void) { return 0; } +# endif + +char *virGetHostname(virConnectPtr conn); + +char *virGetUserDirectory(void); +char *virGetUserConfigDirectory(void); +char *virGetUserCacheDirectory(void); +char *virGetUserRuntimeDirectory(void); +char *virGetUserName(uid_t uid); +char *virGetGroupName(gid_t gid); +int virGetUserID(const char *name, + uid_t *uid) ATTRIBUTE_RETURN_CHECK; +int virGetGroupID(const char *name, + gid_t *gid) ATTRIBUTE_RETURN_CHECK; + +char *virFileFindMountPoint(const char *type); + +void virFileWaitForDevices(void); + +# define virBuildPath(path, ...) virBuildPathInternal(path, __VA_ARGS__, NULL) +int virBuildPathInternal(char **path, ...) ATTRIBUTE_SENTINEL; + +bool virIsDevMapperDevice(const char *dev_name) ATTRIBUTE_NONNULL(1); + +bool virValidateWWN(const char *wwn); + +bool virStrIsPrint(const char *str); +#endif /* __VIR_UTIL_H__ */ diff --git a/src/util/xml.c b/src/util/xml.c index caf26a3..05c7f33 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "xml.h" #include "virbuffer.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h"
diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index cab4398..36539f6 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -31,7 +31,7 @@
#include "internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" #include "vbox_MSCOMGlue.h" diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 5296127..1954ddb 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -38,7 +38,7 @@ #include "vbox_XPCOMCGlue.h" #include "internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h"
diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index cd29e19..f2a0c8f 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -38,7 +38,7 @@ #include "vbox_driver.h" #include "vbox_glue.h" #include "virterror_internal.h" -#include "util.h" +#include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_VBOX
diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 233804e..12195bf 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -28,7 +28,7 @@ #include "datatypes.h" #include "virfile.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "vircommand.h" #include "vmx.h" diff --git a/src/xen/block_stats.c b/src/xen/block_stats.c index 126283b..3f7c97b 100644 --- a/src/xen/block_stats.c +++ b/src/xen/block_stats.c @@ -40,7 +40,7 @@
# include "virterror_internal.h" # include "datatypes.h" -# include "util.h" +# include "virutil.h" # include "block_stats.h" # include "viralloc.h" # include "virfile.h" diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 9b2fcf3..2b8496c 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -54,7 +54,7 @@ # include "xen_inotify.h" #endif #include "xml.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "node_device_conf.h" #include "virpci.h" diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index 5c8fe37..f804620 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -67,7 +67,7 @@ #include "virlog.h" #include "datatypes.h" #include "driver.h" -#include "util.h" +#include "virutil.h" #include "xen_driver.h" #include "xen_hypervisor.h" #include "xs_internal.h" diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 6e8bc2f..7ffc5bb 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -34,7 +34,7 @@ #include "datatypes.h" #include "xend_internal.h" #include "driver.h" -#include "util.h" +#include "virutil.h" #include "virsexpr.h" #include "xen_sxpr.h" #include "virbuffer.h" diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 2109972..e3206eb 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -45,7 +45,7 @@ #include "virhash.h" #include "virbuffer.h" #include "uuid.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virlog.h" #include "count-one-bits.h" diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 0a0ac0e..04b24ab 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -31,7 +31,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virauth.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "viralloc.h" #include "virbuffer.h" diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 33aa4d7..15be403 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -29,7 +29,7 @@ #include "domain_conf.h" #include "virterror_internal.h" #include "datatypes.h" -#include "util.h" +#include "virutil.h" #include "uuid.h" #include "viralloc.h" #include "virbuffer.h" diff --git a/tests/commandhelper.c b/tests/commandhelper.c index 3c7fef5..39f3c53 100644 --- a/tests/commandhelper.c +++ b/tests/commandhelper.c @@ -27,7 +27,7 @@ #include <string.h>
#include "internal.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h" #include "testutils.h" diff --git a/tests/commandtest.c b/tests/commandtest.c index b15c168..d6a285e 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -31,7 +31,7 @@ #include "testutils.h" #include "internal.h" #include "nodeinfo.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "vircommand.h" #include "virfile.h" diff --git a/tests/esxutilstest.c b/tests/esxutilstest.c index b65009b..55b3623 100644 --- a/tests/esxutilstest.c +++ b/tests/esxutilstest.c @@ -9,7 +9,7 @@ # include "internal.h" # include "viralloc.h" # include "testutils.h" -# include "util.h" +# include "virutil.h" # include "vmx/vmx.h" # include "esx/esx_util.h" # include "esx/esx_vi_types.h" diff --git a/tests/eventtest.c b/tests/eventtest.c index 6d00ea8..16a693c 100644 --- a/tests/eventtest.c +++ b/tests/eventtest.c @@ -30,7 +30,7 @@ #include "internal.h" #include "virthread.h" #include "virlog.h" -#include "util.h" +#include "virutil.h" #include "vireventpoll.h"
#define NUM_FDS 31 diff --git a/tests/libvirtdconftest.c b/tests/libvirtdconftest.c index 0365ade..c1d94d2 100644 --- a/tests/libvirtdconftest.c +++ b/tests/libvirtdconftest.c @@ -24,7 +24,7 @@
#include "testutils.h" #include "daemon/libvirtd-config.h" -#include "util.h" +#include "virutil.h" #include "c-ctype.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/tests/nodeinfotest.c b/tests/nodeinfotest.c index c79788e..d900eb9 100644 --- a/tests/nodeinfotest.c +++ b/tests/nodeinfotest.c @@ -8,7 +8,7 @@ #include "testutils.h" #include "internal.h" #include "nodeinfo.h" -#include "util.h" +#include "virutil.h" #include "virfile.h"
#if ! (defined __linux__ && (defined(__x86_64__) || \ diff --git a/tests/openvzutilstest.c b/tests/openvzutilstest.c index 80701a2..9fb7178 100644 --- a/tests/openvzutilstest.c +++ b/tests/openvzutilstest.c @@ -9,7 +9,7 @@ # include "internal.h" # include "viralloc.h" # include "testutils.h" -# include "util.h" +# include "virutil.h" # include "openvz/openvz_conf.h"
static int diff --git a/tests/qemumonitortest.c b/tests/qemumonitortest.c index 21a6828..285dfa8 100644 --- a/tests/qemumonitortest.c +++ b/tests/qemumonitortest.c @@ -10,7 +10,7 @@ # include "internal.h" # include "viralloc.h" # include "testutils.h" -# include "util.h" +# include "virutil.h" # include "qemu/qemu_monitor.h"
struct testEscapeString diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index cc38803..b82eb5d 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -30,7 +30,7 @@ #include "qemu/qemu_monitor.h" #include "rpc/virnetsocket.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h"
diff --git a/tests/securityselinuxtest.c b/tests/securityselinuxtest.c index 045c9c0..b523c79 100644 --- a/tests/securityselinuxtest.c +++ b/tests/securityselinuxtest.c @@ -31,7 +31,7 @@ #include "internal.h" #include "testutils.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h" #include "virterror_internal.h" #include "security/security_manager.h" diff --git a/tests/testutils.c b/tests/testutils.c index c6b1d23..d88af21 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -40,7 +40,7 @@ #include "testutils.h" #include "internal.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virthread.h" #include "virterror_internal.h" #include "virbuffer.h" diff --git a/tests/utiltest.c b/tests/utiltest.c index 4fbb25c..9d18652 100644 --- a/tests/utiltest.c +++ b/tests/utiltest.c @@ -8,7 +8,7 @@ #include "internal.h" #include "viralloc.h" #include "testutils.h" -#include "util.h" +#include "virutil.h"
static void diff --git a/tests/virauthconfigtest.c b/tests/virauthconfigtest.c index 9e7dac5..2ad237d 100644 --- a/tests/virauthconfigtest.c +++ b/tests/virauthconfigtest.c @@ -24,7 +24,7 @@ #include <signal.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virbuftest.c b/tests/virbuftest.c index ec93939..7f9ee66 100644 --- a/tests/virbuftest.c +++ b/tests/virbuftest.c @@ -5,7 +5,7 @@ #include <string.h>
#include "internal.h" -#include "util.h" +#include "virutil.h" #include "testutils.h" #include "virbuffer.h" #include "viralloc.h" diff --git a/tests/virdrivermoduletest.c b/tests/virdrivermoduletest.c index e06179f..cab47d3 100644 --- a/tests/virdrivermoduletest.c +++ b/tests/virdrivermoduletest.c @@ -21,7 +21,7 @@ #include <config.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virhashtest.c b/tests/virhashtest.c index a2a40c6..6e4f267 100644 --- a/tests/virhashtest.c +++ b/tests/virhashtest.c @@ -10,7 +10,7 @@ #include "virhashdata.h" #include "testutils.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virlog.h"
diff --git a/tests/virkeyfiletest.c b/tests/virkeyfiletest.c index ad5a516..33f64c1 100644 --- a/tests/virkeyfiletest.c +++ b/tests/virkeyfiletest.c @@ -24,7 +24,7 @@ #include <signal.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c index 80478d9..c434f47 100644 --- a/tests/virlockspacetest.c +++ b/tests/virlockspacetest.c @@ -25,7 +25,7 @@ #include <sys/stat.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnetmessagetest.c b/tests/virnetmessagetest.c index e3517e8..4e7a1fd 100644 --- a/tests/virnetmessagetest.c +++ b/tests/virnetmessagetest.c @@ -24,7 +24,7 @@ #include <signal.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index 399c4fd..819257b 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -28,7 +28,7 @@ #include <netdb.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c index 27078ea..d945181 100644 --- a/tests/virnettlscontexttest.c +++ b/tests/virnettlscontexttest.c @@ -27,7 +27,7 @@ #include <gnutls/x509.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virshtest.c b/tests/virshtest.c index 72f2a1e..8741d47 100644 --- a/tests/virshtest.c +++ b/tests/virshtest.c @@ -6,7 +6,7 @@
#include "internal.h" #include "xml.h" -#include "util.h" +#include "virutil.h" #include "testutils.h"
#ifdef WIN32 diff --git a/tests/virstringtest.c b/tests/virstringtest.c index a8f4c79..58ab843 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -23,7 +23,7 @@ #include <stdlib.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virtimetest.c b/tests/virtimetest.c index 7d7a2d6..1c22d07 100644 --- a/tests/virtimetest.c +++ b/tests/virtimetest.c @@ -24,7 +24,7 @@ #include <signal.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/viruritest.c b/tests/viruritest.c index 57d3895..ad59270 100644 --- a/tests/viruritest.c +++ b/tests/viruritest.c @@ -24,7 +24,7 @@ #include <signal.h>
#include "testutils.h" -#include "util.h" +#include "virutil.h" #include "virterror_internal.h" #include "viralloc.h" #include "virlog.h" diff --git a/tools/console.c b/tools/console.c index d031308..d024d38 100644 --- a/tools/console.c +++ b/tools/console.c @@ -39,7 +39,7 @@ # include "internal.h" # include "console.h" # include "virlog.h" -# include "util.h" +# include "virutil.h" # include "virfile.h" # include "viralloc.h" # include "virthread.h" diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index b0b0c94..244ffb8 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -43,7 +43,7 @@ #include "conf/domain_conf.h" #include "console.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virkeycode.h" #include "virmacaddr.h" diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 2d59a75..0ad4296 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virsh-domain.h" #include "xml.h" #include "virtypedparam.h" diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index 40216c6..ea8a6c5 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h"
virInterfacePtr diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 66ee7e3..918dee6 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "conf/network_conf.h"
diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 7e569b3..974e495 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "conf/node_device_conf.h"
diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index c3dba0c..1480d13 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h"
virNWFilterPtr diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 6e29604..b3177e0 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -34,7 +34,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h" #include "conf/storage_conf.h"
diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index d81e8ce..a29454f 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -35,7 +35,7 @@ #include "base64.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "xml.h"
static virSecretPtr diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index 3fecde6..8428282 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -36,7 +36,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virsh-domain.h" #include "xml.h" #include "conf/snapshot_conf.h" diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index ebfe52d..6f2c591 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -36,7 +36,7 @@ #include "internal.h" #include "virbuffer.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virsh-pool.h" #include "xml.h" diff --git a/tools/virsh.c b/tools/virsh.c index 91a9677..bfeaaa1 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -58,7 +58,7 @@ #include "base64.h" #include "virbuffer.h" #include "console.h" -#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "xml.h" #include "libvirt/libvirt-qemu.h" diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-common.c index cd75eba..34a527f 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -27,7 +27,7 @@ #include <unistd.h> #include <sys/utsname.h>
-#include "util.h" +#include "virutil.h" #include "viralloc.h" #include "virfile.h" #include "virt-host-validate-common.h"

On Mon, Dec 17, 2012 at 10:22:11PM +0100, Michal Privoznik wrote:
On 17.12.2012 15:57, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 6b6ec82..a8e99f2 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -54,7 +54,7 @@
#include "virterror_internal.h" #include "virlog.h" -#include "util.h" +#include "virutil.h"
#include "lxc_conf.h" #include "lxc_container.h" @@ -64,7 +64,7 @@ #include "virnetdev.h" #include "virnetdevveth.h" #include "viralloc.h" -#include "util.h" +#include "virutil.h" #include "virfile.h" #include "virpidfile.h" #include "vircommand.h"
Why do we have this include twice? One is sufficient ....
No idea, I did a global search-replace so didn't notice these kind of issues myself. BTW, if replying to large patches like this, please trim the text you quote, to only leave context for either the file, or method you are referring to. It took me a while to find your one line comment ! Regards, Danel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

From: "Daniel P. Berrange" <berrange@redhat.com> --- daemon/libvirtd.c | 4 +- daemon/remote.c | 2 +- src/Makefile.am | 2 +- src/conf/capabilities.c | 2 +- src/conf/device_conf.c | 2 +- src/conf/domain_audit.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/interface_conf.c | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 2 +- src/conf/nwfilter_conf.c | 2 +- src/conf/secret_conf.c | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/datatypes.c | 2 +- src/esx/esx_device_monitor.c | 2 +- src/esx/esx_driver.c | 2 +- src/esx/esx_interface_driver.c | 2 +- src/esx/esx_network_driver.c | 2 +- src/esx/esx_nwfilter_driver.c | 2 +- src/esx/esx_secret_driver.c | 2 +- src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/esx/esx_storage_driver.c | 2 +- src/esx/esx_util.c | 2 +- src/esx/esx_vi.c | 2 +- src/esx/esx_vi_methods.c | 2 +- src/hyperv/hyperv_device_monitor.c | 2 +- src/hyperv/hyperv_driver.c | 2 +- src/hyperv/hyperv_interface_driver.c | 2 +- src/hyperv/hyperv_network_driver.c | 2 +- src/hyperv/hyperv_nwfilter_driver.c | 2 +- src/hyperv/hyperv_secret_driver.c | 2 +- src/hyperv/hyperv_storage_driver.c | 2 +- src/hyperv/hyperv_util.c | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/locking/domain_lock.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_nop.c | 2 +- src/locking/lock_manager.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_driver.c | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_hal.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_domain.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_process.c | 2 +- src/secret/secret_driver.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_rbd.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/uuid.c | 313 ----------------------------------- src/util/uuid.h | 41 ----- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevvportprofile.h | 2 +- src/util/viruuid.c | 313 +++++++++++++++++++++++++++++++++++ src/util/viruuid.h | 41 +++++ src/vbox/vbox_tmpl.c | 2 +- src/vmware/vmware_conf.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 2 +- src/xen/xen_driver.c | 2 +- src/xen/xen_inotify.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xm_internal.c | 2 +- src/xen/xs_internal.c | 2 +- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 2 +- src/xenxs/xen_sxpr.c | 2 +- src/xenxs/xen_xm.c | 2 +- 86 files changed, 437 insertions(+), 437 deletions(-) delete mode 100644 src/util/uuid.c delete mode 100644 src/util/uuid.h create mode 100644 src/util/viruuid.c create mode 100644 src/util/viruuid.h diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index edc899e..560746f 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -44,7 +44,7 @@ #include "libvirtd-config.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "remote_driver.h" #include "viralloc.h" #include "virconf.h" @@ -53,7 +53,7 @@ #include "remote.h" #include "remote_driver.h" #include "virhooks.h" -#include "uuid.h" +#include "viruuid.h" #include "viraudit.h" #include "locking/lock_manager.h" diff --git a/daemon/remote.c b/daemon/remote.c index 0b5a3db..1a054d5 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -37,7 +37,7 @@ #include "virlog.h" #include "virutil.h" #include "stream.h" -#include "uuid.h" +#include "viruuid.h" #include "libvirt/libvirt-qemu.h" #include "vircommand.h" #include "intprops.h" diff --git a/src/Makefile.am b/src/Makefile.am index 1303edd..dd5a1bd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/uuid.c util/uuid.h \ util/viralloc.c util/viralloc.h \ util/viratomic.h util/viratomic.c \ util/viraudit.c util/viraudit.h \ @@ -115,6 +114,7 @@ UTIL_SOURCES = \ util/virusb.c util/virusb.h \ util/viruri.h util/viruri.c \ util/virutil.c util/virutil.h \ + util/viruuid.c util/viruuid.h \ $(NULL) EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \ diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index e46a594..f6badcc 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -29,7 +29,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "cpu_conf.h" #include "virterror_internal.h" diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4efafc4..ecfaf30 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -25,7 +25,7 @@ #include "datatypes.h" #include "viralloc.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "device_conf.h" diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index c275f71..b4b2649 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -28,7 +28,7 @@ #include "domain_audit.h" #include "viraudit.h" -#include "uuid.h" +#include "viruuid.h" #include "virlog.h" #include "viralloc.h" diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index ab1fe2a..2943fe3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -37,7 +37,7 @@ #include "viralloc.h" #include "verify.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "virlog.h" diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index e4b088a..6a53bda 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 42f3593..01a6f2e 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -39,7 +39,7 @@ #include "netdev_vlan_conf.h" #include "viralloc.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "c-ctype.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 12819c8..67d743e 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -35,7 +35,7 @@ #include "xml.h" #include "virutil.h" #include "virbuffer.h" -#include "uuid.h" +#include "viruuid.h" #include "virpci.h" #include "virrandom.h" diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c index 09a9d1c..810de6c 100644 --- a/src/conf/nwfilter_conf.c +++ b/src/conf/nwfilter_conf.c @@ -38,7 +38,7 @@ #include "internal.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index a65cf92..2abb95a 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -31,7 +31,7 @@ #include "virterror_internal.h" #include "virutil.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #define VIR_FROM_THIS VIR_FROM_SECRET diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 810d2bf..3ad74d6 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -43,7 +43,7 @@ #include "snapshot_conf.h" #include "virstoragefile.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #include "virterror_internal.h" #include "xml.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 38bb471..4239e49 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -39,7 +39,7 @@ #include "virstoragefile.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 139c37c..8ea54fa 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -34,7 +34,7 @@ #include "virutil.h" #include "xml.h" #include "virterror_internal.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/datatypes.c b/src/datatypes.c index 07aefcc..038c47d 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -26,7 +26,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/esx/esx_device_monitor.c b/src/esx/esx_device_monitor.c index 7cc6ac0..f6c85ba 100644 --- a/src/esx/esx_device_monitor.c +++ b/src/esx/esx_device_monitor.c @@ -28,7 +28,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_private.h" #include "esx_device_monitor.h" #include "esx_vi.h" diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 2c0297c..4ce3a3d 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "virtypedparam.h" #include "esx_driver.h" diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 524886f..53c179b 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -28,7 +28,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "interface_conf.h" #include "virsocketaddr.h" #include "esx_private.h" diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index 0fc2603..48763d4 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "network_conf.h" #include "esx_private.h" #include "esx_network_driver.h" diff --git a/src/esx/esx_nwfilter_driver.c b/src/esx/esx_nwfilter_driver.c index ecee0fb..c59929c 100644 --- a/src/esx/esx_nwfilter_driver.c +++ b/src/esx/esx_nwfilter_driver.c @@ -28,7 +28,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_private.h" #include "esx_nwfilter_driver.h" #include "esx_vi.h" diff --git a/src/esx/esx_secret_driver.c b/src/esx/esx_secret_driver.c index 722d3f7..92cbb14 100644 --- a/src/esx/esx_secret_driver.c +++ b/src/esx/esx_secret_driver.c @@ -27,7 +27,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_private.h" #include "esx_secret_driver.h" #include "esx_vi.h" diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 3c3ab7d..e09fa55 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "storage_conf.h" #include "virstoragefile.h" #include "esx_storage_backend_iscsi.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index c57e070..f965b4f 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -34,7 +34,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "storage_conf.h" #include "virstoragefile.h" #include "esx_storage_backend_vmfs.h" diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index 1324469..5fb4e1f 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -25,7 +25,7 @@ #include <config.h> -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "storage_conf.h" #include "esx_private.h" diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index 9b2e576..4d2019b 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "esx_private.h" #include "esx_util.h" diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 2cc8002..92ac8f8 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -30,7 +30,7 @@ #include "viralloc.h" #include "virlog.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "xml.h" #include "esx_vi.h" diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c index 7ffca559..2279e62 100644 --- a/src/esx/esx_vi_methods.c +++ b/src/esx/esx_vi_methods.c @@ -26,7 +26,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_vi_methods.h" #include "esx_util.h" diff --git a/src/hyperv/hyperv_device_monitor.c b/src/hyperv/hyperv_device_monitor.c index 10d559f..43ee1fc 100644 --- a/src/hyperv/hyperv_device_monitor.c +++ b/src/hyperv/hyperv_device_monitor.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_device_monitor.h" #define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index d777bd8..601a85a 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -30,7 +30,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_driver.h" #include "hyperv_interface_driver.h" #include "hyperv_network_driver.h" diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c index af37de3..7dd6912 100644 --- a/src/hyperv/hyperv_interface_driver.c +++ b/src/hyperv/hyperv_interface_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_interface_driver.h" #define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index cafc956..f34a451 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_network_driver.h" #define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c index 46c57b7..c6125ec 100644 --- a/src/hyperv/hyperv_nwfilter_driver.c +++ b/src/hyperv/hyperv_nwfilter_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_nwfilter_driver.h" #define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c index ea8fa7e..b830e4e 100644 --- a/src/hyperv/hyperv_secret_driver.c +++ b/src/hyperv/hyperv_secret_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_secret_driver.h" #define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c index 7549801..38385a0 100644 --- a/src/hyperv/hyperv_storage_driver.c +++ b/src/hyperv/hyperv_storage_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_storage_driver.h" #define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c index 69a57c6..9bc5b81 100644 --- a/src/hyperv/hyperv_util.c +++ b/src/hyperv/hyperv_util.c @@ -27,7 +27,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_private.h" #include "hyperv_util.h" diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index f4afdce..e029028 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -30,7 +30,7 @@ #include "virlog.h" #include "viralloc.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "hyperv_private.h" #include "hyperv_wmi.h" diff --git a/src/libvirt.c b/src/libvirt.c index 5654d53..e06b643 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -50,7 +50,7 @@ #include "datatypes.h" #include "driver.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "configmake.h" #include "intprops.h" diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index eb6738c..aad1374 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -38,7 +38,7 @@ #include "virfile.h" #include "virstring.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "capabilities.h" #include "libxl_driver.h" #include "libxl_conf.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index af74ebc..76afe34 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -38,7 +38,7 @@ #include "datatypes.h" #include "virfile.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "vircommand.h" #include "libxl.h" #include "libxl_driver.h" diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c index 0ae9750..0354e26 100644 --- a/src/locking/domain_lock.c +++ b/src/locking/domain_lock.c @@ -23,7 +23,7 @@ #include "domain_lock.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virterror_internal.h" #include "virlog.h" diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index df9923e..a445b2e 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -44,7 +44,7 @@ #include "rpc/virnetserver.h" #include "virrandom.h" #include "virhash.h" -#include "uuid.h" +#include "viruuid.h" #include "locking/lock_daemon_dispatch.h" #include "locking/lock_protocol.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index 547db85..9c7ce6d 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -25,7 +25,7 @@ #include "virconf.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virfile.h" #include "virterror_internal.h" diff --git a/src/locking/lock_driver_nop.c b/src/locking/lock_driver_nop.c index cf0f49a..e8e9917 100644 --- a/src/locking/lock_driver_nop.c +++ b/src/locking/lock_driver_nop.c @@ -24,7 +24,7 @@ #include "lock_driver_nop.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" static int virLockManagerNopInit(unsigned int version ATTRIBUTE_UNUSED, diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c index d73e184..1b88838 100644 --- a/src/locking/lock_manager.c +++ b/src/locking/lock_manager.c @@ -27,7 +27,7 @@ #include "virlog.h" #include "virutil.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #if HAVE_DLFCN_H # include <dlfcn.h> diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 043630a..36c49d0 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -34,7 +34,7 @@ #include "virconf.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "configmake.h" #include "lxc_container.h" #include "virnodesuspend.h" diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 050a4c1..57c432a 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -59,7 +59,7 @@ #include "virutil.h" #include "viralloc.h" #include "virnetdevveth.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #include "vircommand.h" #include "virnetdev.h" diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e513b76..42c6f80 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -48,7 +48,7 @@ #include "virnetdevbridge.h" #include "virnetdevveth.h" #include "nodeinfo.h" -#include "uuid.h" +#include "viruuid.h" #include "virstatslinux.h" #include "virhooks.h" #include "virfile.h" diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index dbbd49c..953e571 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -55,7 +55,7 @@ #include "virutil.h" #include "vircommand.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "viriptables.h" #include "virlog.h" #include "virdnsmasq.h" diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 257a363..8ee816b 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -34,7 +34,7 @@ #include "driver.h" #include "datatypes.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virpci.h" #include "virlog.h" #include "node_device_driver.h" diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index d350955..61e5a0e 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -34,7 +34,7 @@ #include "datatypes.h" #include "virlog.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "virpci.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index b0c9c5f..35f5c97 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -46,7 +46,7 @@ #include "virterror_internal.h" #include "openvz_conf.h" #include "openvz_util.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 25b96b4..cd1911e 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -53,7 +53,7 @@ #include "driver.h" #include "libvirt/libvirt.h" #include "virterror_internal.h" -#include "uuid.h" +#include "viruuid.h" #include "domain_conf.h" #include "storage_conf.h" #include "nodeinfo.h" diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 23ccffe..79e5faa 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virutil.h" #include "virfile.h" -#include "uuid.h" +#include "viruuid.h" #include "c-ctype.h" #include "domain_nwfilter.h" #include "domain_audit.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index be88d77..8d05b4c 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -40,7 +40,7 @@ #include "qemu_command.h" #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "virconf.h" #include "virutil.h" diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3e1081a..46b7656 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "c-ctype.h" #include "cpu/cpu.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #include "domain_event.h" #include "virtime.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 15b773b..3821d74 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -68,7 +68,7 @@ #include "virstatslinux.h" #include "capabilities.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "domain_conf.h" #include "domain_audit.h" #include "node_device_conf.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 1e83e3c..afe2374 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -43,7 +43,7 @@ #include "virfile.h" #include "datatypes.h" #include "fdstream.h" -#include "uuid.h" +#include "viruuid.h" #include "virtime.h" #include "locking/domain_lock.h" #include "rpc/virnetsocket.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d4eaa9e..5ffc5a5 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -64,7 +64,7 @@ #include "domain_nwfilter.h" #include "locking/domain_lock.h" #include "network/bridge_driver.h" -#include "uuid.h" +#include "viruuid.h" #include "virprocess.h" #include "virtime.h" #include "virnetdevtap.h" diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 8dfd921..1784fea 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -38,7 +38,7 @@ #include "secret_driver.h" #include "virthread.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "virterror_internal.h" #include "virfile.h" #include "configmake.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 4027cdf..ee96bac 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -42,7 +42,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" -#include "uuid.h" +#include "viruuid.h" #include "virpci.h" #include "virusb.h" #include "virfile.h" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 5cfa3ff..3c15226 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -49,7 +49,7 @@ #include "security_apparmor.h" #include "domain_conf.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virusb.h" #include "virpci.h" #include "virfile.h" diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 29272f1..f98a7c0 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -51,7 +51,7 @@ #include "viralloc.h" #include "internal.h" #include "secret_conf.h" -#include "uuid.h" +#include "viruuid.h" #include "virstoragefile.h" #include "storage_backend.h" #include "virlog.h" diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index ffa3234..7dc46b0 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "virlog.h" #include "base64.h" -#include "uuid.h" +#include "viruuid.h" #include "rados/librados.h" #include "rbd/librbd.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index da76367..1a85eb3 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -37,7 +37,7 @@ #include "test_driver.h" #include "virbuffer.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "capabilities.h" #include "viralloc.h" #include "network_conf.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index b2057e8..bfc0600 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -36,7 +36,7 @@ #include <sys/utsname.h> #include "uml_conf.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "virconf.h" #include "virutil.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 05fb7f2..448d292 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -52,7 +52,7 @@ #include "virstatslinux.h" #include "capabilities.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "domain_conf.h" #include "domain_audit.h" #include "datatypes.h" diff --git a/src/util/uuid.c b/src/util/uuid.c deleted file mode 100644 index 57cfaa6..0000000 --- a/src/util/uuid.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2007-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 "virutil.h" -#include "virterror_internal.h" -#include "virlog.h" -#include "viralloc.h" -#include "virfile.h" -#include "virrandom.h" - -#ifndef ENODATA -# define ENODATA EIO -#endif - -static unsigned char host_uuid[VIR_UUID_BUFLEN]; - -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; - VIR_FORCE_CLOSE(fd); - return n < 0 ? errno : ENODATA; - } - - buf += n; - buflen -= n; - } - - VIR_FORCE_CLOSE(fd); - - return 0; -} - -static int -virUUIDGeneratePseudoRandomBytes(unsigned char *buf, - int buflen) -{ - while (buflen > 0) { - *buf++ = virRandomBits(8); - 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))); - err = virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN); - } - - return err; -} - -/** - * 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; - - /* - * do a liberal scan allowing '-' and ' ' anywhere between character - * pairs, and surrounding whitespace, as long as there are exactly - * 32 hexadecimal digits the end. - */ - cur = uuidstr; - while (c_isspace(*cur)) - cur++; - - 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] = virHexToBin(*cur); - uuid[i] *= 16; - cur++; - if (*cur == 0) - goto error; - if (!c_isxdigit(*cur)) - goto error; - uuid[i] += virHexToBin(*cur); - i++; - cur++; - } - - while (*cur) { - if (!c_isspace(*cur)) - goto error; - 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 a pointer to the resulting character string. - */ -const char * -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'; - return uuidstr; -} - - - -/** - * virUUIDIsValid - * - * @uuid: The UUID to test - * - * Do some basic tests to check whether the given UUID is - * valid as a host UUID. - * Basic tests: - * - Not all of the digits may be equal - */ -int -virUUIDIsValid(unsigned char *uuid) -{ - unsigned int i, ctr = 1; - unsigned char c; - - if (!uuid) - return 0; - - c = uuid[0]; - - for (i = 1; i < VIR_UUID_BUFLEN; i++) - if (uuid[i] == c) - ctr++; - - return ctr != VIR_UUID_BUFLEN; -} - -static int -getDMISystemUUID(char *uuid, int len) -{ - unsigned int i = 0; - const char *paths[] = { - "/sys/devices/virtual/dmi/id/product_uuid", - "/sys/class/dmi/id/product_uuid", - NULL - }; - - while (paths[i]) { - int fd = open(paths[i], O_RDONLY); - if (fd >= 0) { - if (saferead(fd, uuid, len - 1) == len - 1) { - uuid[len - 1] = '\0'; - VIR_FORCE_CLOSE(fd); - return 0; - } - VIR_FORCE_CLOSE(fd); - } - i++; - } - - return -1; -} - - -/** - * setHostUUID - * - * @host_uuid: UUID that the host is supposed to have - * - * Set the UUID of the host if it hasn't been set, yet - * Returns 0 in case of success, an error code in case of error. - */ -int -virSetHostUUIDStr(const char *uuid) -{ - int rc; - char dmiuuid[VIR_UUID_STRING_BUFLEN]; - - if (virUUIDIsValid(host_uuid)) - return EEXIST; - - if (!uuid) { - memset(dmiuuid, 0, sizeof(dmiuuid)); - if (!getDMISystemUUID(dmiuuid, sizeof(dmiuuid))) { - if (!virUUIDParse(dmiuuid, host_uuid)) - return 0; - } - - if (!virUUIDIsValid(host_uuid)) - return virUUIDGenerate(host_uuid); - } else { - rc = virUUIDParse(uuid, host_uuid); - if (rc) - return rc; - if (!virUUIDIsValid(host_uuid)) - return EINVAL; - } - - return 0; -} - -/** - * getHostUUID: - * - * @host_uuid: memory to store the host_uuid into - * - * Get the UUID of the host. Returns 0 in case of success, - * an error code otherwise. - * Returns 0 in case of success, an error code in case of error. - */ -int virGetHostUUID(unsigned char *uuid) -{ - int ret = 0; - - if (!virUUIDIsValid(host_uuid)) - ret = virSetHostUUIDStr(NULL); - - memcpy(uuid, host_uuid, sizeof(host_uuid)); - - return ret; -} diff --git a/src/util/uuid.h b/src/util/uuid.h deleted file mode 100644 index d90fd2e..0000000 --- a/src/util/uuid.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007, 2011, 2012 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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Mark McLoughlin <markmc@redhat.com> - */ - -#ifndef __VIR_UUID_H__ -# define __VIR_UUID_H__ - -# include "internal.h" - -int virSetHostUUIDStr(const char *host_uuid); -int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1); - -int virUUIDIsValid(unsigned char *uuid); - -int virUUIDGenerate(unsigned char *uuid); - -int virUUIDParse(const char *uuidstr, - unsigned char *uuid) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; - -const char *virUUIDFormat(const unsigned char *uuid, - char *uuidstr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -#endif /* __VIR_UUID_H__ */ diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 953d76b..720a48a 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -58,7 +58,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST, # include "viralloc.h" # include "virlog.h" -# include "uuid.h" +# include "viruuid.h" # include "virfile.h" # include "virnetlink.h" # include "virnetdev.h" diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h index cc106b8..940c0e9 100644 --- a/src/util/virnetdevvportprofile.h +++ b/src/util/virnetdevvportprofile.h @@ -24,7 +24,7 @@ # define __VIR_NETDEV_VPORT_PROFILE_H__ # include "internal.h" -# include "uuid.h" +# include "viruuid.h" # include "virutil.h" # include "virmacaddr.h" diff --git a/src/util/viruuid.c b/src/util/viruuid.c new file mode 100644 index 0000000..f4eb331 --- /dev/null +++ b/src/util/viruuid.c @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2007-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Mark McLoughlin <markmc@redhat.com> + */ + +#include <config.h> + +#include "viruuid.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 "virutil.h" +#include "virterror_internal.h" +#include "virlog.h" +#include "viralloc.h" +#include "virfile.h" +#include "virrandom.h" + +#ifndef ENODATA +# define ENODATA EIO +#endif + +static unsigned char host_uuid[VIR_UUID_BUFLEN]; + +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; + VIR_FORCE_CLOSE(fd); + return n < 0 ? errno : ENODATA; + } + + buf += n; + buflen -= n; + } + + VIR_FORCE_CLOSE(fd); + + return 0; +} + +static int +virUUIDGeneratePseudoRandomBytes(unsigned char *buf, + int buflen) +{ + while (buflen > 0) { + *buf++ = virRandomBits(8); + 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))); + err = virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN); + } + + return err; +} + +/** + * 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; + + /* + * do a liberal scan allowing '-' and ' ' anywhere between character + * pairs, and surrounding whitespace, as long as there are exactly + * 32 hexadecimal digits the end. + */ + cur = uuidstr; + while (c_isspace(*cur)) + cur++; + + 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] = virHexToBin(*cur); + uuid[i] *= 16; + cur++; + if (*cur == 0) + goto error; + if (!c_isxdigit(*cur)) + goto error; + uuid[i] += virHexToBin(*cur); + i++; + cur++; + } + + while (*cur) { + if (!c_isspace(*cur)) + goto error; + 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 a pointer to the resulting character string. + */ +const char * +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'; + return uuidstr; +} + + + +/** + * virUUIDIsValid + * + * @uuid: The UUID to test + * + * Do some basic tests to check whether the given UUID is + * valid as a host UUID. + * Basic tests: + * - Not all of the digits may be equal + */ +int +virUUIDIsValid(unsigned char *uuid) +{ + unsigned int i, ctr = 1; + unsigned char c; + + if (!uuid) + return 0; + + c = uuid[0]; + + for (i = 1; i < VIR_UUID_BUFLEN; i++) + if (uuid[i] == c) + ctr++; + + return ctr != VIR_UUID_BUFLEN; +} + +static int +getDMISystemUUID(char *uuid, int len) +{ + unsigned int i = 0; + const char *paths[] = { + "/sys/devices/virtual/dmi/id/product_uuid", + "/sys/class/dmi/id/product_uuid", + NULL + }; + + while (paths[i]) { + int fd = open(paths[i], O_RDONLY); + if (fd >= 0) { + if (saferead(fd, uuid, len - 1) == len - 1) { + uuid[len - 1] = '\0'; + VIR_FORCE_CLOSE(fd); + return 0; + } + VIR_FORCE_CLOSE(fd); + } + i++; + } + + return -1; +} + + +/** + * setHostUUID + * + * @host_uuid: UUID that the host is supposed to have + * + * Set the UUID of the host if it hasn't been set, yet + * Returns 0 in case of success, an error code in case of error. + */ +int +virSetHostUUIDStr(const char *uuid) +{ + int rc; + char dmiuuid[VIR_UUID_STRING_BUFLEN]; + + if (virUUIDIsValid(host_uuid)) + return EEXIST; + + if (!uuid) { + memset(dmiuuid, 0, sizeof(dmiuuid)); + if (!getDMISystemUUID(dmiuuid, sizeof(dmiuuid))) { + if (!virUUIDParse(dmiuuid, host_uuid)) + return 0; + } + + if (!virUUIDIsValid(host_uuid)) + return virUUIDGenerate(host_uuid); + } else { + rc = virUUIDParse(uuid, host_uuid); + if (rc) + return rc; + if (!virUUIDIsValid(host_uuid)) + return EINVAL; + } + + return 0; +} + +/** + * getHostUUID: + * + * @host_uuid: memory to store the host_uuid into + * + * Get the UUID of the host. Returns 0 in case of success, + * an error code otherwise. + * Returns 0 in case of success, an error code in case of error. + */ +int virGetHostUUID(unsigned char *uuid) +{ + int ret = 0; + + if (!virUUIDIsValid(host_uuid)) + ret = virSetHostUUIDStr(NULL); + + memcpy(uuid, host_uuid, sizeof(host_uuid)); + + return ret; +} diff --git a/src/util/viruuid.h b/src/util/viruuid.h new file mode 100644 index 0000000..d90fd2e --- /dev/null +++ b/src/util/viruuid.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007, 2011, 2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Mark McLoughlin <markmc@redhat.com> + */ + +#ifndef __VIR_UUID_H__ +# define __VIR_UUID_H__ + +# include "internal.h" + +int virSetHostUUIDStr(const char *host_uuid); +int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1); + +int virUUIDIsValid(unsigned char *uuid); + +int virUUIDGenerate(unsigned char *uuid); + +int virUUIDParse(const char *uuidstr, + unsigned char *uuid) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +const char *virUUIDFormat(const unsigned char *uuid, + char *uuidstr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +#endif /* __VIR_UUID_H__ */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 923ff04..5cac7bb 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -49,7 +49,7 @@ #include "domain_event.h" #include "storage_conf.h" #include "virstoragefile.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "nodeinfo.h" #include "virlog.h" diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c index 7cf9bcc..22a085d 100644 --- a/src/vmware/vmware_conf.c +++ b/src/vmware/vmware_conf.c @@ -30,7 +30,7 @@ #include "viralloc.h" #include "nodeinfo.h" #include "virfile.h" -#include "uuid.h" +#include "viruuid.h" #include "virterror_internal.h" #include "vmx.h" diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 12195bf..67cdc88 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -29,7 +29,7 @@ #include "virfile.h" #include "viralloc.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "vircommand.h" #include "vmx.h" #include "vmware_conf.h" diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 90496ce..d57a14f 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -30,7 +30,7 @@ #include "virconf.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "viruri.h" diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 2b8496c..4cbe827 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -58,7 +58,7 @@ #include "viralloc.h" #include "node_device_conf.h" #include "virpci.h" -#include "uuid.h" +#include "viruuid.h" #include "fdstream.h" #include "virfile.h" #include "viruri.h" diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 35a625c..4cce25a 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -37,7 +37,7 @@ #include "xen_inotify.h" #include "xend_internal.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #include "xm_internal.h" /* for xenXMDomainConfigParse */ diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 7ffc5bb..120e237 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -38,7 +38,7 @@ #include "virsexpr.h" #include "xen_sxpr.h" #include "virbuffer.h" -#include "uuid.h" +#include "viruuid.h" #include "xen_driver.h" #include "xen_hypervisor.h" #include "xs_internal.h" /* To extract VNC port & Serial console TTY */ diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index e3206eb..0806e77 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -44,7 +44,7 @@ #include "xen_xm.h" #include "virhash.h" #include "virbuffer.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index e414966..20332df 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -46,7 +46,7 @@ #include "driver.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "xen_driver.h" #include "xs_internal.h" #include "xen_hypervisor.h" diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 04b24ab..df5625e 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -32,7 +32,7 @@ #include "datatypes.h" #include "virauth.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "virbuffer.h" #include "viruri.h" diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 15be403..5c53b69 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "virbuffer.h" #include "virlog.h" diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index b28c538..b83ac58 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -31,7 +31,7 @@ #include "virconf.h" #include "viralloc.h" #include "verify.h" -#include "uuid.h" +#include "viruuid.h" #include "virlog.h" #include "count-one-bits.h" #include "xenxs_private.h" diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index 007036b..bbf35d8 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -30,7 +30,7 @@ #include "virconf.h" #include "viralloc.h" #include "verify.h" -#include "uuid.h" +#include "viruuid.h" #include "virsexpr.h" #include "count-one-bits.h" #include "xenxs_private.h" -- 1.7.11.7

On 17.12.2012 15:57, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
--- daemon/libvirtd.c | 4 +- daemon/remote.c | 2 +- src/Makefile.am | 2 +- src/conf/capabilities.c | 2 +- src/conf/device_conf.c | 2 +- src/conf/domain_audit.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/interface_conf.c | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 2 +- src/conf/nwfilter_conf.c | 2 +- src/conf/secret_conf.c | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/datatypes.c | 2 +- src/esx/esx_device_monitor.c | 2 +- src/esx/esx_driver.c | 2 +- src/esx/esx_interface_driver.c | 2 +- src/esx/esx_network_driver.c | 2 +- src/esx/esx_nwfilter_driver.c | 2 +- src/esx/esx_secret_driver.c | 2 +- src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/esx/esx_storage_driver.c | 2 +- src/esx/esx_util.c | 2 +- src/esx/esx_vi.c | 2 +- src/esx/esx_vi_methods.c | 2 +- src/hyperv/hyperv_device_monitor.c | 2 +- src/hyperv/hyperv_driver.c | 2 +- src/hyperv/hyperv_interface_driver.c | 2 +- src/hyperv/hyperv_network_driver.c | 2 +- src/hyperv/hyperv_nwfilter_driver.c | 2 +- src/hyperv/hyperv_secret_driver.c | 2 +- src/hyperv/hyperv_storage_driver.c | 2 +- src/hyperv/hyperv_util.c | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/locking/domain_lock.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_nop.c | 2 +- src/locking/lock_manager.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_driver.c | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_hal.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_domain.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_process.c | 2 +- src/secret/secret_driver.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_rbd.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.c | 2 +- src/uml/uml_driver.c | 2 +- src/util/uuid.c | 313 ----------------------------------- src/util/uuid.h | 41 ----- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevvportprofile.h | 2 +- src/util/viruuid.c | 313 +++++++++++++++++++++++++++++++++++ src/util/viruuid.h | 41 +++++ src/vbox/vbox_tmpl.c | 2 +- src/vmware/vmware_conf.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 2 +- src/xen/xen_driver.c | 2 +- src/xen/xen_inotify.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xm_internal.c | 2 +- src/xen/xs_internal.c | 2 +- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_utils.c | 2 +- src/xenxs/xen_sxpr.c | 2 +- src/xenxs/xen_xm.c | 2 +- 86 files changed, 437 insertions(+), 437 deletions(-) delete mode 100644 src/util/uuid.c delete mode 100644 src/util/uuid.h create mode 100644 src/util/viruuid.c create mode 100644 src/util/viruuid.h
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index edc899e..560746f 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -44,7 +44,7 @@ #include "libvirtd-config.h"
#include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "remote_driver.h" #include "viralloc.h" #include "virconf.h" @@ -53,7 +53,7 @@ #include "remote.h" #include "remote_driver.h" #include "virhooks.h" -#include "uuid.h" +#include "viruuid.h" #include "viraudit.h" #include "locking/lock_manager.h"
Same comment from previous patch applies here as well ....
diff --git a/daemon/remote.c b/daemon/remote.c index 0b5a3db..1a054d5 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -37,7 +37,7 @@ #include "virlog.h" #include "virutil.h" #include "stream.h" -#include "uuid.h" +#include "viruuid.h" #include "libvirt/libvirt-qemu.h" #include "vircommand.h" #include "intprops.h" diff --git a/src/Makefile.am b/src/Makefile.am index 1303edd..dd5a1bd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/uuid.c util/uuid.h \ util/viralloc.c util/viralloc.h \ util/viratomic.h util/viratomic.c \ util/viraudit.c util/viraudit.h \ @@ -115,6 +114,7 @@ UTIL_SOURCES = \ util/virusb.c util/virusb.h \ util/viruri.h util/viruri.c \ util/virutil.c util/virutil.h \ + util/viruuid.c util/viruuid.h \ $(NULL)
EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \ diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index e46a594..f6badcc 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -29,7 +29,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "cpu_conf.h" #include "virterror_internal.h"
diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 4efafc4..ecfaf30 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -25,7 +25,7 @@ #include "datatypes.h" #include "viralloc.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "device_conf.h" diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c index c275f71..b4b2649 100644 --- a/src/conf/domain_audit.c +++ b/src/conf/domain_audit.c @@ -28,7 +28,7 @@
#include "domain_audit.h" #include "viraudit.h" -#include "uuid.h" +#include "viruuid.h" #include "virlog.h" #include "viralloc.h"
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index ab1fe2a..2943fe3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -37,7 +37,7 @@ #include "viralloc.h" #include "verify.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "virlog.h" diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index e4b088a..6a53bda 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -29,7 +29,7 @@
#include "viralloc.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h"
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 42f3593..01a6f2e 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -39,7 +39,7 @@ #include "netdev_vlan_conf.h" #include "viralloc.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "c-ctype.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 12819c8..67d743e 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -35,7 +35,7 @@ #include "xml.h" #include "virutil.h" #include "virbuffer.h" -#include "uuid.h" +#include "viruuid.h" #include "virpci.h" #include "virrandom.h"
diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c index 09a9d1c..810de6c 100644 --- a/src/conf/nwfilter_conf.c +++ b/src/conf/nwfilter_conf.c @@ -38,7 +38,7 @@
#include "internal.h"
-#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index a65cf92..2abb95a 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -31,7 +31,7 @@ #include "virterror_internal.h" #include "virutil.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h"
#define VIR_FROM_THIS VIR_FROM_SECRET
diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 810d2bf..3ad74d6 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -43,7 +43,7 @@ #include "snapshot_conf.h" #include "virstoragefile.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #include "virterror_internal.h" #include "xml.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 38bb471..4239e49 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -39,7 +39,7 @@ #include "virstoragefile.h"
#include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 139c37c..8ea54fa 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -34,7 +34,7 @@ #include "virutil.h" #include "xml.h" #include "virterror_internal.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/datatypes.c b/src/datatypes.c index 07aefcc..038c47d 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -26,7 +26,7 @@ #include "virterror_internal.h" #include "virlog.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h"
#define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/esx/esx_device_monitor.c b/src/esx/esx_device_monitor.c index 7cc6ac0..f6c85ba 100644 --- a/src/esx/esx_device_monitor.c +++ b/src/esx/esx_device_monitor.c @@ -28,7 +28,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_private.h" #include "esx_device_monitor.h" #include "esx_vi.h" diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c index 2c0297c..4ce3a3d 100644 --- a/src/esx/esx_driver.c +++ b/src/esx/esx_driver.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "virtypedparam.h" #include "esx_driver.h" diff --git a/src/esx/esx_interface_driver.c b/src/esx/esx_interface_driver.c index 524886f..53c179b 100644 --- a/src/esx/esx_interface_driver.c +++ b/src/esx/esx_interface_driver.c @@ -28,7 +28,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "interface_conf.h" #include "virsocketaddr.h" #include "esx_private.h" diff --git a/src/esx/esx_network_driver.c b/src/esx/esx_network_driver.c index 0fc2603..48763d4 100644 --- a/src/esx/esx_network_driver.c +++ b/src/esx/esx_network_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "network_conf.h" #include "esx_private.h" #include "esx_network_driver.h" diff --git a/src/esx/esx_nwfilter_driver.c b/src/esx/esx_nwfilter_driver.c index ecee0fb..c59929c 100644 --- a/src/esx/esx_nwfilter_driver.c +++ b/src/esx/esx_nwfilter_driver.c @@ -28,7 +28,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_private.h" #include "esx_nwfilter_driver.h" #include "esx_vi.h" diff --git a/src/esx/esx_secret_driver.c b/src/esx/esx_secret_driver.c index 722d3f7..92cbb14 100644 --- a/src/esx/esx_secret_driver.c +++ b/src/esx/esx_secret_driver.c @@ -27,7 +27,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_private.h" #include "esx_secret_driver.h" #include "esx_vi.h" diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index 3c3ab7d..e09fa55 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "storage_conf.h" #include "virstoragefile.h" #include "esx_storage_backend_iscsi.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index c57e070..f965b4f 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -34,7 +34,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "storage_conf.h" #include "virstoragefile.h" #include "esx_storage_backend_vmfs.h" diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index 1324469..5fb4e1f 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -25,7 +25,7 @@
#include <config.h>
-#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "storage_conf.h" #include "esx_private.h" diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c index 9b2e576..4d2019b 100644 --- a/src/esx/esx_util.c +++ b/src/esx/esx_util.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "esx_private.h" #include "esx_util.h" diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 2cc8002..92ac8f8 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -30,7 +30,7 @@ #include "viralloc.h" #include "virlog.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "xml.h" #include "esx_vi.h" diff --git a/src/esx/esx_vi_methods.c b/src/esx/esx_vi_methods.c index 7ffca559..2279e62 100644 --- a/src/esx/esx_vi_methods.c +++ b/src/esx/esx_vi_methods.c @@ -26,7 +26,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "esx_vi_methods.h" #include "esx_util.h"
diff --git a/src/hyperv/hyperv_device_monitor.c b/src/hyperv/hyperv_device_monitor.c index 10d559f..43ee1fc 100644 --- a/src/hyperv/hyperv_device_monitor.c +++ b/src/hyperv/hyperv_device_monitor.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_device_monitor.h"
#define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index d777bd8..601a85a 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -30,7 +30,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_driver.h" #include "hyperv_interface_driver.h" #include "hyperv_network_driver.h" diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c index af37de3..7dd6912 100644 --- a/src/hyperv/hyperv_interface_driver.c +++ b/src/hyperv/hyperv_interface_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_interface_driver.h"
#define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index cafc956..f34a451 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_network_driver.h"
#define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c index 46c57b7..c6125ec 100644 --- a/src/hyperv/hyperv_nwfilter_driver.c +++ b/src/hyperv/hyperv_nwfilter_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_nwfilter_driver.h"
#define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c index ea8fa7e..b830e4e 100644 --- a/src/hyperv/hyperv_secret_driver.c +++ b/src/hyperv/hyperv_secret_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_secret_driver.h"
#define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c index 7549801..38385a0 100644 --- a/src/hyperv/hyperv_storage_driver.c +++ b/src/hyperv/hyperv_storage_driver.c @@ -29,7 +29,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_storage_driver.h"
#define VIR_FROM_THIS VIR_FROM_HYPERV diff --git a/src/hyperv/hyperv_util.c b/src/hyperv/hyperv_util.c index 69a57c6..9bc5b81 100644 --- a/src/hyperv/hyperv_util.c +++ b/src/hyperv/hyperv_util.c @@ -27,7 +27,7 @@ #include "virutil.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "hyperv_private.h" #include "hyperv_util.h"
diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index f4afdce..e029028 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -30,7 +30,7 @@ #include "virlog.h" #include "viralloc.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "hyperv_private.h" #include "hyperv_wmi.h" diff --git a/src/libvirt.c b/src/libvirt.c index 5654d53..e06b643 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -50,7 +50,7 @@ #include "datatypes.h" #include "driver.h"
-#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "configmake.h" #include "intprops.h" diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index eb6738c..aad1374 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -38,7 +38,7 @@ #include "virfile.h" #include "virstring.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "capabilities.h" #include "libxl_driver.h" #include "libxl_conf.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index af74ebc..76afe34 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -38,7 +38,7 @@ #include "datatypes.h" #include "virfile.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "vircommand.h" #include "libxl.h" #include "libxl_driver.h" diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c index 0ae9750..0354e26 100644 --- a/src/locking/domain_lock.c +++ b/src/locking/domain_lock.c @@ -23,7 +23,7 @@
#include "domain_lock.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virterror_internal.h" #include "virlog.h"
diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index df9923e..a445b2e 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -44,7 +44,7 @@ #include "rpc/virnetserver.h" #include "virrandom.h" #include "virhash.h" -#include "uuid.h" +#include "viruuid.h"
#include "locking/lock_daemon_dispatch.h" #include "locking/lock_protocol.h" diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index 547db85..9c7ce6d 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -25,7 +25,7 @@ #include "virconf.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virfile.h" #include "virterror_internal.h" diff --git a/src/locking/lock_driver_nop.c b/src/locking/lock_driver_nop.c index cf0f49a..e8e9917 100644 --- a/src/locking/lock_driver_nop.c +++ b/src/locking/lock_driver_nop.c @@ -24,7 +24,7 @@ #include "lock_driver_nop.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h"
static int virLockManagerNopInit(unsigned int version ATTRIBUTE_UNUSED, diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c index d73e184..1b88838 100644 --- a/src/locking/lock_manager.c +++ b/src/locking/lock_manager.c @@ -27,7 +27,7 @@ #include "virlog.h" #include "virutil.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h"
#if HAVE_DLFCN_H # include <dlfcn.h> diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 043630a..36c49d0 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -34,7 +34,7 @@ #include "virconf.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "configmake.h" #include "lxc_container.h" #include "virnodesuspend.h" diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 050a4c1..57c432a 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -59,7 +59,7 @@ #include "virutil.h" #include "viralloc.h" #include "virnetdevveth.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #include "vircommand.h" #include "virnetdev.h" diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index e513b76..42c6f80 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -48,7 +48,7 @@ #include "virnetdevbridge.h" #include "virnetdevveth.h" #include "nodeinfo.h" -#include "uuid.h" +#include "viruuid.h" #include "virstatslinux.h" #include "virhooks.h" #include "virfile.h" diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index dbbd49c..953e571 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -55,7 +55,7 @@ #include "virutil.h" #include "vircommand.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "viriptables.h" #include "virlog.h" #include "virdnsmasq.h" diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 257a363..8ee816b 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -34,7 +34,7 @@ #include "driver.h" #include "datatypes.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virpci.h" #include "virlog.h" #include "node_device_driver.h" diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index d350955..61e5a0e 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -34,7 +34,7 @@ #include "datatypes.h" #include "virlog.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "virbuffer.h" #include "virpci.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index b0c9c5f..35f5c97 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -46,7 +46,7 @@ #include "virterror_internal.h" #include "openvz_conf.h" #include "openvz_util.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 25b96b4..cd1911e 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -53,7 +53,7 @@ #include "driver.h" #include "libvirt/libvirt.h" #include "virterror_internal.h" -#include "uuid.h" +#include "viruuid.h" #include "domain_conf.h" #include "storage_conf.h" #include "nodeinfo.h" diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 23ccffe..79e5faa 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -33,7 +33,7 @@ #include "virterror_internal.h" #include "virutil.h" #include "virfile.h" -#include "uuid.h" +#include "viruuid.h" #include "c-ctype.h" #include "domain_nwfilter.h" #include "domain_audit.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index be88d77..8d05b4c 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -40,7 +40,7 @@ #include "qemu_command.h" #include "qemu_capabilities.h" #include "qemu_bridge_filter.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "virconf.h" #include "virutil.h" diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 3e1081a..46b7656 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -32,7 +32,7 @@ #include "virterror_internal.h" #include "c-ctype.h" #include "cpu/cpu.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h" #include "domain_event.h" #include "virtime.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 15b773b..3821d74 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -68,7 +68,7 @@ #include "virstatslinux.h" #include "capabilities.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "domain_conf.h" #include "domain_audit.h" #include "node_device_conf.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 1e83e3c..afe2374 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -43,7 +43,7 @@ #include "virfile.h" #include "datatypes.h" #include "fdstream.h" -#include "uuid.h" +#include "viruuid.h" #include "virtime.h" #include "locking/domain_lock.h" #include "rpc/virnetsocket.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d4eaa9e..5ffc5a5 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -64,7 +64,7 @@ #include "domain_nwfilter.h" #include "locking/domain_lock.h" #include "network/bridge_driver.h" -#include "uuid.h" +#include "viruuid.h" #include "virprocess.h" #include "virtime.h" #include "virnetdevtap.h" diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 8dfd921..1784fea 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -38,7 +38,7 @@ #include "secret_driver.h" #include "virthread.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "virterror_internal.h" #include "virfile.h" #include "configmake.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 4027cdf..ee96bac 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -42,7 +42,7 @@ #include "viralloc.h" #include "virterror_internal.h" #include "datatypes.h" -#include "uuid.h" +#include "viruuid.h" #include "virpci.h" #include "virusb.h" #include "virfile.h" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 5cfa3ff..3c15226 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -49,7 +49,7 @@ #include "security_apparmor.h" #include "domain_conf.h" #include "xml.h" -#include "uuid.h" +#include "viruuid.h" #include "virusb.h" #include "virpci.h" #include "virfile.h" diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 29272f1..f98a7c0 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -51,7 +51,7 @@ #include "viralloc.h" #include "internal.h" #include "secret_conf.h" -#include "uuid.h" +#include "viruuid.h" #include "virstoragefile.h" #include "storage_backend.h" #include "virlog.h" diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index ffa3234..7dc46b0 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "virlog.h" #include "base64.h" -#include "uuid.h" +#include "viruuid.h" #include "rados/librados.h" #include "rbd/librbd.h"
diff --git a/src/test/test_driver.c b/src/test/test_driver.c index da76367..1a85eb3 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -37,7 +37,7 @@ #include "test_driver.h" #include "virbuffer.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "capabilities.h" #include "viralloc.h" #include "network_conf.h" diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index b2057e8..bfc0600 100644 --- a/src/uml/uml_conf.c +++ b/src/uml/uml_conf.c @@ -36,7 +36,7 @@ #include <sys/utsname.h>
#include "uml_conf.h" -#include "uuid.h" +#include "viruuid.h" #include "virbuffer.h" #include "virconf.h" #include "virutil.h" diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 05fb7f2..448d292 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -52,7 +52,7 @@ #include "virstatslinux.h" #include "capabilities.h" #include "viralloc.h" -#include "uuid.h" +#include "viruuid.h" #include "domain_conf.h" #include "domain_audit.h" #include "datatypes.h" diff --git a/src/util/uuid.c b/src/util/uuid.c deleted file mode 100644 index 57cfaa6..0000000 --- a/src/util/uuid.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2007-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 "virutil.h" -#include "virterror_internal.h" -#include "virlog.h" -#include "viralloc.h" -#include "virfile.h" -#include "virrandom.h" - -#ifndef ENODATA -# define ENODATA EIO -#endif - -static unsigned char host_uuid[VIR_UUID_BUFLEN]; - -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; - VIR_FORCE_CLOSE(fd); - return n < 0 ? errno : ENODATA; - } - - buf += n; - buflen -= n; - } - - VIR_FORCE_CLOSE(fd); - - return 0; -} - -static int -virUUIDGeneratePseudoRandomBytes(unsigned char *buf, - int buflen) -{ - while (buflen > 0) { - *buf++ = virRandomBits(8); - 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))); - err = virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN); - } - - return err; -} - -/** - * 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; - - /* - * do a liberal scan allowing '-' and ' ' anywhere between character - * pairs, and surrounding whitespace, as long as there are exactly - * 32 hexadecimal digits the end. - */ - cur = uuidstr; - while (c_isspace(*cur)) - cur++; - - 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] = virHexToBin(*cur); - uuid[i] *= 16; - cur++; - if (*cur == 0) - goto error; - if (!c_isxdigit(*cur)) - goto error; - uuid[i] += virHexToBin(*cur); - i++; - cur++; - } - - while (*cur) { - if (!c_isspace(*cur)) - goto error; - 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 a pointer to the resulting character string. - */ -const char * -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'; - return uuidstr; -} - - - -/** - * virUUIDIsValid - * - * @uuid: The UUID to test - * - * Do some basic tests to check whether the given UUID is - * valid as a host UUID. - * Basic tests: - * - Not all of the digits may be equal - */ -int -virUUIDIsValid(unsigned char *uuid) -{ - unsigned int i, ctr = 1; - unsigned char c; - - if (!uuid) - return 0; - - c = uuid[0]; - - for (i = 1; i < VIR_UUID_BUFLEN; i++) - if (uuid[i] == c) - ctr++; - - return ctr != VIR_UUID_BUFLEN; -} - -static int -getDMISystemUUID(char *uuid, int len) -{ - unsigned int i = 0; - const char *paths[] = { - "/sys/devices/virtual/dmi/id/product_uuid", - "/sys/class/dmi/id/product_uuid", - NULL - }; - - while (paths[i]) { - int fd = open(paths[i], O_RDONLY); - if (fd >= 0) { - if (saferead(fd, uuid, len - 1) == len - 1) { - uuid[len - 1] = '\0'; - VIR_FORCE_CLOSE(fd); - return 0; - } - VIR_FORCE_CLOSE(fd); - } - i++; - } - - return -1; -} - - -/** - * setHostUUID - * - * @host_uuid: UUID that the host is supposed to have - * - * Set the UUID of the host if it hasn't been set, yet - * Returns 0 in case of success, an error code in case of error. - */ -int -virSetHostUUIDStr(const char *uuid) -{ - int rc; - char dmiuuid[VIR_UUID_STRING_BUFLEN]; - - if (virUUIDIsValid(host_uuid)) - return EEXIST; - - if (!uuid) { - memset(dmiuuid, 0, sizeof(dmiuuid)); - if (!getDMISystemUUID(dmiuuid, sizeof(dmiuuid))) { - if (!virUUIDParse(dmiuuid, host_uuid)) - return 0; - } - - if (!virUUIDIsValid(host_uuid)) - return virUUIDGenerate(host_uuid); - } else { - rc = virUUIDParse(uuid, host_uuid); - if (rc) - return rc; - if (!virUUIDIsValid(host_uuid)) - return EINVAL; - } - - return 0; -} - -/** - * getHostUUID: - * - * @host_uuid: memory to store the host_uuid into - * - * Get the UUID of the host. Returns 0 in case of success, - * an error code otherwise. - * Returns 0 in case of success, an error code in case of error. - */ -int virGetHostUUID(unsigned char *uuid) -{ - int ret = 0; - - if (!virUUIDIsValid(host_uuid)) - ret = virSetHostUUIDStr(NULL); - - memcpy(uuid, host_uuid, sizeof(host_uuid)); - - return ret; -} diff --git a/src/util/uuid.h b/src/util/uuid.h deleted file mode 100644 index d90fd2e..0000000 --- a/src/util/uuid.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007, 2011, 2012 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, see - * <http://www.gnu.org/licenses/>. - * - * Authors: - * Mark McLoughlin <markmc@redhat.com> - */ - -#ifndef __VIR_UUID_H__ -# define __VIR_UUID_H__ - -# include "internal.h" - -int virSetHostUUIDStr(const char *host_uuid); -int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1); - -int virUUIDIsValid(unsigned char *uuid); - -int virUUIDGenerate(unsigned char *uuid); - -int virUUIDParse(const char *uuidstr, - unsigned char *uuid) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; - -const char *virUUIDFormat(const unsigned char *uuid, - char *uuidstr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -#endif /* __VIR_UUID_H__ */ diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 953d76b..720a48a 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -58,7 +58,7 @@ VIR_ENUM_IMPL(virNetDevMacVLanMode, VIR_NETDEV_MACVLAN_MODE_LAST,
# include "viralloc.h" # include "virlog.h" -# include "uuid.h" +# include "viruuid.h" # include "virfile.h" # include "virnetlink.h" # include "virnetdev.h" diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h index cc106b8..940c0e9 100644 --- a/src/util/virnetdevvportprofile.h +++ b/src/util/virnetdevvportprofile.h @@ -24,7 +24,7 @@ # define __VIR_NETDEV_VPORT_PROFILE_H__
# include "internal.h" -# include "uuid.h" +# include "viruuid.h" # include "virutil.h" # include "virmacaddr.h"
diff --git a/src/util/viruuid.c b/src/util/viruuid.c new file mode 100644 index 0000000..f4eb331 --- /dev/null +++ b/src/util/viruuid.c @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2007-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Mark McLoughlin <markmc@redhat.com> + */ + +#include <config.h> + +#include "viruuid.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 "virutil.h" +#include "virterror_internal.h" +#include "virlog.h" +#include "viralloc.h" +#include "virfile.h" +#include "virrandom.h" + +#ifndef ENODATA +# define ENODATA EIO +#endif + +static unsigned char host_uuid[VIR_UUID_BUFLEN]; + +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; + VIR_FORCE_CLOSE(fd); + return n < 0 ? errno : ENODATA; + } + + buf += n; + buflen -= n; + } + + VIR_FORCE_CLOSE(fd); + + return 0; +} + +static int +virUUIDGeneratePseudoRandomBytes(unsigned char *buf, + int buflen) +{ + while (buflen > 0) { + *buf++ = virRandomBits(8); + 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))); + err = virUUIDGeneratePseudoRandomBytes(uuid, VIR_UUID_BUFLEN); + } + + return err; +} + +/** + * 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; + + /* + * do a liberal scan allowing '-' and ' ' anywhere between character + * pairs, and surrounding whitespace, as long as there are exactly + * 32 hexadecimal digits the end. + */ + cur = uuidstr; + while (c_isspace(*cur)) + cur++; + + 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] = virHexToBin(*cur); + uuid[i] *= 16; + cur++; + if (*cur == 0) + goto error; + if (!c_isxdigit(*cur)) + goto error; + uuid[i] += virHexToBin(*cur); + i++; + cur++; + } + + while (*cur) { + if (!c_isspace(*cur)) + goto error; + 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 a pointer to the resulting character string. + */ +const char * +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'; + return uuidstr; +} + + + +/** + * virUUIDIsValid + * + * @uuid: The UUID to test + * + * Do some basic tests to check whether the given UUID is + * valid as a host UUID. + * Basic tests: + * - Not all of the digits may be equal + */ +int +virUUIDIsValid(unsigned char *uuid) +{ + unsigned int i, ctr = 1; + unsigned char c; + + if (!uuid) + return 0; + + c = uuid[0]; + + for (i = 1; i < VIR_UUID_BUFLEN; i++) + if (uuid[i] == c) + ctr++; + + return ctr != VIR_UUID_BUFLEN; +} + +static int +getDMISystemUUID(char *uuid, int len) +{ + unsigned int i = 0; + const char *paths[] = { + "/sys/devices/virtual/dmi/id/product_uuid", + "/sys/class/dmi/id/product_uuid", + NULL + }; + + while (paths[i]) { + int fd = open(paths[i], O_RDONLY); + if (fd >= 0) { + if (saferead(fd, uuid, len - 1) == len - 1) { + uuid[len - 1] = '\0'; + VIR_FORCE_CLOSE(fd); + return 0; + } + VIR_FORCE_CLOSE(fd); + } + i++; + } + + return -1; +} + + +/** + * setHostUUID + * + * @host_uuid: UUID that the host is supposed to have + * + * Set the UUID of the host if it hasn't been set, yet + * Returns 0 in case of success, an error code in case of error. + */ +int +virSetHostUUIDStr(const char *uuid) +{ + int rc; + char dmiuuid[VIR_UUID_STRING_BUFLEN]; + + if (virUUIDIsValid(host_uuid)) + return EEXIST; + + if (!uuid) { + memset(dmiuuid, 0, sizeof(dmiuuid)); + if (!getDMISystemUUID(dmiuuid, sizeof(dmiuuid))) { + if (!virUUIDParse(dmiuuid, host_uuid)) + return 0; + } + + if (!virUUIDIsValid(host_uuid)) + return virUUIDGenerate(host_uuid); + } else { + rc = virUUIDParse(uuid, host_uuid); + if (rc) + return rc; + if (!virUUIDIsValid(host_uuid)) + return EINVAL; + } + + return 0; +} + +/** + * getHostUUID: + * + * @host_uuid: memory to store the host_uuid into + * + * Get the UUID of the host. Returns 0 in case of success, + * an error code otherwise. + * Returns 0 in case of success, an error code in case of error. + */ +int virGetHostUUID(unsigned char *uuid) +{ + int ret = 0; + + if (!virUUIDIsValid(host_uuid)) + ret = virSetHostUUIDStr(NULL); + + memcpy(uuid, host_uuid, sizeof(host_uuid)); + + return ret; +} diff --git a/src/util/viruuid.h b/src/util/viruuid.h new file mode 100644 index 0000000..d90fd2e --- /dev/null +++ b/src/util/viruuid.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007, 2011, 2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * Mark McLoughlin <markmc@redhat.com> + */ + +#ifndef __VIR_UUID_H__ +# define __VIR_UUID_H__ + +# include "internal.h" + +int virSetHostUUIDStr(const char *host_uuid); +int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1); + +int virUUIDIsValid(unsigned char *uuid); + +int virUUIDGenerate(unsigned char *uuid); + +int virUUIDParse(const char *uuidstr, + unsigned char *uuid) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +const char *virUUIDFormat(const unsigned char *uuid, + char *uuidstr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +#endif /* __VIR_UUID_H__ */ diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 923ff04..5cac7bb 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -49,7 +49,7 @@ #include "domain_event.h" #include "storage_conf.h" #include "virstoragefile.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "nodeinfo.h" #include "virlog.h" diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c index 7cf9bcc..22a085d 100644 --- a/src/vmware/vmware_conf.c +++ b/src/vmware/vmware_conf.c @@ -30,7 +30,7 @@ #include "viralloc.h" #include "nodeinfo.h" #include "virfile.h" -#include "uuid.h" +#include "viruuid.h" #include "virterror_internal.h" #include "vmx.h"
diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 12195bf..67cdc88 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -29,7 +29,7 @@ #include "virfile.h" #include "viralloc.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "vircommand.h" #include "vmx.h" #include "vmware_conf.h" diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 90496ce..d57a14f 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -30,7 +30,7 @@ #include "virconf.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "vmx.h" #include "viruri.h"
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 2b8496c..4cbe827 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -58,7 +58,7 @@ #include "viralloc.h" #include "node_device_conf.h" #include "virpci.h" -#include "uuid.h" +#include "viruuid.h" #include "fdstream.h" #include "virfile.h" #include "viruri.h" diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 35a625c..4cce25a 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -37,7 +37,7 @@ #include "xen_inotify.h" #include "xend_internal.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "virfile.h"
#include "xm_internal.h" /* for xenXMDomainConfigParse */ diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 7ffc5bb..120e237 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -38,7 +38,7 @@ #include "virsexpr.h" #include "xen_sxpr.h" #include "virbuffer.h" -#include "uuid.h" +#include "viruuid.h" #include "xen_driver.h" #include "xen_hypervisor.h" #include "xs_internal.h" /* To extract VNC port & Serial console TTY */ diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index e3206eb..0806e77 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -44,7 +44,7 @@ #include "xen_xm.h" #include "virhash.h" #include "virbuffer.h" -#include "uuid.h" +#include "viruuid.h" #include "virutil.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index e414966..20332df 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -46,7 +46,7 @@ #include "driver.h" #include "viralloc.h" #include "virlog.h" -#include "uuid.h" +#include "viruuid.h" #include "xen_driver.h" #include "xs_internal.h" #include "xen_hypervisor.h" diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 04b24ab..df5625e 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -32,7 +32,7 @@ #include "datatypes.h" #include "virauth.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "virbuffer.h" #include "viruri.h" diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 15be403..5c53b69 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -30,7 +30,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "viralloc.h" #include "virbuffer.h" #include "virlog.h" diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index b28c538..b83ac58 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -31,7 +31,7 @@ #include "virconf.h" #include "viralloc.h" #include "verify.h" -#include "uuid.h" +#include "viruuid.h" #include "virlog.h" #include "count-one-bits.h" #include "xenxs_private.h" diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index 007036b..bbf35d8 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -30,7 +30,7 @@ #include "virconf.h" #include "viralloc.h" #include "verify.h" -#include "uuid.h" +#include "viruuid.h" #include "virsexpr.h" #include "count-one-bits.h" #include "xenxs_private.h"

On Mon, Dec 17, 2012 at 10:22:03PM +0100, Michal Privoznik wrote:
On 17.12.2012 15:57, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index edc899e..560746f 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -44,7 +44,7 @@ #include "libvirtd-config.h"
#include "virutil.h" -#include "uuid.h" +#include "viruuid.h" #include "remote_driver.h" #include "viralloc.h" #include "virconf.h" @@ -53,7 +53,7 @@ #include "remote.h" #include "remote_driver.h" #include "virhooks.h" -#include "uuid.h" +#include "viruuid.h" #include "viraudit.h" #include "locking/lock_manager.h"
Same comment from previous patch applies here as well ....
Yep, will kill the dup. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

From: "Daniel P. Berrange" <berrange@redhat.com> --- cfg.mk | 2 +- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/conf/cpu_conf.h | 2 +- src/conf/device_conf.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/interface_conf.c | 2 +- src/conf/netdev_bandwidth_conf.h | 2 +- src/conf/netdev_vlan_conf.h | 2 +- src/conf/netdev_vport_profile_conf.h | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 2 +- src/conf/nwfilter_conf.h | 2 +- src/conf/secret_conf.c | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/cpu/cpu.c | 2 +- src/cpu/cpu_map.h | 2 +- src/esx/esx_vi.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/security/virt-aa-helper.c | 2 +- src/storage/storage_backend_fs.c | 2 +- src/test/test_driver.c | 2 +- src/util/virxml.c | 890 +++++++++++++++++++++++++++++++++++ src/util/virxml.h | 148 ++++++ src/util/xml.c | 890 ----------------------------------- src/util/xml.h | 148 ------ src/xen/xen_driver.c | 2 +- tests/cputest.c | 2 +- tests/nwfilterxml2xmltest.c | 2 +- tests/sexpr2xmltest.c | 2 +- tests/virshtest.c | 2 +- tests/xencapstest.c | 2 +- tools/virsh-domain-monitor.c | 2 +- tools/virsh-domain.c | 2 +- tools/virsh-host.c | 2 +- tools/virsh-interface.c | 2 +- tools/virsh-network.c | 2 +- tools/virsh-nodedev.c | 2 +- tools/virsh-nwfilter.c | 2 +- tools/virsh-pool.c | 2 +- tools/virsh-secret.c | 2 +- tools/virsh-snapshot.c | 2 +- tools/virsh-volume.c | 2 +- tools/virsh.c | 2 +- 47 files changed, 1081 insertions(+), 1081 deletions(-) create mode 100644 src/util/virxml.c create mode 100644 src/util/virxml.h delete mode 100644 src/util/xml.c delete mode 100644 src/util/xml.h diff --git a/cfg.mk b/cfg.mk index a269f77..2fcb444 100644 --- a/cfg.mk +++ b/cfg.mk @@ -809,7 +809,7 @@ exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/virutil\.c$$ exclude_file_name_regexp--sc_prohibit_strtol = \ ^src/(util/virsexpr|(vbox|xen|xenxs)/.*)\.c$$ -exclude_file_name_regexp--sc_prohibit_xmlGetProp = ^src/util/xml\.c$$ +exclude_file_name_regexp--sc_prohibit_xmlGetProp = ^src/util/virxml\.c$$ exclude_file_name_regexp--sc_prohibit_xmlURI = ^src/util/viruri\.c$$ diff --git a/po/POTFILES.in b/po/POTFILES.in index 8a24fd4..1afdca5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -180,7 +180,7 @@ src/util/virtypedparam.c src/util/viruri.c src/util/virusb.c src/util/virutil.c -src/util/xml.c +src/util/virxml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c src/vbox/vbox_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index dd5a1bd..dddd162 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -85,7 +85,6 @@ UTIL_SOURCES = \ util/virthreadwin32.h \ util/virthreadpool.c util/virthreadpool.h \ util/virtypedparam.c util/virtypedparam.h \ - util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ util/vircgroup.c util/vircgroup.h \ util/virdbus.c util/virdbus.h \ @@ -115,6 +114,7 @@ UTIL_SOURCES = \ util/viruri.h util/viruri.c \ util/virutil.c util/virutil.h \ util/viruuid.c util/viruuid.h \ + util/virxml.c util/virxml.h \ $(NULL) EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \ diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 7bec912..616d813 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -26,7 +26,7 @@ # include "virutil.h" # include "virbuffer.h" -# include "xml.h" +# include "virxml.h" # include "virbitmap.h" # define VIR_CPU_VENDOR_ID_LENGTH 12 diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index ecfaf30..45ecb28 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -24,7 +24,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "viralloc.h" -#include "xml.h" +#include "virxml.h" #include "viruuid.h" #include "virutil.h" #include "virbuffer.h" diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 2943fe3..a4f33ed 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -36,7 +36,7 @@ #include "snapshot_conf.h" #include "viralloc.h" #include "verify.h" -#include "xml.h" +#include "virxml.h" #include "viruuid.h" #include "virutil.h" #include "virbuffer.h" diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index 6a53bda..3867274 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -28,7 +28,7 @@ #include "interface_conf.h" #include "viralloc.h" -#include "xml.h" +#include "virxml.h" #include "viruuid.h" #include "virutil.h" #include "virbuffer.h" diff --git a/src/conf/netdev_bandwidth_conf.h b/src/conf/netdev_bandwidth_conf.h index 216a540..23aaaf3 100644 --- a/src/conf/netdev_bandwidth_conf.h +++ b/src/conf/netdev_bandwidth_conf.h @@ -26,7 +26,7 @@ # include "internal.h" # include "virnetdevbandwidth.h" # include "virbuffer.h" -# include "xml.h" +# include "virxml.h" virNetDevBandwidthPtr virNetDevBandwidthParse(xmlNodePtr node, int net_type) diff --git a/src/conf/netdev_vlan_conf.h b/src/conf/netdev_vlan_conf.h index 19b50cc..480d6c6 100644 --- a/src/conf/netdev_vlan_conf.h +++ b/src/conf/netdev_vlan_conf.h @@ -25,7 +25,7 @@ # include "internal.h" # include "virnetdevvlan.h" # include "virbuffer.h" -# include "xml.h" +# include "virxml.h" int virNetDevVlanParse(xmlNodePtr node, xmlXPathContextPtr ctxt, virNetDevVlanPtr def); int virNetDevVlanFormat(virNetDevVlanPtr def, virBufferPtr buf); diff --git a/src/conf/netdev_vport_profile_conf.h b/src/conf/netdev_vport_profile_conf.h index 15ecbd6..a70256d 100644 --- a/src/conf/netdev_vport_profile_conf.h +++ b/src/conf/netdev_vport_profile_conf.h @@ -26,7 +26,7 @@ # include "internal.h" # include "virnetdevvportprofile.h" # include "virbuffer.h" -# include "xml.h" +# include "virxml.h" typedef enum { /* generate random defaults for interfaceID/interfaceID diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 01a6f2e..2bd04c5 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -38,7 +38,7 @@ #include "netdev_bandwidth_conf.h" #include "netdev_vlan_conf.h" #include "viralloc.h" -#include "xml.h" +#include "virxml.h" #include "viruuid.h" #include "virutil.h" #include "virbuffer.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 67d743e..3c68011 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -32,7 +32,7 @@ #include "node_device_conf.h" #include "viralloc.h" -#include "xml.h" +#include "virxml.h" #include "virutil.h" #include "virbuffer.h" #include "viruuid.h" diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h index 2ca44b3..ca2c070 100644 --- a/src/conf/nwfilter_conf.h +++ b/src/conf/nwfilter_conf.h @@ -30,7 +30,7 @@ # include "virutil.h" # include "virhash.h" -# include "xml.h" +# include "virxml.h" # include "virbuffer.h" # include "virsocketaddr.h" # include "virmacaddr.h" diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index 2abb95a..46d2ae5 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -30,7 +30,7 @@ #include "secret_conf.h" #include "virterror_internal.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" #include "viruuid.h" #define VIR_FROM_THIS VIR_FROM_SECRET diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 3ad74d6..f7f8f63 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -46,7 +46,7 @@ #include "viruuid.h" #include "virfile.h" #include "virterror_internal.h" -#include "xml.h" +#include "virxml.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 4239e49..04b2581 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -38,7 +38,7 @@ #include "storage_conf.h" #include "virstoragefile.h" -#include "xml.h" +#include "virxml.h" #include "viruuid.h" #include "virbuffer.h" #include "virutil.h" diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 8ea54fa..35e9da4 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -32,7 +32,7 @@ #include "storage_conf.h" #include "storage_encryption_conf.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" #include "virterror_internal.h" #include "viruuid.h" #include "virfile.h" diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 2222a91..3e25f7d 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -25,7 +25,7 @@ #include "virlog.h" #include "viralloc.h" -#include "xml.h" +#include "virxml.h" #include "cpu.h" #include "cpu_x86.h" #include "cpu_powerpc.h" diff --git a/src/cpu/cpu_map.h b/src/cpu/cpu_map.h index 9120513..8d27bcd 100644 --- a/src/cpu/cpu_map.h +++ b/src/cpu/cpu_map.h @@ -24,7 +24,7 @@ #ifndef __VIR_CPU_MAP_H__ # define __VIR_CPU_MAP_H__ -# include "xml.h" +# include "virxml.h" enum cpuMapElement { diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c index 92ac8f8..99c1eb1 100644 --- a/src/esx/esx_vi.c +++ b/src/esx/esx_vi.c @@ -32,7 +32,7 @@ #include "virutil.h" #include "viruuid.h" #include "vmx.h" -#include "xml.h" +#include "virxml.h" #include "esx_vi.h" #include "esx_vi_methods.h" #include "esx_util.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 8d05b4c..56c93a8 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -46,7 +46,7 @@ #include "virutil.h" #include "viralloc.h" #include "datatypes.h" -#include "xml.h" +#include "virxml.h" #include "nodeinfo.h" #include "virlog.h" #include "cpu/cpu.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 3821d74..d24527b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -76,7 +76,7 @@ #include "virusb.h" #include "virprocess.h" #include "libvirt_internal.h" -#include "xml.h" +#include "virxml.h" #include "cpu/cpu.h" #include "virsysinfo.h" #include "domain_nwfilter.h" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 3c15226..ffd3f71 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -48,7 +48,7 @@ #include "security_driver.h" #include "security_apparmor.h" #include "domain_conf.h" -#include "xml.h" +#include "virxml.h" #include "viruuid.h" #include "virusb.h" #include "virpci.h" diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index b744fb4..23fa0f5 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -47,7 +47,7 @@ #include "virstoragefile.h" #include "vircommand.h" #include "viralloc.h" -#include "xml.h" +#include "virxml.h" #include "virfile.h" #include "virlog.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 1a85eb3..bd557d6 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -46,7 +46,7 @@ #include "domain_event.h" #include "storage_conf.h" #include "node_device_conf.h" -#include "xml.h" +#include "virxml.h" #include "virthread.h" #include "virlog.h" #include "virfile.h" diff --git a/src/util/virxml.c b/src/util/virxml.c new file mode 100644 index 0000000..02f7d1a --- /dev/null +++ b/src/util/virxml.c @@ -0,0 +1,890 @@ +/* + * xml.c: XML based interfaces for the libvir library + * + * Copyright (C) 2005, 2007-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * 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 <sys/stat.h> + +#include "virterror_internal.h" +#include "virxml.h" +#include "virbuffer.h" +#include "virutil.h" +#include "viralloc.h" +#include "virfile.h" + +#define VIR_FROM_THIS VIR_FROM_XML + +#define virGenericReportError(from, code, ...) \ + virReportErrorHelper(from, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +/* Internal data to be passed to SAX parser and used by error handler. */ +struct virParserData { + int domcode; +}; + + +/************************************************************************ + * * + * 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(const char *xpath, + xmlXPathContextPtr ctxt) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + char *ret; + + if ((ctxt == NULL) || (xpath == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathString()")); + return NULL; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + 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(); + } + 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(const char *xpath, + size_t maxlen, + xmlXPathContextPtr ctxt) +{ + char *tmp = virXPathString(xpath, ctxt); + + if (tmp != NULL && strlen(tmp) >= maxlen) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("\'%s\' value longer than %zu bytes"), + xpath, maxlen); + VIR_FREE(tmp); + 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(const char *xpath, + xmlXPathContextPtr ctxt, + double *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathNumber()")); + return -1; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj == NULL) || (obj->type != XPATH_NUMBER) || + (isnan(obj->floatval))) { + xmlXPathFreeObject(obj); + return -1; + } + + *value = obj->floatval; + xmlXPathFreeObject(obj); + return 0; +} + +static int +virXPathLongBase(const char *xpath, + xmlXPathContextPtr ctxt, + int base, + long *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret = 0; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathLong()")); + return -1; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + if (virStrToLong_l((char *) obj->stringval, NULL, base, value) < 0) + ret = -2; + } 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); + return ret; +} + +/** + * virXPathInt: + * @xpath: the XPath string to evaluate + * @ctxt: an XPath context + * @value: the returned int 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 an int format. + */ +int +virXPathInt(const char *xpath, + xmlXPathContextPtr ctxt, + int *value) +{ + long tmp; + int ret; + + ret = virXPathLongBase(xpath, ctxt, 10, &tmp); + if (ret < 0) + return ret; + if ((int) tmp != tmp) + return -2; + *value = tmp; + return 0; +} + +/** + * 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(const char *xpath, + xmlXPathContextPtr ctxt, + long *value) +{ + return virXPathLongBase(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(const char *xpath, + xmlXPathContextPtr ctxt, + long *value) +{ + return virXPathLongBase(xpath, ctxt, 16, value); +} + +static int +virXPathULongBase(const char *xpath, + xmlXPathContextPtr ctxt, + int base, + unsigned long *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret = 0; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathULong()")); + return -1; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + if (virStrToLong_ul((char *) obj->stringval, NULL, base, value) < 0) + ret = -2; + } 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); + return ret; +} + +/** + * virXPathUInt: + * @xpath: the XPath string to evaluate + * @ctxt: an XPath context + * @value: the returned int 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 an int format. + */ +int +virXPathUInt(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned int *value) +{ + unsigned long tmp; + int ret; + + ret = virXPathULongBase(xpath, ctxt, 10, &tmp); + if (ret < 0) + return ret; + if ((unsigned int) tmp != tmp) + return -2; + *value = tmp; + return 0; +} + +/** + * 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(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long *value) +{ + return virXPathULongBase(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(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long *value) +{ + return virXPathULongBase(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(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long long *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret = 0; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathULong()")); + return -1; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + if (virStrToLong_ull((char *) obj->stringval, NULL, 10, value) < 0) + ret = -2; + } 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); + return ret; +} + +/** + * 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 +virXPathLongLong(const char *xpath, + xmlXPathContextPtr ctxt, + long long *value) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret = 0; + + if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathLongLong()")); + return -1; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + if (virStrToLong_ll((char *) obj->stringval, NULL, 10, value) < 0) + ret = -2; + } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) && + (!(isnan(obj->floatval)))) { + *value = (long long) obj->floatval; + if (*value != obj->floatval) { + ret = -2; + } + } else { + ret = -1; + } + + xmlXPathFreeObject(obj); + 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(const char *xpath, + xmlXPathContextPtr ctxt) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret; + + if ((ctxt == NULL) || (xpath == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathBoolean()")); + return -1; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) || + (obj->boolval < 0) || (obj->boolval > 1)) { + xmlXPathFreeObject(obj); + return -1; + } + ret = obj->boolval; + + xmlXPathFreeObject(obj); + 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(const char *xpath, + xmlXPathContextPtr ctxt) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + xmlNodePtr ret; + + if ((ctxt == NULL) || (xpath == NULL)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid parameter to virXPathNode()")); + return NULL; + } + relnode = ctxt->node; + obj = xmlXPathEval(BAD_CAST xpath, ctxt); + ctxt->node = relnode; + if ((obj == NULL) || (obj->type != XPATH_NODESET) || + (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) || + (obj->nodesetval->nodeTab == NULL)) { + xmlXPathFreeObject(obj); + return NULL; + } + + ret = obj->nodesetval->nodeTab[0]; + xmlXPathFreeObject(obj); + 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(const char *xpath, + xmlXPathContextPtr ctxt, + xmlNodePtr **list) +{ + xmlXPathObjectPtr obj; + xmlNodePtr relnode; + int ret; + + if ((ctxt == NULL) || (xpath == NULL)) { + virReportError(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); + ctxt->node = relnode; + if (obj == NULL) + return 0; + + if (obj->type != XPATH_NODESET) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Incorrect xpath '%s'"), xpath); + xmlXPathFreeObject(obj); + return -1; + } + + if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) { + xmlXPathFreeObject(obj); + return 0; + } + + ret = obj->nodesetval->nodeNr; + if (list != NULL && ret) { + if (VIR_ALLOC_N(*list, ret) < 0) { + virReportOOMError(); + ret = -1; + } else { + memcpy(*list, obj->nodesetval->nodeTab, + ret * sizeof(xmlNodePtr)); + } + } + xmlXPathFreeObject(obj); + return ret; +} + + +/** + * catchXMLError: + * + * Called from SAX on parsing errors in the XML. + * + * This version is heavily based on xmlParserPrintFileContextInternal from libxml2. + */ +static void +catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + const xmlChar *cur, *base; + unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ + int domcode = VIR_FROM_XML; + + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *contextstr = NULL; + char *pointerstr = NULL; + + + /* conditions for error printing */ + if (!ctxt || + (virGetLastError() != NULL) || + ctxt->input == NULL || + ctxt->lastError.level != XML_ERR_FATAL || + ctxt->lastError.message == NULL) + return; + + if (ctxt->_private) + domcode = ((struct virParserData *) ctxt->_private)->domcode; + + + cur = ctxt->input->cur; + base = ctxt->input->base; + + /* skip backwards over any end-of-lines */ + while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { + cur--; + } + + /* search backwards for beginning-of-line (to max buff size) */ + while ((cur > base) && (*(cur) != '\n') && (*(cur) != '\r')) + cur--; + if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; + + /* calculate the error position in terms of the current position */ + col = ctxt->input->cur - cur; + + /* search forward for end-of-line (to max buff size) */ + /* copy selected text to our buffer */ + while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) { + virBufferAddChar(&buf, *cur++); + } + + /* create blank line with problem pointer */ + contextstr = virBufferContentAndReset(&buf); + + /* (leave buffer space for pointer + line terminator) */ + for (n = 0; (n<col) && (contextstr[n] != 0); n++) { + if (contextstr[n] == '\t') + virBufferAddChar(&buf, '\t'); + else + virBufferAddChar(&buf, '-'); + } + + virBufferAddChar(&buf, '^'); + + pointerstr = virBufferContentAndReset(&buf); + + if (ctxt->lastError.file) { + virGenericReportError(domcode, VIR_ERR_XML_DETAIL, + _("%s:%d: %s%s\n%s"), + ctxt->lastError.file, + ctxt->lastError.line, + ctxt->lastError.message, + contextstr, + pointerstr); + } else { + virGenericReportError(domcode, VIR_ERR_XML_DETAIL, + _("at line %d: %s%s\n%s"), + ctxt->lastError.line, + ctxt->lastError.message, + contextstr, + pointerstr); + } + + VIR_FREE(contextstr); + VIR_FREE(pointerstr); +} + +/** + * virXMLParseHelper: + * @domcode: error domain of the caller, usually VIR_FROM_THIS + * @filename: file to be parsed or NULL if string parsing is requested + * @xmlStr: XML string to be parsed in case filename is NULL + * @url: URL of XML document for string parser + * @ctxt: optional pointer to populate with new context pointer + * + * Parse XML document provided either as a file or a string. The function + * guarantees that the XML document contains a root element. + * + * Returns parsed XML document. + */ +xmlDocPtr +virXMLParseHelper(int domcode, + const char *filename, + const char *xmlStr, + const char *url, + xmlXPathContextPtr *ctxt) +{ + struct virParserData private; + xmlParserCtxtPtr pctxt; + xmlDocPtr xml = NULL; + + /* Set up a parser context so we can catch the details of XML errors. */ + pctxt = xmlNewParserCtxt(); + if (!pctxt || !pctxt->sax) { + virReportOOMError(); + goto error; + } + + private.domcode = domcode; + pctxt->_private = &private; + pctxt->sax->error = catchXMLError; + + if (filename) { + xml = xmlCtxtReadFile(pctxt, filename, NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + } else { + xml = xmlCtxtReadDoc(pctxt, BAD_CAST xmlStr, url, NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOWARNING); + } + if (!xml) + goto error; + + if (xmlDocGetRootElement(xml) == NULL) { + virGenericReportError(domcode, VIR_ERR_INTERNAL_ERROR, + "%s", _("missing root element")); + goto error; + } + + if (ctxt) { + *ctxt = xmlXPathNewContext(xml); + if (!*ctxt) { + virReportOOMError(); + goto error; + } + (*ctxt)->node = xmlDocGetRootElement(xml); + } + +cleanup: + xmlFreeParserCtxt(pctxt); + + return xml; + +error: + xmlFreeDoc(xml); + xml = NULL; + + if (virGetLastError() == NULL) { + virGenericReportError(domcode, VIR_ERR_XML_ERROR, + "%s", _("failed to parse xml document")); + } + goto cleanup; +} + +const char *virXMLPickShellSafeComment(const char *str1, const char *str2) +{ + if (str1 && !strpbrk(str1, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") && + !strstr(str1, "--")) + return str1; + if (str2 && !strpbrk(str2, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") && + !strstr(str2, "--")) + return str2; + return NULL; +} + +static int virXMLEmitWarning(int fd, + const char *name, + const char *cmd) +{ + size_t len; + const char *prologue = + "<!--\n" + "WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE\n" + "OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n" + " virsh "; + const char *epilogue = + "\n" + "or other application using the libvirt API.\n" + "-->\n\n"; + + if (fd < 0 || !cmd) { + errno = EINVAL; + return -1; + } + + len = strlen(prologue); + if (safewrite(fd, prologue, len) != len) + return -1; + + len = strlen(cmd); + if (safewrite(fd, cmd, len) != len) + return -1; + + if (name) { + if (safewrite(fd, " ", 1) != 1) + return -1; + + len = strlen(name); + if (safewrite(fd, name, len) != len) + return -1; + } + + len = strlen(epilogue); + if (safewrite(fd, epilogue, len) != len) + return -1; + + return 0; +} + + +struct virXMLRewriteFileData { + const char *warnName; + const char *warnCommand; + const char *xml; +}; + +static int +virXMLRewriteFile(int fd, void *opaque) +{ + struct virXMLRewriteFileData *data = opaque; + + if (data->warnCommand) { + if (virXMLEmitWarning(fd, data->warnName, data->warnCommand) < 0) + return -1; + } + + if (safewrite(fd, data->xml, strlen(data->xml)) < 0) + return -1; + + return 0; +} + +int +virXMLSaveFile(const char *path, + const char *warnName, + const char *warnCommand, + const char *xml) +{ + struct virXMLRewriteFileData data = { warnName, warnCommand, xml }; + + return virFileRewrite(path, S_IRUSR | S_IWUSR, virXMLRewriteFile, &data); +} + +/* Returns the number of children of node, or -1 on error. */ +long +virXMLChildElementCount(xmlNodePtr node) +{ + long ret = 0; + xmlNodePtr cur = NULL; + + /* xmlChildElementCount returns 0 on error, which isn't helpful; + * besides, it is not available in libxml2 2.6. */ + if (!node || node->type != XML_ELEMENT_NODE) + return -1; + cur = node->children; + while (cur) { + if (cur->type == XML_ELEMENT_NODE) + ret++; + cur = cur->next; + } + return ret; +} diff --git a/src/util/virxml.h b/src/util/virxml.h new file mode 100644 index 0000000..c3b05df --- /dev/null +++ b/src/util/virxml.h @@ -0,0 +1,148 @@ +/* + * 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(const char *xpath, + xmlXPathContextPtr ctxt); +char * virXPathString(const char *xpath, + xmlXPathContextPtr ctxt); +char * virXPathStringLimit(const char *xpath, + size_t maxlen, + xmlXPathContextPtr ctxt); +int virXPathNumber(const char *xpath, + xmlXPathContextPtr ctxt, + double *value); +int virXPathInt(const char *xpath, + xmlXPathContextPtr ctxt, + int *value); +int virXPathUInt(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned int *value); +int virXPathLong(const char *xpath, + xmlXPathContextPtr ctxt, + long *value); +int virXPathULong(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long *value); +int virXPathULongLong(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long long *value); +int virXPathLongLong(const char *xpath, + xmlXPathContextPtr ctxt, + long long *value); +int virXPathLongHex(const char *xpath, + xmlXPathContextPtr ctxt, + long *value); +int virXPathULongHex(const char *xpath, + xmlXPathContextPtr ctxt, + unsigned long *value); +xmlNodePtr virXPathNode(const char *xpath, + xmlXPathContextPtr ctxt); +int virXPathNodeSet(const char *xpath, + xmlXPathContextPtr ctxt, + xmlNodePtr **list); +char * virXMLPropString(xmlNodePtr node, + const char *name); +long virXMLChildElementCount(xmlNodePtr node); + +/* Internal function; prefer the macros below. */ +xmlDocPtr virXMLParseHelper(int domcode, + const char *filename, + const char *xmlStr, + const char *url, + xmlXPathContextPtr *pctxt); + +const char *virXMLPickShellSafeComment(const char *str1, const char *str2); +/** + * virXMLParse: + * @filename: file to parse, or NULL for string parsing + * @xmlStr: if @filename is NULL, a string to parse + * @url: if @filename is NULL, an optional filename to attribute the parse to + * + * Parse xml from either a file or a string. + * + * Return the parsed document object, or NULL on failure. + */ +# define virXMLParse(filename, xmlStr, url) \ + virXMLParseHelper(VIR_FROM_THIS, filename, xmlStr, url, NULL) + +/** + * virXMLParseString: + * @xmlStr: a string to parse + * @url: an optional filename to attribute the parse to + * + * Parse xml from a string. + * + * Return the parsed document object, or NULL on failure. + */ +# define virXMLParseString(xmlStr, url) \ + virXMLParseHelper(VIR_FROM_THIS, NULL, xmlStr, url, NULL) + +/** + * virXMLParseFile: + * @filename: file to parse + * + * Parse xml from a file. + * + * Return the parsed document object, or NULL on failure. + */ +# define virXMLParseFile(filename) \ + virXMLParseHelper(VIR_FROM_THIS, filename, NULL, NULL, NULL) + +/** + * virXMLParseCtxt: + * @filename: file to parse, or NULL for string parsing + * @xmlStr: if @filename is NULL, a string to parse + * @url: if @filename is NULL, an optional filename to attribute the parse to + * @pctxt: if non-NULL, populate with a new context object on success, + * with (*pctxt)->node pre-set to the root node + * + * Parse xml from either a file or a string. + * + * Return the parsed document object, or NULL on failure. + */ +# define virXMLParseCtxt(filename, xmlStr, url, pctxt) \ + virXMLParseHelper(VIR_FROM_THIS, filename, xmlStr, url, pctxt) + +/** + * virXMLParseStringCtxt: + * @xmlStr: a string to parse + * @url: an optional filename to attribute the parse to + * @pctxt: if non-NULL, populate with a new context object on success, + * with (*pctxt)->node pre-set to the root node + * + * Parse xml from a string. + * + * Return the parsed document object, or NULL on failure. + */ +# define virXMLParseStringCtxt(xmlStr, url, pctxt) \ + virXMLParseHelper(VIR_FROM_THIS, NULL, xmlStr, url, pctxt) + +/** + * virXMLParseFileCtxt: + * @filename: file to parse + * @pctxt: if non-NULL, populate with a new context object on success, + * with (*pctxt)->node pre-set to the root node + * + * Parse xml from a file. + * + * Return the parsed document object, or NULL on failure. + */ +# define virXMLParseFileCtxt(filename, pctxt) \ + virXMLParseHelper(VIR_FROM_THIS, filename, NULL, NULL, pctxt) + +int virXMLSaveFile(const char *path, + const char *warnName, + const char *warnCommand, + const char *xml); + +#endif /* __VIR_XML_H__ */ diff --git a/src/util/xml.c b/src/util/xml.c deleted file mode 100644 index 05c7f33..0000000 --- a/src/util/xml.c +++ /dev/null @@ -1,890 +0,0 @@ -/* - * xml.c: XML based interfaces for the libvir library - * - * Copyright (C) 2005, 2007-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 <sys/stat.h> - -#include "virterror_internal.h" -#include "xml.h" -#include "virbuffer.h" -#include "virutil.h" -#include "viralloc.h" -#include "virfile.h" - -#define VIR_FROM_THIS VIR_FROM_XML - -#define virGenericReportError(from, code, ...) \ - virReportErrorHelper(from, code, __FILE__, \ - __FUNCTION__, __LINE__, __VA_ARGS__) - -/* Internal data to be passed to SAX parser and used by error handler. */ -struct virParserData { - int domcode; -}; - - -/************************************************************************ - * * - * 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(const char *xpath, - xmlXPathContextPtr ctxt) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - char *ret; - - if ((ctxt == NULL) || (xpath == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathString()")); - return NULL; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - 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(); - } - 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(const char *xpath, - size_t maxlen, - xmlXPathContextPtr ctxt) -{ - char *tmp = virXPathString(xpath, ctxt); - - if (tmp != NULL && strlen(tmp) >= maxlen) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("\'%s\' value longer than %zu bytes"), - xpath, maxlen); - VIR_FREE(tmp); - 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(const char *xpath, - xmlXPathContextPtr ctxt, - double *value) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - - if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathNumber()")); - return -1; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - if ((obj == NULL) || (obj->type != XPATH_NUMBER) || - (isnan(obj->floatval))) { - xmlXPathFreeObject(obj); - return -1; - } - - *value = obj->floatval; - xmlXPathFreeObject(obj); - return 0; -} - -static int -virXPathLongBase(const char *xpath, - xmlXPathContextPtr ctxt, - int base, - long *value) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - int ret = 0; - - if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathLong()")); - return -1; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (virStrToLong_l((char *) obj->stringval, NULL, base, value) < 0) - ret = -2; - } 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); - return ret; -} - -/** - * virXPathInt: - * @xpath: the XPath string to evaluate - * @ctxt: an XPath context - * @value: the returned int 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 an int format. - */ -int -virXPathInt(const char *xpath, - xmlXPathContextPtr ctxt, - int *value) -{ - long tmp; - int ret; - - ret = virXPathLongBase(xpath, ctxt, 10, &tmp); - if (ret < 0) - return ret; - if ((int) tmp != tmp) - return -2; - *value = tmp; - return 0; -} - -/** - * 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(const char *xpath, - xmlXPathContextPtr ctxt, - long *value) -{ - return virXPathLongBase(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(const char *xpath, - xmlXPathContextPtr ctxt, - long *value) -{ - return virXPathLongBase(xpath, ctxt, 16, value); -} - -static int -virXPathULongBase(const char *xpath, - xmlXPathContextPtr ctxt, - int base, - unsigned long *value) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - int ret = 0; - - if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathULong()")); - return -1; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (virStrToLong_ul((char *) obj->stringval, NULL, base, value) < 0) - ret = -2; - } 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); - return ret; -} - -/** - * virXPathUInt: - * @xpath: the XPath string to evaluate - * @ctxt: an XPath context - * @value: the returned int 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 an int format. - */ -int -virXPathUInt(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned int *value) -{ - unsigned long tmp; - int ret; - - ret = virXPathULongBase(xpath, ctxt, 10, &tmp); - if (ret < 0) - return ret; - if ((unsigned int) tmp != tmp) - return -2; - *value = tmp; - return 0; -} - -/** - * 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(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned long *value) -{ - return virXPathULongBase(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(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned long *value) -{ - return virXPathULongBase(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(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned long long *value) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - int ret = 0; - - if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathULong()")); - return -1; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (virStrToLong_ull((char *) obj->stringval, NULL, 10, value) < 0) - ret = -2; - } 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); - return ret; -} - -/** - * 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 -virXPathLongLong(const char *xpath, - xmlXPathContextPtr ctxt, - long long *value) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - int ret = 0; - - if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathLongLong()")); - return -1; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (virStrToLong_ll((char *) obj->stringval, NULL, 10, value) < 0) - ret = -2; - } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) && - (!(isnan(obj->floatval)))) { - *value = (long long) obj->floatval; - if (*value != obj->floatval) { - ret = -2; - } - } else { - ret = -1; - } - - xmlXPathFreeObject(obj); - 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(const char *xpath, - xmlXPathContextPtr ctxt) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - int ret; - - if ((ctxt == NULL) || (xpath == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathBoolean()")); - return -1; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) || - (obj->boolval < 0) || (obj->boolval > 1)) { - xmlXPathFreeObject(obj); - return -1; - } - ret = obj->boolval; - - xmlXPathFreeObject(obj); - 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(const char *xpath, - xmlXPathContextPtr ctxt) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - xmlNodePtr ret; - - if ((ctxt == NULL) || (xpath == NULL)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Invalid parameter to virXPathNode()")); - return NULL; - } - relnode = ctxt->node; - obj = xmlXPathEval(BAD_CAST xpath, ctxt); - ctxt->node = relnode; - if ((obj == NULL) || (obj->type != XPATH_NODESET) || - (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) || - (obj->nodesetval->nodeTab == NULL)) { - xmlXPathFreeObject(obj); - return NULL; - } - - ret = obj->nodesetval->nodeTab[0]; - xmlXPathFreeObject(obj); - 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(const char *xpath, - xmlXPathContextPtr ctxt, - xmlNodePtr **list) -{ - xmlXPathObjectPtr obj; - xmlNodePtr relnode; - int ret; - - if ((ctxt == NULL) || (xpath == NULL)) { - virReportError(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); - ctxt->node = relnode; - if (obj == NULL) - return 0; - - if (obj->type != XPATH_NODESET) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Incorrect xpath '%s'"), xpath); - xmlXPathFreeObject(obj); - return -1; - } - - if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) { - xmlXPathFreeObject(obj); - return 0; - } - - ret = obj->nodesetval->nodeNr; - if (list != NULL && ret) { - if (VIR_ALLOC_N(*list, ret) < 0) { - virReportOOMError(); - ret = -1; - } else { - memcpy(*list, obj->nodesetval->nodeTab, - ret * sizeof(xmlNodePtr)); - } - } - xmlXPathFreeObject(obj); - return ret; -} - - -/** - * catchXMLError: - * - * Called from SAX on parsing errors in the XML. - * - * This version is heavily based on xmlParserPrintFileContextInternal from libxml2. - */ -static void -catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) -{ - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - - const xmlChar *cur, *base; - unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ - int domcode = VIR_FROM_XML; - - virBuffer buf = VIR_BUFFER_INITIALIZER; - char *contextstr = NULL; - char *pointerstr = NULL; - - - /* conditions for error printing */ - if (!ctxt || - (virGetLastError() != NULL) || - ctxt->input == NULL || - ctxt->lastError.level != XML_ERR_FATAL || - ctxt->lastError.message == NULL) - return; - - if (ctxt->_private) - domcode = ((struct virParserData *) ctxt->_private)->domcode; - - - cur = ctxt->input->cur; - base = ctxt->input->base; - - /* skip backwards over any end-of-lines */ - while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { - cur--; - } - - /* search backwards for beginning-of-line (to max buff size) */ - while ((cur > base) && (*(cur) != '\n') && (*(cur) != '\r')) - cur--; - if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; - - /* calculate the error position in terms of the current position */ - col = ctxt->input->cur - cur; - - /* search forward for end-of-line (to max buff size) */ - /* copy selected text to our buffer */ - while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) { - virBufferAddChar(&buf, *cur++); - } - - /* create blank line with problem pointer */ - contextstr = virBufferContentAndReset(&buf); - - /* (leave buffer space for pointer + line terminator) */ - for (n = 0; (n<col) && (contextstr[n] != 0); n++) { - if (contextstr[n] == '\t') - virBufferAddChar(&buf, '\t'); - else - virBufferAddChar(&buf, '-'); - } - - virBufferAddChar(&buf, '^'); - - pointerstr = virBufferContentAndReset(&buf); - - if (ctxt->lastError.file) { - virGenericReportError(domcode, VIR_ERR_XML_DETAIL, - _("%s:%d: %s%s\n%s"), - ctxt->lastError.file, - ctxt->lastError.line, - ctxt->lastError.message, - contextstr, - pointerstr); - } else { - virGenericReportError(domcode, VIR_ERR_XML_DETAIL, - _("at line %d: %s%s\n%s"), - ctxt->lastError.line, - ctxt->lastError.message, - contextstr, - pointerstr); - } - - VIR_FREE(contextstr); - VIR_FREE(pointerstr); -} - -/** - * virXMLParseHelper: - * @domcode: error domain of the caller, usually VIR_FROM_THIS - * @filename: file to be parsed or NULL if string parsing is requested - * @xmlStr: XML string to be parsed in case filename is NULL - * @url: URL of XML document for string parser - * @ctxt: optional pointer to populate with new context pointer - * - * Parse XML document provided either as a file or a string. The function - * guarantees that the XML document contains a root element. - * - * Returns parsed XML document. - */ -xmlDocPtr -virXMLParseHelper(int domcode, - const char *filename, - const char *xmlStr, - const char *url, - xmlXPathContextPtr *ctxt) -{ - struct virParserData private; - xmlParserCtxtPtr pctxt; - xmlDocPtr xml = NULL; - - /* Set up a parser context so we can catch the details of XML errors. */ - pctxt = xmlNewParserCtxt(); - if (!pctxt || !pctxt->sax) { - virReportOOMError(); - goto error; - } - - private.domcode = domcode; - pctxt->_private = &private; - pctxt->sax->error = catchXMLError; - - if (filename) { - xml = xmlCtxtReadFile(pctxt, filename, NULL, - XML_PARSE_NOENT | XML_PARSE_NONET | - XML_PARSE_NOWARNING); - } else { - xml = xmlCtxtReadDoc(pctxt, BAD_CAST xmlStr, url, NULL, - XML_PARSE_NOENT | XML_PARSE_NONET | - XML_PARSE_NOWARNING); - } - if (!xml) - goto error; - - if (xmlDocGetRootElement(xml) == NULL) { - virGenericReportError(domcode, VIR_ERR_INTERNAL_ERROR, - "%s", _("missing root element")); - goto error; - } - - if (ctxt) { - *ctxt = xmlXPathNewContext(xml); - if (!*ctxt) { - virReportOOMError(); - goto error; - } - (*ctxt)->node = xmlDocGetRootElement(xml); - } - -cleanup: - xmlFreeParserCtxt(pctxt); - - return xml; - -error: - xmlFreeDoc(xml); - xml = NULL; - - if (virGetLastError() == NULL) { - virGenericReportError(domcode, VIR_ERR_XML_ERROR, - "%s", _("failed to parse xml document")); - } - goto cleanup; -} - -const char *virXMLPickShellSafeComment(const char *str1, const char *str2) -{ - if (str1 && !strpbrk(str1, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") && - !strstr(str1, "--")) - return str1; - if (str2 && !strpbrk(str2, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~") && - !strstr(str2, "--")) - return str2; - return NULL; -} - -static int virXMLEmitWarning(int fd, - const char *name, - const char *cmd) -{ - size_t len; - const char *prologue = - "<!--\n" - "WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE\n" - "OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:\n" - " virsh "; - const char *epilogue = - "\n" - "or other application using the libvirt API.\n" - "-->\n\n"; - - if (fd < 0 || !cmd) { - errno = EINVAL; - return -1; - } - - len = strlen(prologue); - if (safewrite(fd, prologue, len) != len) - return -1; - - len = strlen(cmd); - if (safewrite(fd, cmd, len) != len) - return -1; - - if (name) { - if (safewrite(fd, " ", 1) != 1) - return -1; - - len = strlen(name); - if (safewrite(fd, name, len) != len) - return -1; - } - - len = strlen(epilogue); - if (safewrite(fd, epilogue, len) != len) - return -1; - - return 0; -} - - -struct virXMLRewriteFileData { - const char *warnName; - const char *warnCommand; - const char *xml; -}; - -static int -virXMLRewriteFile(int fd, void *opaque) -{ - struct virXMLRewriteFileData *data = opaque; - - if (data->warnCommand) { - if (virXMLEmitWarning(fd, data->warnName, data->warnCommand) < 0) - return -1; - } - - if (safewrite(fd, data->xml, strlen(data->xml)) < 0) - return -1; - - return 0; -} - -int -virXMLSaveFile(const char *path, - const char *warnName, - const char *warnCommand, - const char *xml) -{ - struct virXMLRewriteFileData data = { warnName, warnCommand, xml }; - - return virFileRewrite(path, S_IRUSR | S_IWUSR, virXMLRewriteFile, &data); -} - -/* Returns the number of children of node, or -1 on error. */ -long -virXMLChildElementCount(xmlNodePtr node) -{ - long ret = 0; - xmlNodePtr cur = NULL; - - /* xmlChildElementCount returns 0 on error, which isn't helpful; - * besides, it is not available in libxml2 2.6. */ - if (!node || node->type != XML_ELEMENT_NODE) - return -1; - cur = node->children; - while (cur) { - if (cur->type == XML_ELEMENT_NODE) - ret++; - cur = cur->next; - } - return ret; -} diff --git a/src/util/xml.h b/src/util/xml.h deleted file mode 100644 index c3b05df..0000000 --- a/src/util/xml.h +++ /dev/null @@ -1,148 +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(const char *xpath, - xmlXPathContextPtr ctxt); -char * virXPathString(const char *xpath, - xmlXPathContextPtr ctxt); -char * virXPathStringLimit(const char *xpath, - size_t maxlen, - xmlXPathContextPtr ctxt); -int virXPathNumber(const char *xpath, - xmlXPathContextPtr ctxt, - double *value); -int virXPathInt(const char *xpath, - xmlXPathContextPtr ctxt, - int *value); -int virXPathUInt(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned int *value); -int virXPathLong(const char *xpath, - xmlXPathContextPtr ctxt, - long *value); -int virXPathULong(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned long *value); -int virXPathULongLong(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned long long *value); -int virXPathLongLong(const char *xpath, - xmlXPathContextPtr ctxt, - long long *value); -int virXPathLongHex(const char *xpath, - xmlXPathContextPtr ctxt, - long *value); -int virXPathULongHex(const char *xpath, - xmlXPathContextPtr ctxt, - unsigned long *value); -xmlNodePtr virXPathNode(const char *xpath, - xmlXPathContextPtr ctxt); -int virXPathNodeSet(const char *xpath, - xmlXPathContextPtr ctxt, - xmlNodePtr **list); -char * virXMLPropString(xmlNodePtr node, - const char *name); -long virXMLChildElementCount(xmlNodePtr node); - -/* Internal function; prefer the macros below. */ -xmlDocPtr virXMLParseHelper(int domcode, - const char *filename, - const char *xmlStr, - const char *url, - xmlXPathContextPtr *pctxt); - -const char *virXMLPickShellSafeComment(const char *str1, const char *str2); -/** - * virXMLParse: - * @filename: file to parse, or NULL for string parsing - * @xmlStr: if @filename is NULL, a string to parse - * @url: if @filename is NULL, an optional filename to attribute the parse to - * - * Parse xml from either a file or a string. - * - * Return the parsed document object, or NULL on failure. - */ -# define virXMLParse(filename, xmlStr, url) \ - virXMLParseHelper(VIR_FROM_THIS, filename, xmlStr, url, NULL) - -/** - * virXMLParseString: - * @xmlStr: a string to parse - * @url: an optional filename to attribute the parse to - * - * Parse xml from a string. - * - * Return the parsed document object, or NULL on failure. - */ -# define virXMLParseString(xmlStr, url) \ - virXMLParseHelper(VIR_FROM_THIS, NULL, xmlStr, url, NULL) - -/** - * virXMLParseFile: - * @filename: file to parse - * - * Parse xml from a file. - * - * Return the parsed document object, or NULL on failure. - */ -# define virXMLParseFile(filename) \ - virXMLParseHelper(VIR_FROM_THIS, filename, NULL, NULL, NULL) - -/** - * virXMLParseCtxt: - * @filename: file to parse, or NULL for string parsing - * @xmlStr: if @filename is NULL, a string to parse - * @url: if @filename is NULL, an optional filename to attribute the parse to - * @pctxt: if non-NULL, populate with a new context object on success, - * with (*pctxt)->node pre-set to the root node - * - * Parse xml from either a file or a string. - * - * Return the parsed document object, or NULL on failure. - */ -# define virXMLParseCtxt(filename, xmlStr, url, pctxt) \ - virXMLParseHelper(VIR_FROM_THIS, filename, xmlStr, url, pctxt) - -/** - * virXMLParseStringCtxt: - * @xmlStr: a string to parse - * @url: an optional filename to attribute the parse to - * @pctxt: if non-NULL, populate with a new context object on success, - * with (*pctxt)->node pre-set to the root node - * - * Parse xml from a string. - * - * Return the parsed document object, or NULL on failure. - */ -# define virXMLParseStringCtxt(xmlStr, url, pctxt) \ - virXMLParseHelper(VIR_FROM_THIS, NULL, xmlStr, url, pctxt) - -/** - * virXMLParseFileCtxt: - * @filename: file to parse - * @pctxt: if non-NULL, populate with a new context object on success, - * with (*pctxt)->node pre-set to the root node - * - * Parse xml from a file. - * - * Return the parsed document object, or NULL on failure. - */ -# define virXMLParseFileCtxt(filename, pctxt) \ - virXMLParseHelper(VIR_FROM_THIS, filename, NULL, NULL, pctxt) - -int virXMLSaveFile(const char *path, - const char *warnName, - const char *warnCommand, - const char *xml); - -#endif /* __VIR_XML_H__ */ diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 4cbe827..c35695a 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -53,7 +53,7 @@ #if WITH_XEN_INOTIFY # include "xen_inotify.h" #endif -#include "xml.h" +#include "virxml.h" #include "virutil.h" #include "viralloc.h" #include "node_device_conf.h" diff --git a/tests/cputest.c b/tests/cputest.c index ee1a608..6505367 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -31,7 +31,7 @@ #include <fcntl.h> #include "internal.h" -#include "xml.h" +#include "virxml.h" #include "viralloc.h" #include "virbuffer.h" #include "testutils.h" diff --git a/tests/nwfilterxml2xmltest.c b/tests/nwfilterxml2xmltest.c index 8c29a46..a215bf8 100644 --- a/tests/nwfilterxml2xmltest.c +++ b/tests/nwfilterxml2xmltest.c @@ -10,7 +10,7 @@ #include "internal.h" #include "testutils.h" -#include "xml.h" +#include "virxml.h" #include "virthread.h" #include "nwfilter_params.h" #include "nwfilter_conf.h" diff --git a/tests/sexpr2xmltest.c b/tests/sexpr2xmltest.c index 9b9b09d..07f6f8e 100644 --- a/tests/sexpr2xmltest.c +++ b/tests/sexpr2xmltest.c @@ -5,7 +5,7 @@ #include <unistd.h> #include "internal.h" -#include "xml.h" +#include "virxml.h" #include "datatypes.h" #include "xen/xen_driver.h" #include "xen/xend_internal.h" diff --git a/tests/virshtest.c b/tests/virshtest.c index 8741d47..b82a4c4 100644 --- a/tests/virshtest.c +++ b/tests/virshtest.c @@ -5,7 +5,7 @@ #include <unistd.h> #include "internal.h" -#include "xml.h" +#include "virxml.h" #include "virutil.h" #include "testutils.h" diff --git a/tests/xencapstest.c b/tests/xencapstest.c index 387e278..b3f7d62 100644 --- a/tests/xencapstest.c +++ b/tests/xencapstest.c @@ -6,7 +6,7 @@ #include <unistd.h> #include "internal.h" -#include "xml.h" +#include "virxml.h" #include "testutils.h" #include "xen/xen_hypervisor.h" #include "virfile.h" diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index a443988..f4940fa 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -37,7 +37,7 @@ #include "viralloc.h" #include "virmacaddr.h" #include "virsh-domain.h" -#include "xml.h" +#include "virxml.h" static const char * vshDomainIOErrorToString(int error) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 244ffb8..3a9cebe 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -51,7 +51,7 @@ #include "virsh-domain-monitor.h" #include "virterror_internal.h" #include "virtypedparam.h" -#include "xml.h" +#include "virxml.h" /* Gnulib doesn't guarantee SA_SIGINFO support. */ #ifndef SA_SIGINFO diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 0ad4296..45b89a8 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -36,7 +36,7 @@ #include "viralloc.h" #include "virutil.h" #include "virsh-domain.h" -#include "xml.h" +#include "virxml.h" #include "virtypedparam.h" #include "virjson.h" diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index ea8a6c5..cd14e89 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -35,7 +35,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd, diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 918dee6..c9cd15a 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -35,7 +35,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" #include "conf/network_conf.h" virNetworkPtr diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index 974e495..f9517cc 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -35,7 +35,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" #include "conf/node_device_conf.h" /* diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index 1480d13..9341ea7 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -35,7 +35,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd, diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index b3177e0..adac7f1 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -35,7 +35,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" #include "conf/storage_conf.h" virStoragePoolPtr diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index a29454f..8297743 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -36,7 +36,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virutil.h" -#include "xml.h" +#include "virxml.h" static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index 8428282..3b179e2 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -38,7 +38,7 @@ #include "viralloc.h" #include "virutil.h" #include "virsh-domain.h" -#include "xml.h" +#include "virxml.h" #include "conf/snapshot_conf.h" /* Helper for snapshot-create and snapshot-create-as */ diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 6f2c591..a57fc28 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -39,7 +39,7 @@ #include "virutil.h" #include "virfile.h" #include "virsh-pool.h" -#include "xml.h" +#include "virxml.h" virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, diff --git a/tools/virsh.c b/tools/virsh.c index bfeaaa1..790cf56 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -60,7 +60,7 @@ #include "console.h" #include "virutil.h" #include "viralloc.h" -#include "xml.h" +#include "virxml.h" #include "libvirt/libvirt-qemu.h" #include "virfile.h" #include "configmake.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- cfg.mk | 2 +- daemon/libvirtd-config.c | 2 +- daemon/libvirtd.c | 2 +- daemon/remote.c | 2 +- daemon/stream.c | 2 +- docs/Makefile.am | 2 +- po/POTFILES.in | 4 +- src/Makefile.am | 2 +- src/conf/capabilities.c | 2 +- src/conf/cpu_conf.c | 2 +- src/conf/device_conf.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_event.c | 2 +- src/conf/interface_conf.c | 2 +- src/conf/netdev_bandwidth_conf.c | 2 +- src/conf/netdev_vlan_conf.c | 2 +- src/conf/netdev_vport_profile_conf.c | 2 +- src/conf/network_conf.c | 2 +- src/conf/node_device_conf.c | 2 +- src/conf/nwfilter_conf.c | 2 +- src/conf/nwfilter_ipaddrmap.c | 2 +- src/conf/nwfilter_params.c | 2 +- src/conf/secret_conf.c | 2 +- src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_encryption_conf.c | 2 +- src/conf/virconsole.c | 2 +- src/cpu/cpu.h | 2 +- src/datatypes.c | 2 +- src/esx/esx_private.h | 2 +- src/esx/esx_vi.h | 2 +- src/fdstream.c | 2 +- src/hyperv/hyperv_device_monitor.c | 2 +- src/hyperv/hyperv_interface_driver.c | 2 +- src/hyperv/hyperv_network_driver.c | 2 +- src/hyperv/hyperv_nwfilter_driver.c | 2 +- src/hyperv/hyperv_private.h | 2 +- src/hyperv/hyperv_secret_driver.c | 2 +- src/hyperv/hyperv_storage_driver.c | 2 +- src/hyperv/hyperv_wmi.c | 2 +- src/interface/interface_backend_netcf.c | 2 +- src/interface/interface_backend_udev.c | 2 +- src/libvirt-qemu.c | 2 +- src/libvirt.c | 2 +- src/libxl/libxl_conf.c | 2 +- src/libxl/libxl_driver.c | 2 +- src/locking/domain_lock.c | 2 +- src/locking/lock_daemon.c | 2 +- src/locking/lock_daemon_config.c | 2 +- src/locking/lock_daemon_dispatch.c | 2 +- src/locking/lock_driver_lockd.c | 2 +- src/locking/lock_driver_sanlock.c | 2 +- src/locking/lock_manager.c | 2 +- src/lxc/lxc_cgroup.c | 2 +- src/lxc/lxc_conf.c | 2 +- src/lxc/lxc_container.c | 2 +- src/lxc/lxc_controller.c | 2 +- src/lxc/lxc_domain.c | 2 +- src/lxc/lxc_driver.c | 2 +- src/lxc/lxc_fuse.c | 2 +- src/lxc/lxc_monitor.c | 2 +- src/lxc/lxc_process.c | 2 +- src/network/bridge_driver.c | 2 +- src/node_device/node_device_driver.c | 2 +- src/node_device/node_device_hal.c | 2 +- src/node_device/node_device_linux_sysfs.c | 2 +- src/node_device/node_device_udev.c | 2 +- src/nodeinfo.c | 2 +- src/nwfilter/nwfilter_dhcpsnoop.c | 2 +- src/nwfilter/nwfilter_driver.c | 2 +- src/nwfilter/nwfilter_ebiptables_driver.c | 2 +- src/nwfilter/nwfilter_gentech_driver.c | 2 +- src/nwfilter/nwfilter_learnipaddr.c | 2 +- src/openvz/openvz_conf.c | 2 +- src/openvz/openvz_driver.c | 2 +- src/openvz/openvz_util.c | 2 +- src/parallels/parallels_driver.c | 2 +- src/parallels/parallels_network.c | 2 +- src/parallels/parallels_storage.c | 2 +- src/parallels/parallels_utils.c | 2 +- src/phyp/phyp_driver.c | 2 +- src/qemu/qemu_agent.c | 2 +- src/qemu/qemu_bridge_filter.c | 2 +- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_cgroup.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_conf.c | 2 +- src/qemu/qemu_domain.c | 2 +- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hostdev.c | 2 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_monitor.c | 2 +- src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_text.c | 2 +- src/qemu/qemu_process.c | 2 +- src/remote/remote_driver.c | 2 +- src/rpc/virkeepalive.c | 2 +- src/rpc/virnetclient.c | 2 +- src/rpc/virnetclientprogram.c | 2 +- src/rpc/virnetclientstream.c | 2 +- src/rpc/virnetmessage.c | 2 +- src/rpc/virnetsaslcontext.c | 2 +- src/rpc/virnetserver.c | 2 +- src/rpc/virnetserverclient.c | 2 +- src/rpc/virnetservermdns.c | 2 +- src/rpc/virnetserverprogram.c | 2 +- src/rpc/virnetserverservice.c | 2 +- src/rpc/virnetsocket.c | 2 +- src/rpc/virnetsshsession.c | 2 +- src/rpc/virnettlscontext.c | 2 +- src/secret/secret_driver.c | 2 +- src/security/security_apparmor.c | 2 +- src/security/security_dac.c | 2 +- src/security/security_driver.c | 2 +- src/security/security_manager.c | 2 +- src/security/security_nop.c | 2 +- src/security/security_selinux.c | 2 +- src/security/security_stack.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_disk.c | 2 +- src/storage/storage_backend_fs.c | 2 +- src/storage/storage_backend_iscsi.c | 2 +- src/storage/storage_backend_logical.c | 2 +- src/storage/storage_backend_mpath.c | 2 +- src/storage/storage_backend_rbd.c | 2 +- src/storage/storage_backend_scsi.c | 2 +- src/storage/storage_backend_sheepdog.c | 2 +- src/storage/storage_driver.c | 2 +- src/test/test_driver.c | 2 +- src/uml/uml_conf.h | 2 +- src/util/iohelper.c | 2 +- src/util/viraudit.c | 2 +- src/util/virauth.c | 2 +- src/util/virauthconfig.c | 2 +- src/util/vircommand.c | 2 +- src/util/virconf.c | 2 +- src/util/virdbus.c | 2 +- src/util/virdnsmasq.c | 2 +- src/util/virebtables.c | 2 +- src/util/virerror.c | 1369 +++++++++++++++++++++++++++++ src/util/virerror.h | 167 ++++ src/util/virevent.c | 2 +- src/util/vireventpoll.c | 2 +- src/util/virfile.c | 2 +- src/util/virhash.c | 2 +- src/util/virhooks.c | 2 +- src/util/virinitctl.c | 2 +- src/util/viriptables.c | 2 +- src/util/virjson.c | 2 +- src/util/virkeyfile.c | 2 +- src/util/virlockspace.c | 2 +- src/util/virlog.c | 2 +- src/util/virnetdev.c | 2 +- src/util/virnetdevbandwidth.c | 2 +- src/util/virnetdevbridge.c | 2 +- src/util/virnetdevmacvlan.c | 2 +- src/util/virnetdevopenvswitch.c | 2 +- src/util/virnetdevtap.c | 4 +- src/util/virnetdevveth.c | 2 +- src/util/virnetdevvlan.c | 2 +- src/util/virnetdevvportprofile.c | 2 +- src/util/virnetlink.c | 2 +- src/util/virnodesuspend.c | 2 +- src/util/virobject.c | 2 +- src/util/virpci.c | 2 +- src/util/virpidfile.c | 2 +- src/util/virprocess.c | 2 +- src/util/virrandom.c | 2 +- src/util/virsexpr.c | 2 +- src/util/virsocketaddr.c | 2 +- src/util/virstatslinux.c | 2 +- src/util/virstoragefile.c | 2 +- src/util/virstring.c | 2 +- src/util/virsysinfo.c | 2 +- src/util/virterror.c | 1369 ----------------------------- src/util/virterror_internal.h | 167 ---- src/util/virthreadpool.c | 2 +- src/util/virtime.c | 2 +- src/util/virtypedparam.c | 2 +- src/util/viruri.c | 2 +- src/util/virusb.c | 2 +- src/util/virutil.c | 2 +- src/util/viruuid.c | 2 +- src/util/virxml.c | 2 +- src/vbox/vbox_MSCOMGlue.c | 2 +- src/vbox/vbox_XPCOMCGlue.c | 2 +- src/vbox/vbox_driver.c | 2 +- src/vbox/vbox_tmpl.c | 2 +- src/vmware/vmware_conf.c | 2 +- src/vmware/vmware_driver.c | 2 +- src/vmx/vmx.c | 2 +- src/xen/block_stats.c | 2 +- src/xen/xen_driver.c | 2 +- src/xen/xen_hypervisor.c | 2 +- src/xen/xen_inotify.c | 2 +- src/xen/xend_internal.c | 2 +- src/xen/xm_internal.c | 2 +- src/xen/xs_internal.c | 2 +- src/xenapi/xenapi_driver.c | 2 +- src/xenapi/xenapi_driver_private.h | 2 +- src/xenapi/xenapi_utils.c | 2 +- src/xenxs/xen_sxpr.c | 2 +- src/xenxs/xen_xm.c | 2 +- tests/commandtest.c | 2 +- tests/libvirtdconftest.c | 2 +- tests/qemumonitorjsontest.c | 2 +- tests/qemumonitortestutils.c | 2 +- tests/securityselinuxtest.c | 2 +- tests/testutils.c | 2 +- tests/virauthconfigtest.c | 2 +- tests/virdrivermoduletest.c | 2 +- tests/virkeyfiletest.c | 2 +- tests/virlockspacetest.c | 2 +- tests/virnetmessagetest.c | 2 +- tests/virnetsockettest.c | 2 +- tests/virnettlscontexttest.c | 2 +- tests/virstringtest.c | 2 +- tests/virtimetest.c | 2 +- tests/viruritest.c | 2 +- tools/console.c | 2 +- tools/virsh-domain.c | 2 +- tools/virsh.c | 2 +- tools/virsh.h | 2 +- 224 files changed, 1758 insertions(+), 1758 deletions(-) create mode 100644 src/util/virerror.c create mode 100644 src/util/virerror.h delete mode 100644 src/util/virterror.c delete mode 100644 src/util/virterror_internal.h diff --git a/cfg.mk b/cfg.mk index 2fcb444..26147bd 100644 --- a/cfg.mk +++ b/cfg.mk @@ -762,7 +762,7 @@ exclude_file_name_regexp--sc_libvirt_unmarked_diagnostics = \ exclude_file_name_regexp--sc_po_check = ^(docs/|src/rpc/gendispatch\.pl$$) exclude_file_name_regexp--sc_prohibit_VIR_ERR_NO_MEMORY = \ - ^(include/libvirt/virterror\.h|daemon/dispatch\.c|src/util/virterror\.c)$$ + ^(include/libvirt/virterror\.h|daemon/dispatch\.c|src/util/virerror\.c)$$ exclude_file_name_regexp--sc_prohibit_access_xok = ^src/util/virutil\.c$$ diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index b979a23..8b74bf1 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -26,7 +26,7 @@ #include "libvirtd-config.h" #include "virconf.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "rpc/virnetserver.h" #include "configmake.h" diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 560746f..f2a3036 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -33,7 +33,7 @@ #include <locale.h> #include "libvirt_internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" diff --git a/daemon/remote.c b/daemon/remote.c index 1a054d5..817d5ed 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -22,7 +22,7 @@ #include <config.h> -#include "virterror_internal.h" +#include "virerror.h" #if HAVE_POLKIT0 # include <polkit/polkit.h> diff --git a/daemon/stream.c b/daemon/stream.c index f208139..4df1145 100644 --- a/daemon/stream.c +++ b/daemon/stream.c @@ -28,7 +28,7 @@ #include "viralloc.h" #include "virlog.h" #include "virnetserverclient.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_STREAMS diff --git a/docs/Makefile.am b/docs/Makefile.am index 4fea3a0..cba9d4b 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -239,7 +239,7 @@ $(APIBUILD_STAMP): $(srcdir)/apibuild.py \ $(srcdir)/../include/libvirt/virterror.h \ $(srcdir)/../src/libvirt.c \ $(srcdir)/../src/libvirt-qemu.c \ - $(srcdir)/../src/util/virterror.c + $(srcdir)/../src/util/virerror.c $(AM_V_GEN)srcdir=$(srcdir) $(PYTHON) $(APIBUILD) touch $@ diff --git a/po/POTFILES.in b/po/POTFILES.in index 1afdca5..c79aa73 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -173,8 +173,8 @@ src/util/virsocketaddr.c src/util/virstatslinux.c src/util/virstoragefile.c src/util/virsysinfo.c -src/util/virterror.c -src/util/virterror_internal.h +src/util/virerror.c +src/util/virerror.h src/util/virtime.c src/util/virtypedparam.c src/util/viruri.c diff --git a/src/Makefile.am b/src/Makefile.am index dddd162..0c77062 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,6 +64,7 @@ UTIL_SOURCES = \ util/virconf.c util/virconf.h \ util/virdnsmasq.c util/virdnsmasq.h \ util/virebtables.c util/virebtables.h \ + util/virerror.c util/virerror.h \ util/virevent.c util/virevent.h \ util/vireventpoll.c util/vireventpoll.h \ util/virfile.c util/virfile.h \ @@ -85,7 +86,6 @@ UTIL_SOURCES = \ util/virthreadwin32.h \ util/virthreadpool.c util/virthreadpool.h \ util/virtypedparam.c util/virtypedparam.h \ - util/virterror.c util/virterror_internal.h \ util/vircgroup.c util/vircgroup.h \ util/virdbus.c util/virdbus.h \ util/virhash.c util/virhash.h \ diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c index f6badcc..e6cb2a6 100644 --- a/src/conf/capabilities.c +++ b/src/conf/capabilities.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "viruuid.h" #include "cpu_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_CAPABILITIES diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 95c6ca1..7acf327 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -23,7 +23,7 @@ #include <config.h> -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virutil.h" #include "virbuffer.h" diff --git a/src/conf/device_conf.c b/src/conf/device_conf.c index 45ecb28..099b1cb 100644 --- a/src/conf/device_conf.c +++ b/src/conf/device_conf.c @@ -21,7 +21,7 @@ */ #include <config.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "viralloc.h" #include "virxml.h" diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a4f33ed..db4b274 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -30,7 +30,7 @@ #include <unistd.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "domain_conf.h" #include "snapshot_conf.h" diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index d523808..96a07ac 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -27,7 +27,7 @@ #include "virlog.h" #include "datatypes.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/conf/interface_conf.c b/src/conf/interface_conf.c index 3867274..9301ec0 100644 --- a/src/conf/interface_conf.c +++ b/src/conf/interface_conf.c @@ -22,7 +22,7 @@ */ #include <config.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "interface_conf.h" diff --git a/src/conf/netdev_bandwidth_conf.c b/src/conf/netdev_bandwidth_conf.c index e64aeff..b830cd0 100644 --- a/src/conf/netdev_bandwidth_conf.c +++ b/src/conf/netdev_bandwidth_conf.c @@ -23,7 +23,7 @@ #include <config.h> #include "netdev_bandwidth_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "viralloc.h" #include "domain_conf.h" diff --git a/src/conf/netdev_vlan_conf.c b/src/conf/netdev_vlan_conf.c index 8cee025..9207184 100644 --- a/src/conf/netdev_vlan_conf.c +++ b/src/conf/netdev_vlan_conf.c @@ -22,7 +22,7 @@ #include <config.h> #include "netdev_vlan_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/conf/netdev_vport_profile_conf.c b/src/conf/netdev_vport_profile_conf.c index a9a38d7..701e17e 100644 --- a/src/conf/netdev_vport_profile_conf.c +++ b/src/conf/netdev_vport_profile_conf.c @@ -23,7 +23,7 @@ #include <config.h> #include "netdev_vport_profile_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 2bd04c5..f949f79 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -31,7 +31,7 @@ #include <string.h> #include <dirent.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "network_conf.h" #include "netdev_vport_profile_conf.h" diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c index 3c68011..53b6af2 100644 --- a/src/conf/node_device_conf.c +++ b/src/conf/node_device_conf.c @@ -26,7 +26,7 @@ #include <unistd.h> #include <errno.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "viralloc.h" diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c index 810de6c..ca22411 100644 --- a/src/conf/nwfilter_conf.c +++ b/src/conf/nwfilter_conf.c @@ -40,7 +40,7 @@ #include "viruuid.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "nwfilter_params.h" #include "nwfilter_conf.h" diff --git a/src/conf/nwfilter_ipaddrmap.c b/src/conf/nwfilter_ipaddrmap.c index ddad49e..317069d 100644 --- a/src/conf/nwfilter_ipaddrmap.c +++ b/src/conf/nwfilter_ipaddrmap.c @@ -26,7 +26,7 @@ #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "nwfilter_params.h" #include "nwfilter_ipaddrmap.h" diff --git a/src/conf/nwfilter_params.c b/src/conf/nwfilter_params.c index 1429952..7aebc8d 100644 --- a/src/conf/nwfilter_params.c +++ b/src/conf/nwfilter_params.c @@ -26,7 +26,7 @@ #include "internal.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "nwfilter_params.h" #include "domain_conf.h" diff --git a/src/conf/secret_conf.c b/src/conf/secret_conf.c index 46d2ae5..891af65 100644 --- a/src/conf/secret_conf.c +++ b/src/conf/secret_conf.c @@ -28,7 +28,7 @@ #include "virlog.h" #include "viralloc.h" #include "secret_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "virxml.h" #include "viruuid.h" diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index f7f8f63..201c586 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -45,7 +45,7 @@ #include "virutil.h" #include "viruuid.h" #include "virfile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virxml.h" #define VIR_FROM_THIS VIR_FROM_DOMAIN_SNAPSHOT diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 04b2581..7a39998 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -33,7 +33,7 @@ #include <fcntl.h> #include <string.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "storage_conf.h" #include "virstoragefile.h" diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 35e9da4..88dff1b 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -33,7 +33,7 @@ #include "storage_encryption_conf.h" #include "virutil.h" #include "virxml.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viruuid.h" #include "virfile.h" diff --git a/src/conf/virconsole.c b/src/conf/virconsole.c index 515c5fa..239e2d2 100644 --- a/src/conf/virconsole.c +++ b/src/conf/virconsole.c @@ -35,7 +35,7 @@ #include "viralloc.h" #include "virpidfile.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virfile.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 01c732c..a00a469 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -24,7 +24,7 @@ #ifndef __VIR_CPU_H__ # define __VIR_CPU_H__ -# include "virterror_internal.h" +# include "virerror.h" # include "datatypes.h" # include "conf/cpu_conf.h" # include "cpu_x86_data.h" diff --git a/src/datatypes.c b/src/datatypes.c index 038c47d..068233c 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -23,7 +23,7 @@ #include <unistd.h> #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "viralloc.h" #include "viruuid.h" diff --git a/src/esx/esx_private.h b/src/esx/esx_private.h index de6ba5d..f1e7adf 100644 --- a/src/esx/esx_private.h +++ b/src/esx/esx_private.h @@ -24,7 +24,7 @@ # define __ESX_PRIVATE_H__ # include "internal.h" -# include "virterror_internal.h" +# include "virerror.h" # include "capabilities.h" # include "esx_vi.h" diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h index a121d1c..3eaeb38 100644 --- a/src/esx/esx_vi.h +++ b/src/esx/esx_vi.h @@ -29,7 +29,7 @@ # include <curl/curl.h> # include "internal.h" -# include "virterror_internal.h" +# include "virerror.h" # include "datatypes.h" # include "esx_vi_types.h" # include "esx_util.h" diff --git a/src/fdstream.c b/src/fdstream.c index f7f101e..cc2dfe9 100644 --- a/src/fdstream.c +++ b/src/fdstream.c @@ -33,7 +33,7 @@ #include <netinet/in.h> #include "fdstream.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virlog.h" #include "viralloc.h" diff --git a/src/hyperv/hyperv_device_monitor.c b/src/hyperv/hyperv_device_monitor.c index 43ee1fc..9432081 100644 --- a/src/hyperv/hyperv_device_monitor.c +++ b/src/hyperv/hyperv_device_monitor.c @@ -24,7 +24,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/hyperv/hyperv_interface_driver.c b/src/hyperv/hyperv_interface_driver.c index 7dd6912..b42dbce 100644 --- a/src/hyperv/hyperv_interface_driver.c +++ b/src/hyperv/hyperv_interface_driver.c @@ -24,7 +24,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/hyperv/hyperv_network_driver.c b/src/hyperv/hyperv_network_driver.c index f34a451..c75c943 100644 --- a/src/hyperv/hyperv_network_driver.c +++ b/src/hyperv/hyperv_network_driver.c @@ -24,7 +24,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/hyperv/hyperv_nwfilter_driver.c b/src/hyperv/hyperv_nwfilter_driver.c index c6125ec..faa9074 100644 --- a/src/hyperv/hyperv_nwfilter_driver.c +++ b/src/hyperv/hyperv_nwfilter_driver.c @@ -24,7 +24,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/hyperv/hyperv_private.h b/src/hyperv/hyperv_private.h index 30051ea..9c9fd3e 100644 --- a/src/hyperv/hyperv_private.h +++ b/src/hyperv/hyperv_private.h @@ -25,7 +25,7 @@ # define __HYPERV_PRIVATE_H__ # include "internal.h" -# include "virterror_internal.h" +# include "virerror.h" # include "hyperv_util.h" # include "openwsman.h" diff --git a/src/hyperv/hyperv_secret_driver.c b/src/hyperv/hyperv_secret_driver.c index b830e4e..602ae99 100644 --- a/src/hyperv/hyperv_secret_driver.c +++ b/src/hyperv/hyperv_secret_driver.c @@ -24,7 +24,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/hyperv/hyperv_storage_driver.c b/src/hyperv/hyperv_storage_driver.c index 38385a0..a169b14 100644 --- a/src/hyperv/hyperv_storage_driver.c +++ b/src/hyperv/hyperv_storage_driver.c @@ -24,7 +24,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index e029028..33ba21f 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -25,7 +25,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virlog.h" #include "viralloc.h" diff --git a/src/interface/interface_backend_netcf.c b/src/interface/interface_backend_netcf.c index 74a749b..35335c2 100644 --- a/src/interface/interface_backend_netcf.c +++ b/src/interface/interface_backend_netcf.c @@ -25,7 +25,7 @@ #include <netcf.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "interface_driver.h" #include "interface_conf.h" diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c index 248b02e..cc20b98 100644 --- a/src/interface/interface_backend_udev.c +++ b/src/interface/interface_backend_udev.c @@ -23,7 +23,7 @@ #include <dirent.h> #include <libudev.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "interface_driver.h" #include "interface_conf.h" diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c index 8d53b5c..11da2f3 100644 --- a/src/libvirt-qemu.c +++ b/src/libvirt-qemu.c @@ -23,7 +23,7 @@ #include <config.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "libvirt/libvirt-qemu.h" diff --git a/src/libvirt.c b/src/libvirt.c index e06b643..bf674d1 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -45,7 +45,7 @@ # include <curl/curl.h> #endif -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "driver.h" diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index aad1374..15d2271 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virfile.h" #include "virstring.h" diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index 76afe34..db821c5 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -33,7 +33,7 @@ #include "internal.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virconf.h" #include "datatypes.h" #include "virfile.h" diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c index 0354e26..6191e9b 100644 --- a/src/locking/domain_lock.c +++ b/src/locking/domain_lock.c @@ -24,7 +24,7 @@ #include "domain_lock.h" #include "viralloc.h" #include "viruuid.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_LOCKING diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index a445b2e..7288f7a 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -37,7 +37,7 @@ #include "virfile.h" #include "virpidfile.h" #include "virprocess.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "viralloc.h" #include "virconf.h" diff --git a/src/locking/lock_daemon_config.c b/src/locking/lock_daemon_config.c index e370dd4..12b06e2 100644 --- a/src/locking/lock_daemon_config.c +++ b/src/locking/lock_daemon_config.c @@ -26,7 +26,7 @@ #include "lock_daemon_config.h" #include "virconf.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "rpc/virnetserver.h" #include "configmake.h" diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c index def7c2f..45d2cae 100644 --- a/src/locking/lock_daemon_dispatch.c +++ b/src/locking/lock_daemon_dispatch.c @@ -30,7 +30,7 @@ #include "lock_daemon.h" #include "lock_protocol.h" #include "lock_daemon_dispatch_stubs.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index 9c7ce6d..4b72a05 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -28,7 +28,7 @@ #include "viruuid.h" #include "virutil.h" #include "virfile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "rpc/virnetclient.h" #include "lock_protocol.h" #include "configmake.h" diff --git a/src/locking/lock_driver_sanlock.c b/src/locking/lock_driver_sanlock.c index 511543a..75ced84 100644 --- a/src/locking/lock_driver_sanlock.c +++ b/src/locking/lock_driver_sanlock.c @@ -38,7 +38,7 @@ #include "dirname.h" #include "lock_driver.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virutil.h" #include "virfile.h" diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c index 1b88838..ae60caf 100644 --- a/src/locking/lock_manager.c +++ b/src/locking/lock_manager.c @@ -23,7 +23,7 @@ #include "lock_manager.h" #include "lock_driver_nop.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 5d1f7ff..a490551 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -24,7 +24,7 @@ #include "lxc_cgroup.h" #include "lxc_container.h" #include "virfile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "viralloc.h" #include "vircgroup.h" diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 36c49d0..689215a 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -30,7 +30,7 @@ #include "lxc_conf.h" #include "nodeinfo.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virconf.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 57c432a..655b610 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -53,7 +53,7 @@ # include <blkid/blkid.h> #endif -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "lxc_container.h" #include "virutil.h" diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index a8e99f2..5517f68 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -52,7 +52,7 @@ # include <numa.h> #endif -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virutil.h" diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index fab1506..1b02aa5 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -25,7 +25,7 @@ #include "viralloc.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_LXC diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 42c6f80..bdd4fba 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -35,7 +35,7 @@ #include <unistd.h> #include <wait.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "lxc_conf.h" diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c index 485456e..fdba042 100644 --- a/src/lxc/lxc_fuse.c +++ b/src/lxc/lxc_fuse.c @@ -31,7 +31,7 @@ #include "lxc_fuse.h" #include "lxc_cgroup.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virfile.h" #include "virbuffer.h" diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c index b0da21f..65194a5 100644 --- a/src/lxc/lxc_monitor.c +++ b/src/lxc/lxc_monitor.c @@ -27,7 +27,7 @@ #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virthread.h" #include "rpc/virnetclient.h" diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index af14f6a..57d1ae8 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -40,7 +40,7 @@ #include "network/bridge_driver.h" #include "viralloc.h" #include "domain_audit.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "vircommand.h" #include "virhooks.h" diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 953e571..9ea09c7 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -44,7 +44,7 @@ #include <sys/ioctl.h> #include <net/if.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "bridge_driver.h" #include "network_conf.h" diff --git a/src/node_device/node_device_driver.c b/src/node_device/node_device_driver.c index 6cc1837..522af99 100644 --- a/src/node_device/node_device_driver.c +++ b/src/node_device/node_device_driver.c @@ -30,7 +30,7 @@ #include <time.h> #include <sys/stat.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/node_device/node_device_hal.c b/src/node_device/node_device_hal.c index 8ee816b..610df8d 100644 --- a/src/node_device/node_device_hal.c +++ b/src/node_device/node_device_hal.c @@ -30,7 +30,7 @@ #include "node_device_conf.h" #include "node_device_hal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "driver.h" #include "datatypes.h" #include "viralloc.h" diff --git a/src/node_device/node_device_linux_sysfs.c b/src/node_device/node_device_linux_sysfs.c index be5d3ed..9c305d3 100644 --- a/src/node_device/node_device_linux_sysfs.c +++ b/src/node_device/node_device_linux_sysfs.c @@ -28,7 +28,7 @@ #include "node_device_driver.h" #include "node_device_hal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c index 61e5a0e..a9b30b2 100644 --- a/src/node_device/node_device_udev.c +++ b/src/node_device/node_device_udev.c @@ -27,7 +27,7 @@ #include <c-ctype.h> #include "node_device_udev.h" -#include "virterror_internal.h" +#include "virerror.h" #include "node_device_conf.h" #include "node_device_driver.h" #include "driver.h" diff --git a/src/nodeinfo.c b/src/nodeinfo.c index 65f4431..9cde01a 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -44,7 +44,7 @@ #include "physmem.h" #include "virutil.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "count-one-bits.h" #include "intprops.h" #include "virfile.h" diff --git a/src/nwfilter/nwfilter_dhcpsnoop.c b/src/nwfilter/nwfilter_dhcpsnoop.c index c1ab622..90b5615 100644 --- a/src/nwfilter/nwfilter_dhcpsnoop.c +++ b/src/nwfilter/nwfilter_dhcpsnoop.c @@ -57,7 +57,7 @@ #include "viralloc.h" #include "virlog.h" #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "conf/domain_conf.h" #include "nwfilter_gentech_driver.h" #include "nwfilter_dhcpsnoop.h" diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c index 4b1188d..1ac91cf 100644 --- a/src/nwfilter/nwfilter_driver.c +++ b/src/nwfilter/nwfilter_driver.c @@ -32,7 +32,7 @@ #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "viralloc.h" #include "domain_conf.h" diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index 092ae5a..4fec52d 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -33,7 +33,7 @@ #include "virbuffer.h" #include "viralloc.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "domain_conf.h" #include "nwfilter_conf.h" #include "nwfilter_driver.h" diff --git a/src/nwfilter/nwfilter_gentech_driver.c b/src/nwfilter/nwfilter_gentech_driver.c index 2b4cc8e..086bb13 100644 --- a/src/nwfilter/nwfilter_gentech_driver.c +++ b/src/nwfilter/nwfilter_gentech_driver.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "virlog.h" #include "domain_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "nwfilter_gentech_driver.h" #include "nwfilter_ebiptables_driver.h" #include "nwfilter_dhcpsnoop.h" diff --git a/src/nwfilter/nwfilter_learnipaddr.c b/src/nwfilter/nwfilter_learnipaddr.c index 442cc83..7a4f983 100644 --- a/src/nwfilter/nwfilter_learnipaddr.c +++ b/src/nwfilter/nwfilter_learnipaddr.c @@ -46,7 +46,7 @@ #include "virlog.h" #include "datatypes.h" #include "virnetdev.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virthread.h" #include "conf/nwfilter_params.h" #include "conf/domain_conf.h" diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 35f5c97..f208753 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -43,7 +43,7 @@ #include <sys/utsname.h> #include <sys/wait.h> -#include "virterror_internal.h" +#include "virerror.h" #include "openvz_conf.h" #include "openvz_util.h" #include "viruuid.h" diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index a407193..17c44a3 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -45,7 +45,7 @@ #include <stdio.h> #include <sys/wait.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "openvz_driver.h" #include "openvz_util.h" diff --git a/src/openvz/openvz_util.c b/src/openvz/openvz_util.c index 51b22c9..dc69df2 100644 --- a/src/openvz/openvz_util.c +++ b/src/openvz/openvz_util.c @@ -25,7 +25,7 @@ #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "vircommand.h" #include "datatypes.h" #include "viralloc.h" diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 87d098e..cf7db2e 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -42,7 +42,7 @@ #include <sys/statvfs.h> #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virutil.h" #include "virlog.h" diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index 4729f18..c5ece79 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -24,7 +24,7 @@ #include "datatypes.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "md5.h" #include "parallels_utils.h" diff --git a/src/parallels/parallels_storage.c b/src/parallels/parallels_storage.c index 0e6c100..e768d88 100644 --- a/src/parallels/parallels_storage.c +++ b/src/parallels/parallels_storage.c @@ -34,7 +34,7 @@ #include "viralloc.h" #include "configmake.h" #include "virstoragefile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "parallels_utils.h" diff --git a/src/parallels/parallels_utils.c b/src/parallels/parallels_utils.c index 9e317b1..dd2f0b7 100644 --- a/src/parallels/parallels_utils.c +++ b/src/parallels/parallels_utils.c @@ -25,7 +25,7 @@ #include <stdarg.h> #include "vircommand.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virjson.h" diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index cd1911e..4333c90 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -52,7 +52,7 @@ #include "virlog.h" #include "driver.h" #include "libvirt/libvirt.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viruuid.h" #include "domain_conf.h" #include "storage_conf.h" diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index ec1e300..bb421bd 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -36,7 +36,7 @@ #include "qemu_command.h" #include "viralloc.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virjson.h" #include "virfile.h" #include "virprocess.h" diff --git a/src/qemu/qemu_bridge_filter.c b/src/qemu/qemu_bridge_filter.c index 6d84f47..3bc1141 100644 --- a/src/qemu/qemu_bridge_filter.c +++ b/src/qemu/qemu_bridge_filter.c @@ -26,7 +26,7 @@ #include "qemu_conf.h" #include "qemu_driver.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "qemu_bridge_filter.h" diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7a27183..f4de93b 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -26,7 +26,7 @@ #include "qemu_capabilities.h" #include "viralloc.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "virfile.h" #include "virpidfile.h" diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c index 9db7ad9..4fe98e9 100644 --- a/src/qemu/qemu_cgroup.c +++ b/src/qemu/qemu_cgroup.c @@ -29,7 +29,7 @@ #include "vircgroup.h" #include "virlog.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "domain_audit.h" diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 79e5faa..8afe31b 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -30,7 +30,7 @@ #include "cpu/cpu.h" #include "viralloc.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "virfile.h" #include "viruuid.h" diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 56c93a8..eb0a479 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -35,7 +35,7 @@ #include <arpa/inet.h> #include <sys/utsname.h> -#include "virterror_internal.h" +#include "virerror.h" #include "qemu_conf.h" #include "qemu_command.h" #include "qemu_capabilities.h" diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 46b7656..5d11f83 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -29,7 +29,7 @@ #include "qemu_migration.h" #include "viralloc.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "c-ctype.h" #include "cpu/cpu.h" #include "viruuid.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d24527b..c7cbfbf 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -59,7 +59,7 @@ #include "qemu_process.h" #include "qemu_migration.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "virbuffer.h" diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 5c23ccb..c7d4987 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -25,7 +25,7 @@ #include "qemu_hostdev.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virpci.h" #include "virusb.h" diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e5b28da..8de108d 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -34,7 +34,7 @@ #include "domain_nwfilter.h" #include "virlog.h" #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virpci.h" #include "virfile.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index afe2374..b2c412d 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -37,7 +37,7 @@ #include "domain_audit.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virutil.h" #include "virfile.h" diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 5ca1f89..99642b6 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -31,7 +31,7 @@ #include "qemu_monitor.h" #include "qemu_monitor_text.h" #include "qemu_monitor_json.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 0137291..2d2d254 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -39,7 +39,7 @@ #include "virlog.h" #include "driver.h" #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virjson.h" #ifdef WITH_DTRACE_PROBES diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 82e9108..6506f9d 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -38,7 +38,7 @@ #include "virlog.h" #include "driver.h" #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virbuffer.h" #ifdef WITH_DTRACE_PROBES diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 5ffc5a5..1d5200f 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -52,7 +52,7 @@ #include "datatypes.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virhooks.h" #include "virfile.h" diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ac7dc87..ae861cc 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -29,7 +29,7 @@ #include "virnetclient.h" #include "virnetclientprogram.h" #include "virnetclientstream.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "domain_event.h" diff --git a/src/rpc/virkeepalive.c b/src/rpc/virkeepalive.c index 18be350..a8ceff5 100644 --- a/src/rpc/virkeepalive.c +++ b/src/rpc/virkeepalive.c @@ -27,7 +27,7 @@ #include "virfile.h" #include "virlog.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virnetsocket.h" #include "virkeepaliveprotocol.h" #include "virkeepalive.h" diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 9347f0b..208e2e9 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -35,7 +35,7 @@ #include "virfile.h" #include "virlog.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c index eff4a4c..a179b8d 100644 --- a/src/rpc/virnetclientprogram.c +++ b/src/rpc/virnetclientprogram.c @@ -29,7 +29,7 @@ #include "virnetprotocol.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virutil.h" #include "virfile.h" diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c index 7e1f9c7..15ed91a 100644 --- a/src/rpc/virnetclientstream.c +++ b/src/rpc/virnetclientstream.c @@ -25,7 +25,7 @@ #include "virnetclientstream.h" #include "virnetclient.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virthread.h" diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c index b2da65b..b7330de 100644 --- a/src/rpc/virnetmessage.c +++ b/src/rpc/virnetmessage.c @@ -25,7 +25,7 @@ #include "virnetmessage.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virfile.h" #include "virutil.h" diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c index cd30f4d..cbf7261 100644 --- a/src/rpc/virnetsaslcontext.c +++ b/src/rpc/virnetsaslcontext.c @@ -25,7 +25,7 @@ #include "virnetsaslcontext.h" #include "virnetmessage.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virthread.h" #include "virlog.h" diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 47a6293..5674309 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -30,7 +30,7 @@ #include "virnetserver.h" #include "virlog.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virthread.h" #include "virthreadpool.h" #include "virutil.h" diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index f1eb69b..aefc511 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -30,7 +30,7 @@ #include "virnetserverclient.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virthread.h" #include "virkeepalive.h" diff --git a/src/rpc/virnetservermdns.c b/src/rpc/virnetservermdns.c index daef2b4..b6f8e8e 100644 --- a/src/rpc/virnetservermdns.c +++ b/src/rpc/virnetservermdns.c @@ -43,7 +43,7 @@ #include "virnetservermdns.h" #include "vireventpoll.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c index a8f875c..3ac3809 100644 --- a/src/rpc/virnetserverprogram.c +++ b/src/rpc/virnetserverprogram.c @@ -27,7 +27,7 @@ #include "virnetserverclient.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virfile.h" #include "virthread.h" diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c index 9992983..7d671f0 100644 --- a/src/rpc/virnetserverservice.c +++ b/src/rpc/virnetserverservice.c @@ -26,7 +26,7 @@ #include "virnetserverservice.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virthread.h" #define VIR_FROM_THIS VIR_FROM_RPC diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index a959c30..ef93892 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -43,7 +43,7 @@ #include "virnetsocket.h" #include "virutil.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virfile.h" #include "virthread.h" diff --git a/src/rpc/virnetsshsession.c b/src/rpc/virnetsshsession.c index ad8bd48..661860f 100644 --- a/src/rpc/virnetsshsession.c +++ b/src/rpc/virnetsshsession.c @@ -32,7 +32,7 @@ #include "configmake.h" #include "virthread.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virobject.h" #define VIR_FROM_THIS VIR_FROM_SSH diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index b01de8c..56e372b 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -31,7 +31,7 @@ #include "virnettlscontext.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "virlog.h" #include "virthread.h" diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 1784fea..5be33b9 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -39,7 +39,7 @@ #include "virthread.h" #include "virutil.h" #include "viruuid.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virfile.h" #include "configmake.h" diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index ee96bac..edc81ac 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -40,7 +40,7 @@ #include "security_apparmor.h" #include "virutil.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "viruuid.h" #include "virpci.h" diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 3104f42..d0e1731 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -24,7 +24,7 @@ #include <fcntl.h> #include "security_dac.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/security/security_driver.c b/src/security/security_driver.c index 82d3ca9..319b86f 100644 --- a/src/security/security_driver.c +++ b/src/security/security_driver.c @@ -23,7 +23,7 @@ #include <config.h> #include <string.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "security_driver.h" diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 2da6244..960fcc9 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -26,7 +26,7 @@ #include "security_driver.h" #include "security_stack.h" #include "security_dac.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/security/security_nop.c b/src/security/security_nop.c index 5f3270a..61b8e83 100644 --- a/src/security/security_nop.c +++ b/src/security/security_nop.c @@ -21,7 +21,7 @@ #include "security_nop.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index ccba258..ae94ec3 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -33,7 +33,7 @@ #include "security_driver.h" #include "security_selinux.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/security/security_stack.c b/src/security/security_stack.c index 390bd3b..931d31d 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -22,7 +22,7 @@ #include "security_stack.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_SECURITY diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index f98a7c0..df79b28 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -46,7 +46,7 @@ #endif #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "viralloc.h" #include "internal.h" diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c index aceb82b..4214e97 100644 --- a/src/storage/storage_backend_disk.c +++ b/src/storage/storage_backend_disk.c @@ -26,7 +26,7 @@ #include <unistd.h> #include <stdio.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "storage_backend_disk.h" #include "virutil.h" diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 23fa0f5..2205371 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -41,7 +41,7 @@ # include <blkid/blkid.h> #endif -#include "virterror_internal.h" +#include "virerror.h" #include "storage_backend_fs.h" #include "storage_conf.h" #include "virstoragefile.h" diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index e91c4b1..f374961 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -34,7 +34,7 @@ #include <unistd.h> #include <sys/stat.h> -#include "virterror_internal.h" +#include "virerror.h" #include "storage_backend_scsi.h" #include "storage_backend_iscsi.h" #include "virutil.h" diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c index 83b517c..2734689 100644 --- a/src/storage/storage_backend_logical.c +++ b/src/storage/storage_backend_logical.c @@ -31,7 +31,7 @@ #include <unistd.h> #include <fcntl.h> -#include "virterror_internal.h" +#include "virerror.h" #include "storage_backend_logical.h" #include "storage_conf.h" #include "vircommand.h" diff --git a/src/storage/storage_backend_mpath.c b/src/storage/storage_backend_mpath.c index 0e5d032..b12b81f 100644 --- a/src/storage/storage_backend_mpath.c +++ b/src/storage/storage_backend_mpath.c @@ -29,7 +29,7 @@ #include <libdevmapper.h> -#include "virterror_internal.h" +#include "virerror.h" #include "storage_conf.h" #include "storage_backend.h" #include "viralloc.h" diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index 7dc46b0..f5c6b0f 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -22,7 +22,7 @@ #include <config.h> -#include "virterror_internal.h" +#include "virerror.h" #include "storage_backend_rbd.h" #include "storage_conf.h" #include "virutil.h" diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c index 1db8fdd..1a03c49 100644 --- a/src/storage/storage_backend_scsi.c +++ b/src/storage/storage_backend_scsi.c @@ -28,7 +28,7 @@ #include <dirent.h> #include <fcntl.h> -#include "virterror_internal.h" +#include "virerror.h" #include "storage_backend_scsi.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/storage/storage_backend_sheepdog.c b/src/storage/storage_backend_sheepdog.c index 1046ac9..cd18f33 100644 --- a/src/storage/storage_backend_sheepdog.c +++ b/src/storage/storage_backend_sheepdog.c @@ -26,7 +26,7 @@ #include <config.h> -#include "virterror_internal.h" +#include "virerror.h" #include "storage_backend_sheepdog.h" #include "storage_conf.h" #include "vircommand.h" diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index d93617c..ff56f4f 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -36,7 +36,7 @@ #include <errno.h> #include <string.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "driver.h" #include "virutil.h" diff --git a/src/test/test_driver.c b/src/test/test_driver.c index bd557d6..8518fd3 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -32,7 +32,7 @@ #include <libxml/xmlsave.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "test_driver.h" #include "virbuffer.h" diff --git a/src/uml/uml_conf.h b/src/uml/uml_conf.h index dfa168e..a4e264f 100644 --- a/src/uml/uml_conf.h +++ b/src/uml/uml_conf.h @@ -29,7 +29,7 @@ # include "network_conf.h" # include "domain_conf.h" # include "domain_event.h" -# include "virterror_internal.h" +# include "virerror.h" # include "virthread.h" # include "vircommand.h" # include "virhash.h" diff --git a/src/util/iohelper.c b/src/util/iohelper.c index 40b04f9..2230bcb 100644 --- a/src/util/iohelper.c +++ b/src/util/iohelper.c @@ -37,7 +37,7 @@ #include "virthread.h" #include "virfile.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "configmake.h" #include "virrandom.h" diff --git a/src/util/viraudit.c b/src/util/viraudit.c index 05189d5..04ac323 100644 --- a/src/util/viraudit.c +++ b/src/util/viraudit.c @@ -27,7 +27,7 @@ #include <stdio.h> #include <unistd.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "viraudit.h" #include "virutil.h" diff --git a/src/util/virauth.c b/src/util/virauth.c index cbb16ec..c26e340 100644 --- a/src/util/virauth.c +++ b/src/util/virauth.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "virlog.h" #include "datatypes.h" -#include "virterror_internal.h" +#include "virerror.h" #include "configmake.h" #include "virauthconfig.h" diff --git a/src/util/virauthconfig.c b/src/util/virauthconfig.c index d60f7bf..1d1f084 100644 --- a/src/util/virauthconfig.c +++ b/src/util/virauthconfig.c @@ -28,7 +28,7 @@ #include "viralloc.h" #include "virutil.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" struct _virAuthConfig { diff --git a/src/util/vircommand.c b/src/util/vircommand.c index d059586..c906f2a 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -35,7 +35,7 @@ #include "vircommand.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "virlog.h" #include "virfile.h" diff --git a/src/util/virconf.c b/src/util/virconf.c index 7e4c8c1..16ed2cb 100644 --- a/src/util/virconf.c +++ b/src/util/virconf.c @@ -30,7 +30,7 @@ #include <sys/stat.h> #include <fcntl.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virbuffer.h" #include "virconf.h" #include "virutil.h" diff --git a/src/util/virdbus.c b/src/util/virdbus.c index f45074c..127e57f 100644 --- a/src/util/virdbus.c +++ b/src/util/virdbus.c @@ -23,7 +23,7 @@ #include "virdbus.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virthread.h" diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c index 6b9abd9..e9148c1 100644 --- a/src/util/virdnsmasq.c +++ b/src/util/virdnsmasq.c @@ -44,7 +44,7 @@ #include "virutil.h" #include "vircommand.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virfile.h" diff --git a/src/util/virebtables.c b/src/util/virebtables.c index edf4956..959599a 100644 --- a/src/util/virebtables.c +++ b/src/util/virebtables.c @@ -43,7 +43,7 @@ #include "virebtables.h" #include "vircommand.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virthread.h" diff --git a/src/util/virerror.c b/src/util/virerror.c new file mode 100644 index 0000000..257880f --- /dev/null +++ b/src/util/virerror.c @@ -0,0 +1,1369 @@ +/* + * virterror.c: implements error handling and reporting code for libvirt + * + * Copyright (C) 2006, 2008-2012 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, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel Veillard <veillard@redhat.com> + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "virerror.h" +#include "datatypes.h" +#include "virlog.h" +#include "viralloc.h" +#include "virthread.h" +#include "virutil.h" + +virThreadLocal virLastErr; + +virErrorFunc virErrorHandler = NULL; /* global error handler */ +void *virUserData = NULL; /* associated data */ +virErrorLogPriorityFunc virErrorLogPriorityFilter = NULL; + +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; +} + + +VIR_ENUM_DECL(virErrorDomain) +VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, + "", /* 0 */ + "Xen Driver", + "Xen Daemon", + "Xen Store", + "S-Expression", + + "XML Util", /* 5 */ + "Domain", + "XML-RPC", + "Proxy Daemon", + "Config File", + + "QEMU Driver", /* 10 */ + "Network", + "Test Driver", + "Remote Driver", + "OpenVZ Driver", + + "Xen XM Driver", /* 15 */ + "Linux Statistics", + "LXC Driver", + "Storage Driver", + "Network Driver", + + "Domain Config", /* 20 */ + "User Mode Linux Driver", + "Node Device Driver", + "Xen Inotify Driver", + "Security Driver", + + "VirtualBox Driver", /* 25 */ + "Network Interface Driver", + "Open Nebula Driver", + "ESX Driver", + "Power Hypervisor Driver", + + "Secrets Driver", /* 30 */ + "CPU Driver", + "XenAPI Driver", + "Network Filter Driver", + "Lifecycle Hook", + + "Domain Snapshot", /* 35 */ + "Audit Utils", + "Sysinfo Utils", + "I/O Stream Utils", + "VMWare Driver", + + "Event Loop", /* 40 */ + "Xen Light Driver", + "Lock Driver", + "Hyper-V Driver", + "Capabilities Utils", + + "URI Utils", /* 45 */ + "Authentication Utils", + "DBus Utils", + "Parallels Cloud Server", + "Device Config", + + "SSH transport layer", /* 50 */ + "Lock Space", + "Init control", + ) + + +/* + * 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(_("An error occurred, but the cause is unknown")); +} + + +/* + * Internal helper to perform a deep copy of 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; + /* + * Deliberately 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; + if (virThreadLocalSet(&virLastErr, err) < 0) + VIR_FREE(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; +} + +/** + * virSetError: + * @newerr: previously saved error object + * + * Set the current error from a previously saved error object + * + * Can be used to re-set an old error, which may have been squashed by + * other functions (like cleanup routines). + * + * Returns 0 on success, -1 on failure. Leaves errno unchanged. + */ +int +virSetError(virErrorPtr newerr) +{ + virErrorPtr err; + int saved_errno = errno; + int ret = -1; + + err = virLastErrorObject(); + if (!err) + goto cleanup; + + virResetError(err); + ret = virCopyError(newerr, err); +cleanup: + errno = saved_errno; + return ret; +} + +/** + * 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 guarantee 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. On success, errno is + * unchanged; on failure, errno is ENOMEM. + * + * 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; + int saved_errno = errno; + + if (VIR_ALLOC(to) < 0) + return NULL; + + virCopyLastError(to); + errno = saved_errno; + 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; + VIR_FREE(err->message); + VIR_FREE(err->str1); + VIR_FREE(err->str2); + VIR_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 compatibility. + * + * 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 compatibility. + * + * 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 guarantee 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 = virErrorDomainTypeToString(err->domain); + if (!dom) + dom = "Unknown"; + 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); +} + +/** + * virDispatchError: + * @conn: pointer to the hypervisor connection + * + * Internal helper to do final stage of error + * reporting in public APIs. + * + * - Copy the global error to per-connection error if needed + * - Set a generic error message if none is already set + * - Invoke the error callback functions + */ +void +virDispatchError(virConnectPtr conn) +{ + virErrorPtr err = virLastErrorObject(); + virErrorFunc handler = virErrorHandler; + void *userData = virUserData; + + /* Can only happen on OOM. */ + if (!err) + return; + + /* Set a generic error message if none is already set */ + if (err->code == VIR_ERR_OK) + virErrorGenericFailure(err); + + /* Copy the global error to per-connection error if needed */ + if (conn) { + virMutexLock(&conn->lock); + virCopyError(err, &conn->err); + + if (conn->handler != NULL) { + handler = conn->handler; + userData = conn->userData; + } + virMutexUnlock(&conn->lock); + } + + /* Invoke the error callback functions */ + if (handler != NULL) { + (handler)(userData, err); + } else { + virDefaultErrorFunc(err); + } +} + + + +/** + * virRaiseErrorFull: + * @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(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, ...) +{ + int save_errno = errno; + virErrorPtr to; + char *str; + int priority; + + /* + * All errors are recorded in thread local storage + * For compatibility, public API calls will copy them + * to the per-connection error object when necessary + */ + to = virLastErrorObject(); + if (!to) { + errno = save_errno; + return; /* Hit OOM allocating thread error object, sod all we can do now */ + } + + virResetError(to); + + if (code == VIR_ERR_OK) { + errno = save_errno; + return; + } + + /* + * formats the message; drop message on OOM situations + */ + if (fmt == NULL) { + str = strdup(_("No error message provided")); + } else { + va_list ap; + va_start(ap, fmt); + virVasprintf(&str, fmt, ap); + va_end(ap); + } + + /* + * Save the information about the error + */ + /* + * Deliberately 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; + + /* + * Hook up the error or warning to the logging facility + */ + priority = virErrorLevelPriority(level); + if (virErrorLogPriorityFilter) + priority = virErrorLogPriorityFilter(to, priority); + virLogMessage(virErrorLogPriorityFilter ? VIR_LOG_FROM_FILE : VIR_LOG_FROM_ERROR, + priority, + filename, linenr, funcname, + NULL, "%s", str); + + errno = save_errno; +} + +/** + * 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 + */ +static 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 connection driver"); + else + errmsg = _("this function is not supported by the connection driver: %s"); + break; + case VIR_ERR_NO_CONNECT: + if (info == NULL) + errmsg = _("no connection driver available"); + else + errmsg = _("no connection 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"); + else + errmsg = _("invalid argument: %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 name information"); + else + errmsg = _("missing 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 is invalid or not well formed"); + else + errmsg = _("XML error: %s"); + 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_AUTH_CANCELLED: + if (info == NULL) + errmsg = _("authentication cancelled"); + else + errmsg = _("authentication cancelled: %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_STORAGE_PROBE_FAILED: + if (info == NULL) + errmsg = _("Storage pool probe failed"); + else + errmsg = _("Storage pool probe failed: %s"); + break; + case VIR_ERR_STORAGE_POOL_BUILT: + if (info == NULL) + errmsg = _("Storage pool already built"); + else + errmsg = _("Storage pool already built: %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"); + break; + case VIR_ERR_NO_SECRET: + if (info == NULL) + errmsg = _("Secret not found"); + else + errmsg = _("Secret not found: %s"); + break; + case VIR_WAR_NO_NWFILTER: + if (info == NULL) + errmsg = _("Failed to start the nwfilter driver"); + else + errmsg = _("Failed to start the nwfilter driver: %s"); + break; + case VIR_ERR_INVALID_NWFILTER: + if (info == NULL) + errmsg = _("Invalid network filter"); + else + errmsg = _("Invalid network filter: %s"); + break; + case VIR_ERR_NO_NWFILTER: + if (info == NULL) + errmsg = _("Network filter not found"); + else + errmsg = _("Network filter not found: %s"); + break; + case VIR_ERR_BUILD_FIREWALL: + if (info == NULL) + errmsg = _("Error while building firewall"); + else + errmsg = _("Error while building firewall: %s"); + break; + case VIR_ERR_CONFIG_UNSUPPORTED: + if (info == NULL) + errmsg = _("unsupported configuration"); + else + errmsg = _("unsupported configuration: %s"); + break; + case VIR_ERR_OPERATION_TIMEOUT: + if (info == NULL) + errmsg = _("Timed out during operation"); + else + errmsg = _("Timed out during operation: %s"); + break; + case VIR_ERR_MIGRATE_PERSIST_FAILED: + if (info == NULL) + errmsg = _("Failed to make domain persistent after migration"); + else + errmsg = _("Failed to make domain persistent after migration: %s"); + break; + case VIR_ERR_HOOK_SCRIPT_FAILED: + if (info == NULL) + errmsg = _("Hook script execution failed"); + else + errmsg = _("Hook script execution failed: %s"); + break; + case VIR_ERR_INVALID_DOMAIN_SNAPSHOT: + if (info == NULL) + errmsg = _("Invalid snapshot"); + else + errmsg = _("Invalid snapshot: %s"); + break; + case VIR_ERR_NO_DOMAIN_SNAPSHOT: + if (info == NULL) + errmsg = _("Domain snapshot not found"); + else + errmsg = _("Domain snapshot not found: %s"); + break; + case VIR_ERR_INVALID_STREAM: + if (info == NULL) + errmsg = _("invalid stream pointer"); + else + errmsg = _("invalid stream pointer in %s"); + break; + case VIR_ERR_ARGUMENT_UNSUPPORTED: + if (info == NULL) + errmsg = _("argument unsupported"); + else + errmsg = _("argument unsupported: %s"); + break; + case VIR_ERR_SNAPSHOT_REVERT_RISKY: + if (info == NULL) + errmsg = _("revert requires force"); + else + errmsg = _("revert requires force: %s"); + break; + case VIR_ERR_OPERATION_ABORTED: + if (info == NULL) + errmsg = _("operation aborted"); + else + errmsg = _("operation aborted: %s"); + break; + case VIR_ERR_NO_DOMAIN_METADATA: + if (info == NULL) + errmsg = _("metadata not found"); + else + errmsg = _("metadata not found: %s"); + break; + case VIR_ERR_MIGRATE_UNSAFE: + if (!info) + errmsg = _("Unsafe migration"); + else + errmsg = _("Unsafe migration: %s"); + break; + case VIR_ERR_OVERFLOW: + if (!info) + errmsg = _("numerical overflow"); + else + errmsg = _("numerical overflow: %s"); + break; + case VIR_ERR_BLOCK_COPY_ACTIVE: + if (!info) + errmsg = _("block copy still active"); + else + errmsg = _("block copy still active: %s"); + break; + case VIR_ERR_OPERATION_UNSUPPORTED: + if (!info) + errmsg = _("Operation not supported"); + else + errmsg = _("Operation not supported: %s"); + break; + case VIR_ERR_SSH: + if (info == NULL) + errmsg = _("SSH transport error"); + else + errmsg = _("SSH transport error: %s"); + break; + case VIR_ERR_AGENT_UNRESPONSIVE: + if (info == NULL) + errmsg = _("Guest agent is not responding"); + else + errmsg = _("Guest agent is not responding: %s"); + break; + case VIR_ERR_RESOURCE_BUSY: + if (info == NULL) + errmsg = _("resource busy"); + else + errmsg = _("resource busy %s"); + break; + } + return errmsg; +} + +/** + * virReportErrorHelper: + * + * @domcode: the virErrorDomain indicating where it's coming from + * @errorcode: 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(int domcode, + int errorcode, + const char *filename, + const char *funcname, + size_t linenr, + const char *fmt, ...) +{ + int save_errno = errno; + 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(errorcode, (errorMessage[0] ? errorMessage : NULL)); + virRaiseErrorFull(filename, funcname, linenr, + domcode, errorcode, VIR_ERR_ERROR, + virerr, errorMessage, NULL, + -1, -1, virerr, errorMessage); + errno = save_errno; +} + +/** + * virStrerror: + * @theerrno: the errno value + * @errBuf: the buffer to save the error to + * @errBufLen: the buffer length + * + * Generate an error 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) +{ + int save_errno = errno; + const char *ret; + + strerror_r(theerrno, errBuf, errBufLen); + ret = errBuf; + errno = save_errno; + return ret; +} + +/** + * virReportSystemErrorFull: + * @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(int domcode, + int theerrno, + const char *filename, + const char *funcname, + size_t linenr, + const char *fmt, ...) +{ + int save_errno = errno; + 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(errnoDetail); + if (0 <= n && n + 2 + len < sizeof(msgDetailBuf)) { + char *p = msgDetailBuf + n; + stpcpy(stpcpy(p, ": "), errnoDetail); + msgDetail = msgDetailBuf; + } + } + + if (!msgDetail) + msgDetail = errnoDetail; + + virRaiseErrorFull(filename, funcname, linenr, + domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR, + msg, msgDetail, NULL, theerrno, -1, msg, msgDetail); + errno = save_errno; +} + +/** + * virReportOOMErrorFull: + * @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(int domcode, + const char *filename, + const char *funcname, + size_t linenr) +{ + const char *virerr; + + virerr = virErrorMsg(VIR_ERR_NO_MEMORY, NULL); + virRaiseErrorFull(filename, funcname, linenr, + domcode, VIR_ERR_NO_MEMORY, VIR_ERR_ERROR, + virerr, NULL, NULL, -1, -1, virerr, NULL); +} + +/** + * virSetErrorLogPriorityFunc: + * @func: function to install + * + * Install a function used to filter error logging based on error priority. + */ +void virSetErrorLogPriorityFunc(virErrorLogPriorityFunc func) +{ + virErrorLogPriorityFilter = func; +} diff --git a/src/util/virerror.h b/src/util/virerror.h new file mode 100644 index 0000000..961c423 --- /dev/null +++ b/src/util/virerror.h @@ -0,0 +1,167 @@ +/* + * virterror.h: internal error handling + * + * Copyright (C) 2006-2009, 2011 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, see + * <http://www.gnu.org/licenses/>. + * + */ + +#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(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(12, 13); + +void virReportErrorHelper(int domcode, int errcode, + const char *filename, + const char *funcname, + size_t linenr, + const char *fmt, ...) + ATTRIBUTE_FMT_PRINTF(6, 7); + +void virReportSystemErrorFull(int domcode, + int theerrno, + const char *filename, + const char *funcname, + size_t linenr, + const char *fmt, ...) + ATTRIBUTE_FMT_PRINTF(6, 7); + +# define virReportSystemError(theerrno, fmt,...) \ + virReportSystemErrorFull(VIR_FROM_THIS, \ + (theerrno), \ + __FILE__, __FUNCTION__, __LINE__, \ + (fmt), __VA_ARGS__) + +# define virReportInvalidNullArg(argname) \ + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ + VIR_FROM_THIS, \ + VIR_ERR_INVALID_ARG, \ + VIR_ERR_ERROR, \ + __FUNCTION__, \ + #argname, \ + NULL, \ + 0, 0, \ + _("%s in %s must be NULL"), \ + #argname, __FUNCTION__) +# define virReportInvalidNonNullArg(argname) \ + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ + VIR_FROM_THIS, \ + VIR_ERR_INVALID_ARG, \ + VIR_ERR_ERROR, \ + __FUNCTION__, \ + #argname, \ + NULL, \ + 0, 0, \ + _("%s in %s must not be NULL"), \ + #argname, __FUNCTION__) +# define virReportInvalidPositiveArg(argname) \ + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ + VIR_FROM_THIS, \ + VIR_ERR_INVALID_ARG, \ + VIR_ERR_ERROR, \ + __FUNCTION__, \ + #argname, \ + NULL, \ + 0, 0, \ + _("%s in %s must greater than zero"), \ + #argname, __FUNCTION__) +# define virReportInvalidNonZeroArg(argname) \ + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ + VIR_FROM_THIS, \ + VIR_ERR_INVALID_ARG, \ + VIR_ERR_ERROR, \ + __FUNCTION__, \ + #argname, \ + NULL, \ + 0, 0, \ + _("%s in %s must not be zero"), \ + #argname, __FUNCTION__) +# define virReportInvalidZeroArg(argname) \ + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ + VIR_FROM_THIS, \ + VIR_ERR_INVALID_ARG, \ + VIR_ERR_ERROR, \ + __FUNCTION__, \ + #argname, \ + NULL, \ + 0, 0, \ + _("%s in %s must be zero"), \ + #argname, __FUNCTION__) +# define virReportInvalidNonNegativeArg(argname) \ + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ + VIR_FROM_THIS, \ + VIR_ERR_INVALID_ARG, \ + VIR_ERR_ERROR, \ + __FUNCTION__, \ + #argname, \ + NULL, \ + 0, 0, \ + _("%s in %s must be zero or greater"), \ + #argname, __FUNCTION__) +# define virReportInvalidArg(argname, fmt, ...) \ + virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ + VIR_FROM_THIS, \ + VIR_ERR_INVALID_ARG, \ + VIR_ERR_ERROR, \ + __FUNCTION__, \ + #argname, \ + NULL, \ + 0, 0, \ + (fmt), __VA_ARGS__) + +void virReportOOMErrorFull(int domcode, + const char *filename, + const char *funcname, + size_t linenr); + +# define virReportOOMError() \ + virReportOOMErrorFull(VIR_FROM_THIS, __FILE__, __FUNCTION__, __LINE__) + +# define virReportError(code, ...) \ + virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +int virSetError(virErrorPtr newerr); +void virDispatchError(virConnectPtr conn); +const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen); + +typedef int (*virErrorLogPriorityFunc)(virErrorPtr, int); +void virSetErrorLogPriorityFunc(virErrorLogPriorityFunc func); + +#endif diff --git a/src/util/virevent.c b/src/util/virevent.c index 573b4ac..a207a48 100644 --- a/src/util/virevent.c +++ b/src/util/virevent.c @@ -26,7 +26,7 @@ #include "virevent.h" #include "vireventpoll.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include <stdlib.h> diff --git a/src/util/vireventpoll.c b/src/util/vireventpoll.c index afb0e05..ac1bf8e 100644 --- a/src/util/vireventpoll.c +++ b/src/util/vireventpoll.c @@ -37,7 +37,7 @@ #include "viralloc.h" #include "virutil.h" #include "virfile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virtime.h" #define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__) diff --git a/src/util/virfile.c b/src/util/virfile.c index f20ce64..50999aa 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -40,7 +40,7 @@ #include "vircommand.h" #include "configmake.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virhash.c b/src/util/virhash.c index a1234c4..2fe8751 100644 --- a/src/util/virhash.c +++ b/src/util/virhash.c @@ -24,7 +24,7 @@ #include <string.h> #include <stdlib.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virhash.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/util/virhooks.c b/src/util/virhooks.c index 54a869a..9ff158a 100644 --- a/src/util/virhooks.c +++ b/src/util/virhooks.c @@ -30,7 +30,7 @@ #include <stdlib.h> #include <stdio.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virhooks.h" #include "virutil.h" #include "virlog.h" diff --git a/src/util/virinitctl.c b/src/util/virinitctl.c index f8ac673..1618ffa 100644 --- a/src/util/virinitctl.c +++ b/src/util/virinitctl.c @@ -28,7 +28,7 @@ #include "internal.h" #include "virinitctl.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/util/viriptables.c b/src/util/viriptables.c index eb8acf5..5ff3a1e 100644 --- a/src/util/viriptables.c +++ b/src/util/viriptables.c @@ -41,7 +41,7 @@ #include "viriptables.h" #include "vircommand.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virthread.h" diff --git a/src/util/virjson.c b/src/util/virjson.c index 4c9797c..2c412c2 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -25,7 +25,7 @@ #include "virjson.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virutil.h" diff --git a/src/util/virkeyfile.c b/src/util/virkeyfile.c index 99e5cd7..d77e95d 100644 --- a/src/util/virkeyfile.c +++ b/src/util/virkeyfile.c @@ -31,7 +31,7 @@ #include "virutil.h" #include "virhash.h" #include "virkeyfile.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_CONF diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c index 81a1d81..9ada6a6 100644 --- a/src/util/virlockspace.c +++ b/src/util/virlockspace.c @@ -24,7 +24,7 @@ #include "virlockspace.h" #include "virlog.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "virfile.h" #include "virhash.h" diff --git a/src/util/virlog.c b/src/util/virlog.c index 43a59b4..d0e996d 100644 --- a/src/util/virlog.c +++ b/src/util/virlog.c @@ -40,7 +40,7 @@ # include <sys/un.h> #endif -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "viralloc.h" #include "virutil.h" diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 3ea0e39..ce02d2c 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -25,7 +25,7 @@ #include "virnetdev.h" #include "virmacaddr.h" #include "virfile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "vircommand.h" #include "viralloc.h" #include "virpci.h" diff --git a/src/util/virnetdevbandwidth.c b/src/util/virnetdevbandwidth.c index 9cc8858..2c5b63a 100644 --- a/src/util/virnetdevbandwidth.c +++ b/src/util/virnetdevbandwidth.c @@ -25,7 +25,7 @@ #include "virnetdevbandwidth.h" #include "vircommand.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virnetdevbridge.c b/src/util/virnetdevbridge.c index 4de88e3..b87c601 100644 --- a/src/util/virnetdevbridge.c +++ b/src/util/virnetdevbridge.c @@ -23,7 +23,7 @@ #include <config.h> #include "virnetdevbridge.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include "virfile.h" #include "viralloc.h" diff --git a/src/util/virnetdevmacvlan.c b/src/util/virnetdevmacvlan.c index 720a48a..a74db1e 100644 --- a/src/util/virnetdevmacvlan.c +++ b/src/util/virnetdevmacvlan.c @@ -30,7 +30,7 @@ #include "virnetdevmacvlan.h" #include "virmacaddr.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NET diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c index b876a4e..47c3db8 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -26,7 +26,7 @@ #include "virnetdevopenvswitch.h" #include "vircommand.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virmacaddr.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 3565bbd..a884de1 100644 --- a/src/util/virnetdevtap.c +++ b/src/util/virnetdevtap.c @@ -27,9 +27,9 @@ #include "virnetdev.h" #include "virnetdevbridge.h" #include "virnetdevopenvswitch.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virfile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" #include "virutil.h" diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c index c6568b7..3f81655 100644 --- a/src/util/virnetdevveth.c +++ b/src/util/virnetdevveth.c @@ -29,7 +29,7 @@ #include "viralloc.h" #include "virlog.h" #include "vircommand.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virnetdevvlan.c b/src/util/virnetdevvlan.c index 53c6b65..2fe2017 100644 --- a/src/util/virnetdevvlan.c +++ b/src/util/virnetdevvlan.c @@ -22,7 +22,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virnetdevvlan.h" #include "viralloc.h" diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index 60acabd..bb97e3a 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -23,7 +23,7 @@ #include <config.h> #include "virnetdevvportprofile.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #define VIR_FROM_THIS VIR_FROM_NET diff --git a/src/util/virnetlink.c b/src/util/virnetlink.c index fdd4c0d..0b36fdc 100644 --- a/src/util/virnetlink.c +++ b/src/util/virnetlink.c @@ -40,7 +40,7 @@ #include "viralloc.h" #include "virthread.h" #include "virmacaddr.h" -#include "virterror_internal.h" +#include "virerror.h" #ifndef SOL_NETLINK # define SOL_NETLINK 270 diff --git a/src/util/virnodesuspend.c b/src/util/virnodesuspend.c index 878be1d..df40ccd 100644 --- a/src/util/virnodesuspend.c +++ b/src/util/virnodesuspend.c @@ -28,7 +28,7 @@ #include "viralloc.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virobject.c b/src/util/virobject.c index aca6182..f51b735 100644 --- a/src/util/virobject.c +++ b/src/util/virobject.c @@ -25,7 +25,7 @@ #include "virthread.h" #include "viralloc.h" #include "viratomic.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virpci.c b/src/util/virpci.c index 8875aa6..83e9a7b 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -37,7 +37,7 @@ #include "virlog.h" #include "viralloc.h" #include "vircommand.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virfile.h" #define PCI_SYSFS "/sys/bus/pci/" diff --git a/src/util/virpidfile.c b/src/util/virpidfile.c index 29097e3..14c9f9f 100644 --- a/src/util/virpidfile.c +++ b/src/util/virpidfile.c @@ -33,7 +33,7 @@ #include "virutil.h" #include "intprops.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "c-ctype.h" #include "areadlink.h" diff --git a/src/util/virprocess.c b/src/util/virprocess.c index b276643..e8001e5 100644 --- a/src/util/virprocess.c +++ b/src/util/virprocess.c @@ -28,7 +28,7 @@ #include <sched.h> #include "virprocess.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" #include "virutil.h" diff --git a/src/util/virrandom.c b/src/util/virrandom.c index 1b6de6b..6c5bc91 100644 --- a/src/util/virrandom.c +++ b/src/util/virrandom.c @@ -30,7 +30,7 @@ #include "virthread.h" #include "count-one-bits.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virsexpr.c b/src/util/virsexpr.c index 8b70404..18d3c2d 100644 --- a/src/util/virsexpr.c +++ b/src/util/virsexpr.c @@ -17,7 +17,7 @@ #include "c-ctype.h" #include <errno.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virsexpr.h" #include "virutil.h" #include "viralloc.h" diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index 0f2f23d..7bc43a9 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -24,7 +24,7 @@ #include <config.h> #include "virsocketaddr.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #include <netdb.h> diff --git a/src/util/virstatslinux.c b/src/util/virstatslinux.c index 135df75..3505b96 100644 --- a/src/util/virstatslinux.c +++ b/src/util/virstatslinux.c @@ -32,7 +32,7 @@ # include <unistd.h> # include <regex.h> -# include "virterror_internal.h" +# include "virerror.h" # include "datatypes.h" # include "virutil.h" # include "virstatslinux.h" diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index f183f19..4ff3e14 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -36,7 +36,7 @@ #endif #include "dirname.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virfile.h" #include "c-ctype.h" diff --git a/src/util/virstring.c b/src/util/virstring.c index 5607b3e..0420ca3 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -24,7 +24,7 @@ #include "virstring.h" #include "viralloc.h" #include "virbuffer.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virsysinfo.c b/src/util/virsysinfo.c index 88e4f5c..61f7288 100644 --- a/src/util/virsysinfo.c +++ b/src/util/virsysinfo.c @@ -30,7 +30,7 @@ #include <stdlib.h> #include <stdio.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virsysinfo.h" #include "virutil.h" #include "virlog.h" diff --git a/src/util/virterror.c b/src/util/virterror.c deleted file mode 100644 index a586738..0000000 --- a/src/util/virterror.c +++ /dev/null @@ -1,1369 +0,0 @@ -/* - * virterror.c: implements error handling and reporting code for libvirt - * - * Copyright (C) 2006, 2008-2012 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, see - * <http://www.gnu.org/licenses/>. - * - * 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 "virlog.h" -#include "viralloc.h" -#include "virthread.h" -#include "virutil.h" - -virThreadLocal virLastErr; - -virErrorFunc virErrorHandler = NULL; /* global error handler */ -void *virUserData = NULL; /* associated data */ -virErrorLogPriorityFunc virErrorLogPriorityFilter = NULL; - -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; -} - - -VIR_ENUM_DECL(virErrorDomain) -VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, - "", /* 0 */ - "Xen Driver", - "Xen Daemon", - "Xen Store", - "S-Expression", - - "XML Util", /* 5 */ - "Domain", - "XML-RPC", - "Proxy Daemon", - "Config File", - - "QEMU Driver", /* 10 */ - "Network", - "Test Driver", - "Remote Driver", - "OpenVZ Driver", - - "Xen XM Driver", /* 15 */ - "Linux Statistics", - "LXC Driver", - "Storage Driver", - "Network Driver", - - "Domain Config", /* 20 */ - "User Mode Linux Driver", - "Node Device Driver", - "Xen Inotify Driver", - "Security Driver", - - "VirtualBox Driver", /* 25 */ - "Network Interface Driver", - "Open Nebula Driver", - "ESX Driver", - "Power Hypervisor Driver", - - "Secrets Driver", /* 30 */ - "CPU Driver", - "XenAPI Driver", - "Network Filter Driver", - "Lifecycle Hook", - - "Domain Snapshot", /* 35 */ - "Audit Utils", - "Sysinfo Utils", - "I/O Stream Utils", - "VMWare Driver", - - "Event Loop", /* 40 */ - "Xen Light Driver", - "Lock Driver", - "Hyper-V Driver", - "Capabilities Utils", - - "URI Utils", /* 45 */ - "Authentication Utils", - "DBus Utils", - "Parallels Cloud Server", - "Device Config", - - "SSH transport layer", /* 50 */ - "Lock Space", - "Init control", - ) - - -/* - * 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(_("An error occurred, but the cause is unknown")); -} - - -/* - * Internal helper to perform a deep copy of 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; - /* - * Deliberately 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; - if (virThreadLocalSet(&virLastErr, err) < 0) - VIR_FREE(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; -} - -/** - * virSetError: - * @newerr: previously saved error object - * - * Set the current error from a previously saved error object - * - * Can be used to re-set an old error, which may have been squashed by - * other functions (like cleanup routines). - * - * Returns 0 on success, -1 on failure. Leaves errno unchanged. - */ -int -virSetError(virErrorPtr newerr) -{ - virErrorPtr err; - int saved_errno = errno; - int ret = -1; - - err = virLastErrorObject(); - if (!err) - goto cleanup; - - virResetError(err); - ret = virCopyError(newerr, err); -cleanup: - errno = saved_errno; - return ret; -} - -/** - * 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 guarantee 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. On success, errno is - * unchanged; on failure, errno is ENOMEM. - * - * 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; - int saved_errno = errno; - - if (VIR_ALLOC(to) < 0) - return NULL; - - virCopyLastError(to); - errno = saved_errno; - 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; - VIR_FREE(err->message); - VIR_FREE(err->str1); - VIR_FREE(err->str2); - VIR_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 compatibility. - * - * 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 compatibility. - * - * 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 guarantee 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 = virErrorDomainTypeToString(err->domain); - if (!dom) - dom = "Unknown"; - 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); -} - -/** - * virDispatchError: - * @conn: pointer to the hypervisor connection - * - * Internal helper to do final stage of error - * reporting in public APIs. - * - * - Copy the global error to per-connection error if needed - * - Set a generic error message if none is already set - * - Invoke the error callback functions - */ -void -virDispatchError(virConnectPtr conn) -{ - virErrorPtr err = virLastErrorObject(); - virErrorFunc handler = virErrorHandler; - void *userData = virUserData; - - /* Can only happen on OOM. */ - if (!err) - return; - - /* Set a generic error message if none is already set */ - if (err->code == VIR_ERR_OK) - virErrorGenericFailure(err); - - /* Copy the global error to per-connection error if needed */ - if (conn) { - virMutexLock(&conn->lock); - virCopyError(err, &conn->err); - - if (conn->handler != NULL) { - handler = conn->handler; - userData = conn->userData; - } - virMutexUnlock(&conn->lock); - } - - /* Invoke the error callback functions */ - if (handler != NULL) { - (handler)(userData, err); - } else { - virDefaultErrorFunc(err); - } -} - - - -/** - * virRaiseErrorFull: - * @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(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, ...) -{ - int save_errno = errno; - virErrorPtr to; - char *str; - int priority; - - /* - * All errors are recorded in thread local storage - * For compatibility, public API calls will copy them - * to the per-connection error object when necessary - */ - to = virLastErrorObject(); - if (!to) { - errno = save_errno; - return; /* Hit OOM allocating thread error object, sod all we can do now */ - } - - virResetError(to); - - if (code == VIR_ERR_OK) { - errno = save_errno; - return; - } - - /* - * formats the message; drop message on OOM situations - */ - if (fmt == NULL) { - str = strdup(_("No error message provided")); - } else { - va_list ap; - va_start(ap, fmt); - virVasprintf(&str, fmt, ap); - va_end(ap); - } - - /* - * Save the information about the error - */ - /* - * Deliberately 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; - - /* - * Hook up the error or warning to the logging facility - */ - priority = virErrorLevelPriority(level); - if (virErrorLogPriorityFilter) - priority = virErrorLogPriorityFilter(to, priority); - virLogMessage(virErrorLogPriorityFilter ? VIR_LOG_FROM_FILE : VIR_LOG_FROM_ERROR, - priority, - filename, linenr, funcname, - NULL, "%s", str); - - errno = save_errno; -} - -/** - * 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 - */ -static 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 connection driver"); - else - errmsg = _("this function is not supported by the connection driver: %s"); - break; - case VIR_ERR_NO_CONNECT: - if (info == NULL) - errmsg = _("no connection driver available"); - else - errmsg = _("no connection 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"); - else - errmsg = _("invalid argument: %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 name information"); - else - errmsg = _("missing 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 is invalid or not well formed"); - else - errmsg = _("XML error: %s"); - 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_AUTH_CANCELLED: - if (info == NULL) - errmsg = _("authentication cancelled"); - else - errmsg = _("authentication cancelled: %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_STORAGE_PROBE_FAILED: - if (info == NULL) - errmsg = _("Storage pool probe failed"); - else - errmsg = _("Storage pool probe failed: %s"); - break; - case VIR_ERR_STORAGE_POOL_BUILT: - if (info == NULL) - errmsg = _("Storage pool already built"); - else - errmsg = _("Storage pool already built: %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"); - break; - case VIR_ERR_NO_SECRET: - if (info == NULL) - errmsg = _("Secret not found"); - else - errmsg = _("Secret not found: %s"); - break; - case VIR_WAR_NO_NWFILTER: - if (info == NULL) - errmsg = _("Failed to start the nwfilter driver"); - else - errmsg = _("Failed to start the nwfilter driver: %s"); - break; - case VIR_ERR_INVALID_NWFILTER: - if (info == NULL) - errmsg = _("Invalid network filter"); - else - errmsg = _("Invalid network filter: %s"); - break; - case VIR_ERR_NO_NWFILTER: - if (info == NULL) - errmsg = _("Network filter not found"); - else - errmsg = _("Network filter not found: %s"); - break; - case VIR_ERR_BUILD_FIREWALL: - if (info == NULL) - errmsg = _("Error while building firewall"); - else - errmsg = _("Error while building firewall: %s"); - break; - case VIR_ERR_CONFIG_UNSUPPORTED: - if (info == NULL) - errmsg = _("unsupported configuration"); - else - errmsg = _("unsupported configuration: %s"); - break; - case VIR_ERR_OPERATION_TIMEOUT: - if (info == NULL) - errmsg = _("Timed out during operation"); - else - errmsg = _("Timed out during operation: %s"); - break; - case VIR_ERR_MIGRATE_PERSIST_FAILED: - if (info == NULL) - errmsg = _("Failed to make domain persistent after migration"); - else - errmsg = _("Failed to make domain persistent after migration: %s"); - break; - case VIR_ERR_HOOK_SCRIPT_FAILED: - if (info == NULL) - errmsg = _("Hook script execution failed"); - else - errmsg = _("Hook script execution failed: %s"); - break; - case VIR_ERR_INVALID_DOMAIN_SNAPSHOT: - if (info == NULL) - errmsg = _("Invalid snapshot"); - else - errmsg = _("Invalid snapshot: %s"); - break; - case VIR_ERR_NO_DOMAIN_SNAPSHOT: - if (info == NULL) - errmsg = _("Domain snapshot not found"); - else - errmsg = _("Domain snapshot not found: %s"); - break; - case VIR_ERR_INVALID_STREAM: - if (info == NULL) - errmsg = _("invalid stream pointer"); - else - errmsg = _("invalid stream pointer in %s"); - break; - case VIR_ERR_ARGUMENT_UNSUPPORTED: - if (info == NULL) - errmsg = _("argument unsupported"); - else - errmsg = _("argument unsupported: %s"); - break; - case VIR_ERR_SNAPSHOT_REVERT_RISKY: - if (info == NULL) - errmsg = _("revert requires force"); - else - errmsg = _("revert requires force: %s"); - break; - case VIR_ERR_OPERATION_ABORTED: - if (info == NULL) - errmsg = _("operation aborted"); - else - errmsg = _("operation aborted: %s"); - break; - case VIR_ERR_NO_DOMAIN_METADATA: - if (info == NULL) - errmsg = _("metadata not found"); - else - errmsg = _("metadata not found: %s"); - break; - case VIR_ERR_MIGRATE_UNSAFE: - if (!info) - errmsg = _("Unsafe migration"); - else - errmsg = _("Unsafe migration: %s"); - break; - case VIR_ERR_OVERFLOW: - if (!info) - errmsg = _("numerical overflow"); - else - errmsg = _("numerical overflow: %s"); - break; - case VIR_ERR_BLOCK_COPY_ACTIVE: - if (!info) - errmsg = _("block copy still active"); - else - errmsg = _("block copy still active: %s"); - break; - case VIR_ERR_OPERATION_UNSUPPORTED: - if (!info) - errmsg = _("Operation not supported"); - else - errmsg = _("Operation not supported: %s"); - break; - case VIR_ERR_SSH: - if (info == NULL) - errmsg = _("SSH transport error"); - else - errmsg = _("SSH transport error: %s"); - break; - case VIR_ERR_AGENT_UNRESPONSIVE: - if (info == NULL) - errmsg = _("Guest agent is not responding"); - else - errmsg = _("Guest agent is not responding: %s"); - break; - case VIR_ERR_RESOURCE_BUSY: - if (info == NULL) - errmsg = _("resource busy"); - else - errmsg = _("resource busy %s"); - break; - } - return errmsg; -} - -/** - * virReportErrorHelper: - * - * @domcode: the virErrorDomain indicating where it's coming from - * @errorcode: 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(int domcode, - int errorcode, - const char *filename, - const char *funcname, - size_t linenr, - const char *fmt, ...) -{ - int save_errno = errno; - 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(errorcode, (errorMessage[0] ? errorMessage : NULL)); - virRaiseErrorFull(filename, funcname, linenr, - domcode, errorcode, VIR_ERR_ERROR, - virerr, errorMessage, NULL, - -1, -1, virerr, errorMessage); - errno = save_errno; -} - -/** - * virStrerror: - * @theerrno: the errno value - * @errBuf: the buffer to save the error to - * @errBufLen: the buffer length - * - * Generate an error 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) -{ - int save_errno = errno; - const char *ret; - - strerror_r(theerrno, errBuf, errBufLen); - ret = errBuf; - errno = save_errno; - return ret; -} - -/** - * virReportSystemErrorFull: - * @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(int domcode, - int theerrno, - const char *filename, - const char *funcname, - size_t linenr, - const char *fmt, ...) -{ - int save_errno = errno; - 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(errnoDetail); - if (0 <= n && n + 2 + len < sizeof(msgDetailBuf)) { - char *p = msgDetailBuf + n; - stpcpy(stpcpy(p, ": "), errnoDetail); - msgDetail = msgDetailBuf; - } - } - - if (!msgDetail) - msgDetail = errnoDetail; - - virRaiseErrorFull(filename, funcname, linenr, - domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR, - msg, msgDetail, NULL, theerrno, -1, msg, msgDetail); - errno = save_errno; -} - -/** - * virReportOOMErrorFull: - * @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(int domcode, - const char *filename, - const char *funcname, - size_t linenr) -{ - const char *virerr; - - virerr = virErrorMsg(VIR_ERR_NO_MEMORY, NULL); - virRaiseErrorFull(filename, funcname, linenr, - domcode, VIR_ERR_NO_MEMORY, VIR_ERR_ERROR, - virerr, NULL, NULL, -1, -1, virerr, NULL); -} - -/** - * virSetErrorLogPriorityFunc: - * @func: function to install - * - * Install a function used to filter error logging based on error priority. - */ -void virSetErrorLogPriorityFunc(virErrorLogPriorityFunc func) -{ - virErrorLogPriorityFilter = func; -} diff --git a/src/util/virterror_internal.h b/src/util/virterror_internal.h deleted file mode 100644 index 961c423..0000000 --- a/src/util/virterror_internal.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * virterror.h: internal error handling - * - * Copyright (C) 2006-2009, 2011 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, see - * <http://www.gnu.org/licenses/>. - * - */ - -#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(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(12, 13); - -void virReportErrorHelper(int domcode, int errcode, - const char *filename, - const char *funcname, - size_t linenr, - const char *fmt, ...) - ATTRIBUTE_FMT_PRINTF(6, 7); - -void virReportSystemErrorFull(int domcode, - int theerrno, - const char *filename, - const char *funcname, - size_t linenr, - const char *fmt, ...) - ATTRIBUTE_FMT_PRINTF(6, 7); - -# define virReportSystemError(theerrno, fmt,...) \ - virReportSystemErrorFull(VIR_FROM_THIS, \ - (theerrno), \ - __FILE__, __FUNCTION__, __LINE__, \ - (fmt), __VA_ARGS__) - -# define virReportInvalidNullArg(argname) \ - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ - VIR_FROM_THIS, \ - VIR_ERR_INVALID_ARG, \ - VIR_ERR_ERROR, \ - __FUNCTION__, \ - #argname, \ - NULL, \ - 0, 0, \ - _("%s in %s must be NULL"), \ - #argname, __FUNCTION__) -# define virReportInvalidNonNullArg(argname) \ - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ - VIR_FROM_THIS, \ - VIR_ERR_INVALID_ARG, \ - VIR_ERR_ERROR, \ - __FUNCTION__, \ - #argname, \ - NULL, \ - 0, 0, \ - _("%s in %s must not be NULL"), \ - #argname, __FUNCTION__) -# define virReportInvalidPositiveArg(argname) \ - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ - VIR_FROM_THIS, \ - VIR_ERR_INVALID_ARG, \ - VIR_ERR_ERROR, \ - __FUNCTION__, \ - #argname, \ - NULL, \ - 0, 0, \ - _("%s in %s must greater than zero"), \ - #argname, __FUNCTION__) -# define virReportInvalidNonZeroArg(argname) \ - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ - VIR_FROM_THIS, \ - VIR_ERR_INVALID_ARG, \ - VIR_ERR_ERROR, \ - __FUNCTION__, \ - #argname, \ - NULL, \ - 0, 0, \ - _("%s in %s must not be zero"), \ - #argname, __FUNCTION__) -# define virReportInvalidZeroArg(argname) \ - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ - VIR_FROM_THIS, \ - VIR_ERR_INVALID_ARG, \ - VIR_ERR_ERROR, \ - __FUNCTION__, \ - #argname, \ - NULL, \ - 0, 0, \ - _("%s in %s must be zero"), \ - #argname, __FUNCTION__) -# define virReportInvalidNonNegativeArg(argname) \ - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ - VIR_FROM_THIS, \ - VIR_ERR_INVALID_ARG, \ - VIR_ERR_ERROR, \ - __FUNCTION__, \ - #argname, \ - NULL, \ - 0, 0, \ - _("%s in %s must be zero or greater"), \ - #argname, __FUNCTION__) -# define virReportInvalidArg(argname, fmt, ...) \ - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, \ - VIR_FROM_THIS, \ - VIR_ERR_INVALID_ARG, \ - VIR_ERR_ERROR, \ - __FUNCTION__, \ - #argname, \ - NULL, \ - 0, 0, \ - (fmt), __VA_ARGS__) - -void virReportOOMErrorFull(int domcode, - const char *filename, - const char *funcname, - size_t linenr); - -# define virReportOOMError() \ - virReportOOMErrorFull(VIR_FROM_THIS, __FILE__, __FUNCTION__, __LINE__) - -# define virReportError(code, ...) \ - virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ - __FUNCTION__, __LINE__, __VA_ARGS__) - -int virSetError(virErrorPtr newerr); -void virDispatchError(virConnectPtr conn); -const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen); - -typedef int (*virErrorLogPriorityFunc)(virErrorPtr, int); -void virSetErrorLogPriorityFunc(virErrorLogPriorityFunc func); - -#endif diff --git a/src/util/virthreadpool.c b/src/util/virthreadpool.c index 307cefb..12a43e1 100644 --- a/src/util/virthreadpool.c +++ b/src/util/virthreadpool.c @@ -28,7 +28,7 @@ #include "virthreadpool.h" #include "viralloc.h" #include "virthread.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virtime.c b/src/util/virtime.c index c614380..b54a4e8 100644 --- a/src/util/virtime.c +++ b/src/util/virtime.c @@ -39,7 +39,7 @@ #include "virtime.h" #include "virutil.h" #include "viralloc.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/virtypedparam.c b/src/util/virtypedparam.c index 60fb485..33e6a09 100644 --- a/src/util/virtypedparam.c +++ b/src/util/virtypedparam.c @@ -26,7 +26,7 @@ #include "viralloc.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/src/util/viruri.c b/src/util/viruri.c index e59cd5a..2888cb0 100644 --- a/src/util/viruri.c +++ b/src/util/viruri.c @@ -24,7 +24,7 @@ #include "viralloc.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virbuffer.h" #define VIR_FROM_THIS VIR_FROM_URI diff --git a/src/util/virusb.c b/src/util/virusb.c index c053c44..26bd017 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -35,7 +35,7 @@ #include "virlog.h" #include "viralloc.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #define USB_SYSFS "/sys/bus/usb" #define USB_DEVFS "/dev/bus/usb/" diff --git a/src/util/virutil.c b/src/util/virutil.c index 9fb1c6f..a2ad725 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -75,7 +75,7 @@ #include "c-ctype.h" #include "dirname.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virbuffer.h" #include "virutil.h" diff --git a/src/util/viruuid.c b/src/util/viruuid.c index f4eb331..373c362 100644 --- a/src/util/viruuid.c +++ b/src/util/viruuid.c @@ -36,7 +36,7 @@ #include "c-ctype.h" #include "internal.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/util/virxml.c b/src/util/virxml.c index 02f7d1a..8f19054 100644 --- a/src/util/virxml.c +++ b/src/util/virxml.c @@ -30,7 +30,7 @@ #include <math.h> /* for isnan() */ #include <sys/stat.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virxml.h" #include "virbuffer.h" #include "virutil.h" diff --git a/src/vbox/vbox_MSCOMGlue.c b/src/vbox/vbox_MSCOMGlue.c index 36539f6..b5fb821 100644 --- a/src/vbox/vbox_MSCOMGlue.c +++ b/src/vbox/vbox_MSCOMGlue.c @@ -33,7 +33,7 @@ #include "viralloc.h" #include "virutil.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "vbox_MSCOMGlue.h" #define VIR_FROM_THIS VIR_FROM_VBOX diff --git a/src/vbox/vbox_XPCOMCGlue.c b/src/vbox/vbox_XPCOMCGlue.c index 1954ddb..2b568e2 100644 --- a/src/vbox/vbox_XPCOMCGlue.c +++ b/src/vbox/vbox_XPCOMCGlue.c @@ -40,7 +40,7 @@ #include "viralloc.h" #include "virutil.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_VBOX diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index f2a0c8f..736c895 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -37,7 +37,7 @@ #include "virlog.h" #include "vbox_driver.h" #include "vbox_glue.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virutil.h" #define VIR_FROM_THIS VIR_FROM_VBOX diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 5cac7bb..abcf90e 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -45,7 +45,7 @@ #include "domain_conf.h" #include "snapshot_conf.h" #include "network_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "domain_event.h" #include "storage_conf.h" #include "virstoragefile.h" diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c index 22a085d..8187185 100644 --- a/src/vmware/vmware_conf.c +++ b/src/vmware/vmware_conf.c @@ -31,7 +31,7 @@ #include "nodeinfo.h" #include "virfile.h" #include "viruuid.h" -#include "virterror_internal.h" +#include "virerror.h" #include "vmx.h" #include "vmware_conf.h" diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 67cdc88..3763f40 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -24,7 +24,7 @@ #include <fcntl.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virfile.h" #include "viralloc.h" diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index d57a14f..cc1344c 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -26,7 +26,7 @@ #include <c-ctype.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virconf.h" #include "viralloc.h" #include "virlog.h" diff --git a/src/xen/block_stats.c b/src/xen/block_stats.c index 3f7c97b..9f5823c 100644 --- a/src/xen/block_stats.c +++ b/src/xen/block_stats.c @@ -38,7 +38,7 @@ # include <xs.h> # endif -# include "virterror_internal.h" +# include "virerror.h" # include "datatypes.h" # include "virutil.h" # include "block_stats.h" diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index c35695a..2ef2c57 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -39,7 +39,7 @@ #include <fcntl.h> #include <xen/dom0_ops.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "xen_driver.h" diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c index f804620..ba93d2e 100644 --- a/src/xen/xen_hypervisor.c +++ b/src/xen/xen_hypervisor.c @@ -63,7 +63,7 @@ /* required for shutdown flags */ #include <xen/sched.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "driver.h" diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index 4cce25a..2043c74 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -27,7 +27,7 @@ #include <dirent.h> #include <sys/inotify.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "driver.h" #include "viralloc.h" diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 120e237..84a25e8 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -29,7 +29,7 @@ #include <netdb.h> #include <errno.h> -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "datatypes.h" #include "xend_internal.h" diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c index 0806e77..003e8f7 100644 --- a/src/xen/xm_internal.c +++ b/src/xen/xm_internal.c @@ -35,7 +35,7 @@ #include <stdint.h> #include <xen/dom0_ops.h> -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "xm_internal.h" #include "xen_driver.h" diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c index 20332df..9308522 100644 --- a/src/xen/xs_internal.c +++ b/src/xen/xs_internal.c @@ -41,7 +41,7 @@ # include <xs.h> #endif -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "driver.h" #include "viralloc.h" diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index df5625e..d7e22d3 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -28,7 +28,7 @@ #include <xen/api/xen_all.h> #include "internal.h" #include "domain_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virauth.h" #include "virutil.h" diff --git a/src/xenapi/xenapi_driver_private.h b/src/xenapi/xenapi_driver_private.h index 42684bd..7e5b6e7 100644 --- a/src/xenapi/xenapi_driver_private.h +++ b/src/xenapi/xenapi_driver_private.h @@ -25,7 +25,7 @@ # include <libxml/tree.h> # include <xen/api/xen_common.h> -# include "virterror_internal.h" +# include "virerror.h" /*# define PRINT_XML*/ # define VIR_FROM_THIS VIR_FROM_XENAPI diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c index 5c53b69..3b8384e 100644 --- a/src/xenapi/xenapi_utils.c +++ b/src/xenapi/xenapi_utils.c @@ -27,7 +27,7 @@ #include <xen/api/xen_all.h> #include "internal.h" #include "domain_conf.h" -#include "virterror_internal.h" +#include "virerror.h" #include "datatypes.h" #include "virutil.h" #include "viruuid.h" diff --git a/src/xenxs/xen_sxpr.c b/src/xenxs/xen_sxpr.c index b83ac58..83b7c74 100644 --- a/src/xenxs/xen_sxpr.c +++ b/src/xenxs/xen_sxpr.c @@ -27,7 +27,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virconf.h" #include "viralloc.h" #include "verify.h" diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index bbf35d8..df13ac7 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -26,7 +26,7 @@ #include <config.h> #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virconf.h" #include "viralloc.h" #include "verify.h" diff --git a/tests/commandtest.c b/tests/commandtest.c index d6a285e..fd2b8c0 100644 --- a/tests/commandtest.c +++ b/tests/commandtest.c @@ -36,7 +36,7 @@ #include "vircommand.h" #include "virfile.h" #include "virpidfile.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/tests/libvirtdconftest.c b/tests/libvirtdconftest.c index c1d94d2..fd033f8 100644 --- a/tests/libvirtdconftest.c +++ b/tests/libvirtdconftest.c @@ -26,7 +26,7 @@ #include "daemon/libvirtd-config.h" #include "virutil.h" #include "c-ctype.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virlog.h" #include "virconf.h" diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index e1b6c56..35f2da6 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -23,7 +23,7 @@ #include "testutilsqemu.h" #include "qemumonitortestutils.h" #include "virthread.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index b82eb5d..78eab29 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -32,7 +32,7 @@ #include "viralloc.h" #include "virutil.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #define VIR_FROM_THIS VIR_FROM_NONE diff --git a/tests/securityselinuxtest.c b/tests/securityselinuxtest.c index b523c79..8aa4f08 100644 --- a/tests/securityselinuxtest.c +++ b/tests/securityselinuxtest.c @@ -33,7 +33,7 @@ #include "viralloc.h" #include "virutil.h" #include "virlog.h" -#include "virterror_internal.h" +#include "virerror.h" #include "security/security_manager.h" diff --git a/tests/testutils.c b/tests/testutils.c index d88af21..9c8f365 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -42,7 +42,7 @@ #include "viralloc.h" #include "virutil.h" #include "virthread.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virbuffer.h" #include "virlog.h" #include "vircommand.h" diff --git a/tests/virauthconfigtest.c b/tests/virauthconfigtest.c index 2ad237d..67c5de8 100644 --- a/tests/virauthconfigtest.c +++ b/tests/virauthconfigtest.c @@ -25,7 +25,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virdrivermoduletest.c b/tests/virdrivermoduletest.c index cab47d3..de8cf70 100644 --- a/tests/virdrivermoduletest.c +++ b/tests/virdrivermoduletest.c @@ -22,7 +22,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" #include "driver.h" diff --git a/tests/virkeyfiletest.c b/tests/virkeyfiletest.c index 33f64c1..fb41840 100644 --- a/tests/virkeyfiletest.c +++ b/tests/virkeyfiletest.c @@ -25,7 +25,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c index c434f47..8673700 100644 --- a/tests/virlockspacetest.c +++ b/tests/virlockspacetest.c @@ -26,7 +26,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnetmessagetest.c b/tests/virnetmessagetest.c index 4e7a1fd..e58fd1f 100644 --- a/tests/virnetmessagetest.c +++ b/tests/virnetmessagetest.c @@ -25,7 +25,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index 819257b..b968973 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -29,7 +29,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/tests/virnettlscontexttest.c b/tests/virnettlscontexttest.c index d945181..a1e71dc 100644 --- a/tests/virnettlscontexttest.c +++ b/tests/virnettlscontexttest.c @@ -28,7 +28,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" #include "virfile.h" diff --git a/tests/virstringtest.c b/tests/virstringtest.c index 58ab843..86d8986 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -24,7 +24,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/virtimetest.c b/tests/virtimetest.c index 1c22d07..18f621a 100644 --- a/tests/virtimetest.c +++ b/tests/virtimetest.c @@ -25,7 +25,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/tests/viruritest.c b/tests/viruritest.c index ad59270..3cb88da 100644 --- a/tests/viruritest.c +++ b/tests/viruritest.c @@ -25,7 +25,7 @@ #include "testutils.h" #include "virutil.h" -#include "virterror_internal.h" +#include "virerror.h" #include "viralloc.h" #include "virlog.h" diff --git a/tools/console.c b/tools/console.c index d024d38..29873ea 100644 --- a/tools/console.c +++ b/tools/console.c @@ -43,7 +43,7 @@ # include "virfile.h" # include "viralloc.h" # include "virthread.h" -# include "virterror_internal.h" +# include "virerror.h" /* * Convert given character to control character. diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 3a9cebe..f3da1d5 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -49,7 +49,7 @@ #include "virmacaddr.h" #include "virstring.h" #include "virsh-domain-monitor.h" -#include "virterror_internal.h" +#include "virerror.h" #include "virtypedparam.h" #include "virxml.h" diff --git a/tools/virsh.c b/tools/virsh.c index 790cf56..283194a 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -54,7 +54,7 @@ #endif #include "internal.h" -#include "virterror_internal.h" +#include "virerror.h" #include "base64.h" #include "virbuffer.h" #include "console.h" diff --git a/tools/virsh.h b/tools/virsh.h index 6e6d3ee..ab7161f 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -34,7 +34,7 @@ # include <inttypes.h> # include "internal.h" -# include "virterror_internal.h" +# include "virerror.h" # include "virthread.h" # include "virnetdevbandwidth.h" -- 1.7.11.7

From: "Daniel P. Berrange" <berrange@redhat.com> --- src/Makefile.am | 53 +++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 0c77062..19a5b09 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,41 +60,27 @@ UTIL_SOURCES = \ util/virauthconfig.c util/virauthconfig.h \ util/virbitmap.c util/virbitmap.h \ util/virbuffer.c util/virbuffer.h \ + util/vircgroup.c util/vircgroup.h \ util/vircommand.c util/vircommand.h \ util/virconf.c util/virconf.h \ - util/virdnsmasq.c util/virdnsmasq.h \ + util/virdbus.c util/virdbus.h \ + util/virdnsmasq.c util/virdnsmasq.h \ util/virebtables.c util/virebtables.h \ util/virerror.c util/virerror.h \ util/virevent.c util/virevent.h \ util/vireventpoll.c util/vireventpoll.h \ util/virfile.c util/virfile.h \ + util/virhash.c util/virhash.h \ + util/virhashcode.c util/virhashcode.h \ util/virhooks.c util/virhooks.h \ - util/virnodesuspend.c util/virnodesuspend.h \ + util/virinitctl.c util/virinitctl.h \ util/viriptables.c util/viriptables.h \ util/virjson.c util/virjson.h \ - util/virlog.c util/virlog.h \ - util/virobject.c util/virobject.h \ - util/virpci.c util/virpci.h \ - util/virpidfile.c util/virpidfile.h \ - util/virprocess.c util/virprocess.h \ - util/virsexpr.c util/virsexpr.h \ - util/virstatslinux.c util/virstatslinux.h \ - util/virstoragefile.c util/virstoragefile.h \ - util/virsysinfo.c util/virsysinfo.h \ - util/virthread.c util/virthread.h \ - util/virthreadpthread.h \ - util/virthreadwin32.h \ - util/virthreadpool.c util/virthreadpool.h \ - util/virtypedparam.c util/virtypedparam.h \ - util/vircgroup.c util/vircgroup.h \ - util/virdbus.c util/virdbus.h \ - util/virhash.c util/virhash.h \ - util/virhashcode.c util/virhashcode.h \ - util/virinitctl.c util/virinitctl.h \ util/virkeycode.c util/virkeycode.h \ util/virkeyfile.c util/virkeyfile.h \ util/virkeymaps.h \ util/virlockspace.c util/virlockspace.h \ + util/virlog.c util/virlog.h \ util/virmacaddr.h util/virmacaddr.c \ util/virnetdev.h util/virnetdev.c \ util/virnetdevbandwidth.h util/virnetdevbandwidth.c \ @@ -102,14 +88,28 @@ UTIL_SOURCES = \ util/virnetdevmacvlan.c util/virnetdevmacvlan.h \ util/virnetdevopenvswitch.h util/virnetdevopenvswitch.c \ util/virnetdevtap.h util/virnetdevtap.c \ - util/virnetdevveth.h util/virnetdevveth.c \ - util/virnetdevvlan.h util/virnetdevvlan.c \ + util/virnetdevveth.h util/virnetdevveth.c \ + util/virnetdevvlan.h util/virnetdevvlan.c \ util/virnetdevvportprofile.h util/virnetdevvportprofile.c \ util/virnetlink.c util/virnetlink.h \ + util/virnodesuspend.c util/virnodesuspend.h \ + util/virobject.c util/virobject.h \ + util/virpci.c util/virpci.h \ + util/virpidfile.c util/virpidfile.h \ + util/virprocess.c util/virprocess.h \ util/virrandom.h util/virrandom.c \ - util/virsocketaddr.h util/virsocketaddr.c \ - util/virstring.h util/virstring.c \ - util/virtime.h util/virtime.c \ + util/virsexpr.c util/virsexpr.h \ + util/virsocketaddr.h util/virsocketaddr.c \ + util/virstatslinux.c util/virstatslinux.h \ + util/virstoragefile.c util/virstoragefile.h \ + util/virstring.h util/virstring.c \ + util/virsysinfo.c util/virsysinfo.h \ + util/virthread.c util/virthread.h \ + util/virthreadpthread.h \ + util/virthreadwin32.h \ + util/virthreadpool.c util/virthreadpool.h \ + util/virtime.h util/virtime.c \ + util/virtypedparam.c util/virtypedparam.h \ util/virusb.c util/virusb.h \ util/viruri.h util/viruri.c \ util/virutil.c util/virutil.h \ @@ -117,6 +117,7 @@ UTIL_SOURCES = \ util/virxml.c util/virxml.h \ $(NULL) + EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \ $(srcdir)/util/virkeycode-mapgen.py -- 1.7.11.7

On 17.12.2012 15:57, Daniel P. Berrange wrote:
Currently the files in src/util are 50/50 split between those having a 'vir' prefix and those which don't. Finish the job by remaining all remaining files to have a 'vir' prefix too, guaranteeing that they can't clash with system headers[1].
The only case which was not a plain rename, was merging processinfo.{c,h} into the virprocess.{c,h} since the functionality logically belongs together.
At the end src/Makefile.am is updated to sort util files alphabetically.
Left as further work - make sure all functions in these files also have a 'vir' prefix. eg dnsmasq, ebtables, iptables, usb and pci files are violators in this regard.
Also left, much of virutil.c should move into virfile.c
Daniel
[1] Not a theoretical problem - we already hit a clsah on 'usb.h' before forcing us to use 'hostusb.h' and 'memory.h' clashes with a system header but we never noticed so far.
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
I've tried, but failed to apply patch 04/28; On the top of which commit should I apply this? I've tried the current HEAD (c17b16d1be8). Moreover, if you plan to resend, consider formatting patch with '-M' which catches the renaming and reduces the size of patches. Michal

On Mon, Dec 17, 2012 at 04:45:59PM +0100, Michal Privoznik wrote:
On 17.12.2012 15:57, Daniel P. Berrange wrote:
Currently the files in src/util are 50/50 split between those having a 'vir' prefix and those which don't. Finish the job by remaining all remaining files to have a 'vir' prefix too, guaranteeing that they can't clash with system headers[1].
The only case which was not a plain rename, was merging processinfo.{c,h} into the virprocess.{c,h} since the functionality logically belongs together.
At the end src/Makefile.am is updated to sort util files alphabetically.
Left as further work - make sure all functions in these files also have a 'vir' prefix. eg dnsmasq, ebtables, iptables, usb and pci files are violators in this regard.
Also left, much of virutil.c should move into virfile.c
Daniel
[1] Not a theoretical problem - we already hit a clsah on 'usb.h' before forcing us to use 'hostusb.h' and 'memory.h' clashes with a system header but we never noticed so far.
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
I've tried, but failed to apply patch 04/28; On the top of which commit should I apply this? I've tried the current HEAD (c17b16d1be8).
It was on top of 77d3a8097480e388f1ce3129fe530f235b05f93b which is 1 commit newer than what you have
Moreover, if you plan to resend, consider formatting patch with '-M' which catches the renaming and reduces the size of patches.
Yeah, my .gitconfig was missing the rename detection config option on this host Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 17.12.2012 15:57, Daniel P. Berrange wrote:
Currently the files in src/util are 50/50 split between those having a 'vir' prefix and those which don't. Finish the job by remaining all remaining files to have a 'vir' prefix too, guaranteeing that they can't clash with system headers[1].
The only case which was not a plain rename, was merging processinfo.{c,h} into the virprocess.{c,h} since the functionality logically belongs together.
At the end src/Makefile.am is updated to sort util files alphabetically.
Left as further work - make sure all functions in these files also have a 'vir' prefix. eg dnsmasq, ebtables, iptables, usb and pci files are violators in this regard.
Also left, much of virutil.c should move into virfile.c
Daniel
[1] Not a theoretical problem - we already hit a clsah on 'usb.h' before forcing us to use 'hostusb.h' and 'memory.h' clashes with a system header but we never noticed so far.
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
ACK if you solve small nits I've found in 24 and 25. Michal

On Mon, Dec 17, 2012 at 10:22:18PM +0100, Michal Privoznik wrote:
On 17.12.2012 15:57, Daniel P. Berrange wrote:
Currently the files in src/util are 50/50 split between those having a 'vir' prefix and those which don't. Finish the job by remaining all remaining files to have a 'vir' prefix too, guaranteeing that they can't clash with system headers[1].
The only case which was not a plain rename, was merging processinfo.{c,h} into the virprocess.{c,h} since the functionality logically belongs together.
At the end src/Makefile.am is updated to sort util files alphabetically.
Left as further work - make sure all functions in these files also have a 'vir' prefix. eg dnsmasq, ebtables, iptables, usb and pci files are violators in this regard.
Also left, much of virutil.c should move into virfile.c
Daniel
[1] Not a theoretical problem - we already hit a clsah on 'usb.h' before forcing us to use 'hostusb.h' and 'memory.h' clashes with a system header but we never noticed so far.
ACK if you solve small nits I've found in 24 and 25.
Yep, will solve those issues. Ordinarily I would push changes after being acked, but given this is a quite significant change, I'd prefer to have another explicit ACK for this mass renaming. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (3)
-
Daniel P. Berrange
-
Michal Privoznik
-
Viktor Mihajlovski