#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 = virSocketFormatAddr(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)
+{
+ int err;
+ 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;
+ }
+
+ if ((err = virFileMakePath(config_dir))) {
+ virReportSystemError(err, _("cannot create config directory '%s'"),
+ config_dir);
+ 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;
+
+ if (nhosts == 0)
+ return rc;
+
+ 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) {
+ if (rename(tmp, path) < 0) {
+ rc = errno;
+ unlink(tmp);
+ goto cleanup;
+ }
+
+ if (unlink(tmp) < 0) {
+ rc = errno;
+ 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)
{
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:
*
if (!(ctx->hostsfile = hostsfileNew(network_name, config_dir)))
goto error;
+ if (!(ctx->addnhostsfile = addnhostsNew(network_name, config_dir)))
+ goto error;
return ctx;
if (ctx->hostsfile)
hostsfileFree(ctx->hostsfile);
+ if (ctx->addnhostsfile)
+ addnhostsFree(ctx->addnhostsfile);
VIR_FREE(ctx);
}
hostsfileAdd(ctx->hostsfile, mac, ip, name);
}
+/*
+ * 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.
+ */
+
+void
+dnsmasqAddHost(dnsmasqContext *ctx,
+ virSocketAddr *ip,
+ const char *name)
+{
+ if (ctx->addnhostsfile)
+ addnhostsAdd(ctx->addnhostsfile, ip, name);
+}
+
/**
* dnsmasqSave:
* @ctx: pointer to the dnsmasq context for each network
int
dnsmasqSave(const dnsmasqContext *ctx)
{
+ int ret = 0;
+
if (ctx->hostsfile)
- return hostsfileSave(ctx->hostsfile);
+ ret = hostsfileSave(ctx->hostsfile);
+ if (ret == 0) {
+ if (ctx->addnhostsfile)
+ ret = addnhostsSave(ctx->addnhostsfile);
+ }
- return 0;
+ return ret;
}
int
dnsmasqDelete(const dnsmasqContext *ctx)
{
+ int ret = 0;
+
if (ctx->hostsfile)
- return hostsfileDelete(ctx->hostsfile);
+ ret = genericFileDelete(ctx->hostsfile->path);
+ if (ctx->addnhostsfile)
+ ret = genericFileDelete(ctx->addnhostsfile->path);
- return 0;
+ return ret;
}
/**