This patch adds the files implements dnsmasq (hostsfile) module.
Signed-off-by: Satoru SATOH <satoru.satoh(a)gmail.com>
---
src/util/dnsmasq.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/util/dnsmasq.h | 59 ++++++++++
2 files changed, 385 insertions(+), 0 deletions(-)
create mode 100644 src/util/dnsmasq.c
create mode 100644 src/util/dnsmasq.h
diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c
new file mode 100644
index 0000000..b46654e
--- /dev/null
+++ b/src/util/dnsmasq.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2010 Satoru SATOH <satoru.satoh(a)gmail.com>
+ * Copyright (C) 2007-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * 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 "dnsmasq.h"
+#include "util.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "logging.h"
+
+#define VIR_FROM_THIS VIR_FROM_NETWORK
+
+static void
+dhcphostFree(dnsmasqDhcpHost *host)
+{
+ VIR_FREE(host->host);
+}
+
+static void
+hostsfileFree(dnsmasqHostsfile *hostsfile)
+{
+ int i;
+
+ if (hostsfile->hosts) {
+ for (i = 0; i < hostsfile->nhosts; i++)
+ dhcphostFree(&hostsfile->hosts[i]);
+
+ VIR_FREE(hostsfile->hosts);
+
+ hostsfile->nhosts = 0;
+ }
+
+ hostsfile->path[0] = '\0';
+
+ VIR_FREE(hostsfile);
+}
+
+static int
+hostsfileAdd(dnsmasqHostsfile *hostsfile,
+ const char *mac,
+ const char *ip,
+ const char *name)
+{
+ if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
+ goto alloc_error;
+
+ if (name) {
+ if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
"%s,%s,%s",
+ mac, ip, name) < 0) {
+ goto alloc_error;
+ }
+ } else {
+ if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
"%s,%s",
+ mac, ip) < 0) {
+ goto alloc_error;
+ }
+ }
+
+ hostsfile->nhosts++;
+
+ return 0;
+
+ alloc_error:
+ virReportSystemError(ENOMEM,
+ _("Failed to add dhcp host entry: mac=%s, ip=%s, name=%s\n"),
+ mac, ip, (name ? name : "(null)"));
+ return -1;
+}
+
+static dnsmasqHostsfile *
+hostsfileNew(const char *name,
+ const char *config_dir)
+{
+ int err;
+ dnsmasqHostsfile *hostsfile;
+
+ if (VIR_ALLOC(hostsfile) < 0)
+ return NULL;
+
+ hostsfile->hosts = NULL;
+ hostsfile->nhosts = 0;
+
+ if ((err = virFileMakePath(config_dir))) {
+ virReportSystemError(err, _("cannot create config directory
'%s'"),
+ config_dir);
+ goto error;
+ }
+
+ if (virFileBuildPath(config_dir, name, ".hostsfile", hostsfile->path,
+ sizeof(hostsfile->path)) < 0) {
+ virReportSystemError(err,
+ _("config filename '%s/%s.%s' is too long"),
+ config_dir, name, ".hostsfile");
+ goto error;
+ }
+
+ return hostsfile;
+
+ error:
+ hostsfileFree(hostsfile);
+ return NULL;
+}
+
+static int
+hostsfileWrite(const char *path, dnsmasqDhcpHost *hosts, int nhosts)
+{
+ char tmp[PATH_MAX];
+ FILE *f;
+ int istmp;
+ int i;
+
+ if (nhosts == 0 && unlink(path) == 0)
+ return 0;
+
+ if (snprintf(tmp, PATH_MAX, "%s.new", path) >= PATH_MAX)
+ return EINVAL;
+
+ istmp = 1;
+
+ if (!(f = fopen(tmp, "w"))) {
+ istmp = 0;
+ if (!(f = fopen(path, "w")))
+ return errno;
+ }
+
+ for (i = 0; i < nhosts; i++) {
+ if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) {
+ fclose(f);
+ if (istmp)
+ unlink(tmp);
+ return errno;
+ }
+ }
+
+ fclose(f);
+
+ if (istmp && rename(tmp, path) < 0) {
+ unlink(tmp);
+ return errno;
+ }
+
+ if (istmp)
+ unlink(tmp);
+
+ return 0;
+}
+
+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;
+}
+
+static int
+hostsfileDelete(dnsmasqHostsfile *hostsfile)
+{
+ if (!virFileExists(hostsfile->path))
+ return 0;
+
+ if (unlink(hostsfile->path) < 0) {
+ virReportSystemError(errno, _("cannot remove 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)
+ return NULL;
+
+ if (!(ctx->hostsfile = hostsfileNew(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 an dnsmasq context
+ */
+void
+dnsmasqContextFree(dnsmasqContext *ctx)
+{
+ if (!ctx)
+ return;
+
+ if (ctx->hostsfile)
+ hostsfileFree(ctx->hostsfile);
+
+ 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 string contains ip address of the host
+ * @name: pointer to the string contains hostname of the host or NULL
+ *
+ * Add dhcp-host entry.
+ */
+void
+dnsmasqAddDhcpHost(dnsmasqContext *ctx,
+ const char *mac,
+ const char *ip,
+ const char *name)
+{
+ if (ctx->hostsfile)
+ hostsfileAdd(ctx->hostsfile, mac, 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)
+{
+ if (ctx->hostsfile)
+ return hostsfileSave(ctx->hostsfile);
+
+ return 0;
+}
+
+
+/**
+ * dnsmasqDelete:
+ * @ctx: pointer to the dnsmasq context for each network
+ *
+ * Delete all the configuration files associated with a context.
+ */
+int
+dnsmasqDelete(const dnsmasqContext *ctx)
+{
+ if (ctx->hostsfile)
+ return hostsfileDelete(ctx->hostsfile);
+
+ return 0;
+}
+
+/**
+ * dnsmasqReload:
+ * @pid: the pid of the target dnsmasq process
+ *
+ * Reloads all the configurations associated to a context
+ */
+int
+dnsmasqReload(pid_t pid)
+{
+ if (kill(pid, SIGHUP) != 0) {
+ virReportSystemError(errno,
+ _("Failed to make dnsmasq (PID: %d) reloading config files.\n"),
+ pid);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/src/util/dnsmasq.h b/src/util/dnsmasq.h
new file mode 100644
index 0000000..987226b
--- /dev/null
+++ b/src/util/dnsmasq.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2010 Satoru SATOH <satoru.satoh(a)gmail.com>
+ * Copyright (C) 2007, 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * based on iptables.h
+ */
+
+#ifndef __DNSMASQ_H__
+#define __DNSMASQ_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
+{
+ int nhosts;
+ dnsmasqDhcpHost *hosts;
+
+ char path[PATH_MAX]; /* Absolute path of dnsmasq's hostsfile. */
+} dnsmasqHostsfile;
+
+typedef struct
+{
+ dnsmasqHostsfile *hostsfile;
+} dnsmasqContext;
+
+dnsmasqContext * dnsmasqContextNew(const char *network_name,
+ const char *config_dir);
+void dnsmasqContextFree(dnsmasqContext *ctx);
+void dnsmasqAddDhcpHost(dnsmasqContext *ctx,
+ const char *mac,
+ const char *ip,
+ const char *name);
+int dnsmasqSave(const dnsmasqContext *ctx);
+int dnsmasqDelete(const dnsmasqContext *ctx);
+int dnsmasqReload(pid_t pid);
+
+#endif /* __DNSMASQ_H__ */
--
1.6.2.5