[libvirt] [PATCH 06/28] Rename dnsmasq.{c,h} to virdnsmasq.{c,h}

Daniel P. Berrange berrange at redhat.com
Mon Dec 17 14:57:39 UTC 2012


From: "Daniel P. Berrange" <berrange at 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 at 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 at 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 at 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 at 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




More information about the libvir-list mailing list