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