From 134ec453dd586a275039a5f164cbf9597a3c931c Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20H=C3=A4rdeman?= Date: Fri, 7 Nov 2025 17:25:40 +0100 Subject: [PATCH] statefiles: simplify dhcpv6_ia_write_hostsfile() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Use a dirfd to keep track of the hostsfile directory, also make sure that the directory is created if necessary (this is in preparation for writing per-interface hostsfiles). Signed-off-by: David Härdeman Link: https://github.com/openwrt/odhcpd/pull/302 Signed-off-by: Álvaro Fernández Rojas --- src/config.c | 14 +++++++++++ src/odhcpd.h | 1 + src/statefiles.c | 62 ++++++++++++++++++------------------------------ 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/config.c b/src/config.c index 39a6db5..8bc8953 100644 --- a/src/config.c +++ b/src/config.c @@ -40,6 +40,7 @@ struct config config = { .dhcp_cb = NULL, .dhcp_statefile = NULL, .dhcp_hostsfile = NULL, + .dhcp_hostsdir_fd = -1, .ra_piofolder = NULL, .ra_piofolder_fd = -1, .uci_cfgdir = NULL, @@ -2312,6 +2313,19 @@ void odhcpd_reload(void) mkdir_p(dirname(path), 0755); } + if (config.dhcp_hostsfile) { + char *dir = dirname(strdupa(config.dhcp_hostsfile)); + char *file = basename(config.dhcp_hostsfile); + + memmove(config.dhcp_hostsfile, file, strlen(file) + 1); + mkdir_p(dir, 0755); + + close(config.dhcp_hostsdir_fd); + config.dhcp_hostsdir_fd = open(dir, O_PATH | O_DIRECTORY | O_CLOEXEC); + if (config.dhcp_hostsdir_fd < 0) + error("Unable to open hostsdir '%s': %m", dir); + } + if (config.ra_piofolder) { char *path = strdupa(config.ra_piofolder); diff --git a/src/odhcpd.h b/src/odhcpd.h index d13d078..54bb973 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -203,6 +203,7 @@ struct config { char *dhcp_cb; char *dhcp_statefile; char *dhcp_hostsfile; + int dhcp_hostsdir_fd; char *ra_piofolder; int ra_piofolder_fd; diff --git a/src/statefiles.c b/src/statefiles.c index 0dedbca..a0954c4 100644 --- a/src/statefiles.c +++ b/src/statefiles.c @@ -147,52 +147,32 @@ static void dhcpv6_write_ia_addr(struct in6_addr *addr, int prefix, _unused uint static void dhcpv6_ia_write_hostsfile(time_t now) { struct write_ctxt ctxt; + size_t tmp_hostsfile_strlen; + char *tmp_hostsfile; + int fd; - unsigned hostsfile_strlen = strlen(config.dhcp_hostsfile) + 1; - unsigned tmp_hostsfile_strlen = hostsfile_strlen + 1; /* space for . */ - char *tmp_hostsfile = alloca(tmp_hostsfile_strlen); - - char *dir_hostsfile; - char *base_hostsfile; - char *pdir_hostsfile; - char *pbase_hostsfile; - - int fd, ret; - - dir_hostsfile = strndup(config.dhcp_hostsfile, hostsfile_strlen); - base_hostsfile = strndup(config.dhcp_hostsfile, hostsfile_strlen); - - pdir_hostsfile = dirname(dir_hostsfile); - pbase_hostsfile = basename(base_hostsfile); - - snprintf(tmp_hostsfile, tmp_hostsfile_strlen, "%s/.%s", pdir_hostsfile, pbase_hostsfile); + if (config.dhcp_hostsdir_fd < 0 || !config.dhcp_hostsfile) + return; - free(dir_hostsfile); - free(base_hostsfile); + tmp_hostsfile_strlen = strlen(config.dhcp_hostsfile) + 2; + tmp_hostsfile = alloca(tmp_hostsfile_strlen); + sprintf(tmp_hostsfile, ".%s", config.dhcp_hostsfile); - fd = open(tmp_hostsfile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644); + fd = openat(config.dhcp_hostsdir_fd, tmp_hostsfile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644); if (fd < 0) - return; + goto err; - ret = lockf(fd, F_LOCK, 0); - if (ret < 0) { - close(fd); - return; - } + if (lockf(fd, F_LOCK, 0) < 0) + goto err; - if (ftruncate(fd, 0) < 0) {} + if (ftruncate(fd, 0) < 0) + goto err; ctxt.fp = fdopen(fd, "w"); - if (!ctxt.fp) { - close(fd); - return; - } + if (!ctxt.fp) + goto err; avl_for_each_element(&interfaces, ctxt.iface, avl) { - if (ctxt.iface->dhcpv6 != MODE_SERVER && - ctxt.iface->dhcpv4 != MODE_SERVER) - continue; - if (ctxt.iface->dhcpv6 == MODE_SERVER) { list_for_each_entry(ctxt.c, &ctxt.iface->ia_assignments, head) { if (!(ctxt.c->flags & OAF_BOUND)) @@ -232,8 +212,13 @@ static void dhcpv6_ia_write_hostsfile(time_t now) } fclose(ctxt.fp); + renameat(config.dhcp_hostsdir_fd, tmp_hostsfile, + config.dhcp_hostsdir_fd, config.dhcp_hostsfile); + return; - rename(tmp_hostsfile, config.dhcp_hostsfile); +err: + error("Unable to write hostsfile: %m"); + close(fd); } void dhcpv6_ia_write_statefile(void) @@ -384,8 +369,7 @@ void dhcpv6_ia_write_statefile(void) if (memcmp(newmd5, statemd5, sizeof(newmd5))) { memcpy(statemd5, newmd5, sizeof(statemd5)); - if (config.dhcp_hostsfile) - dhcpv6_ia_write_hostsfile(now); + dhcpv6_ia_write_hostsfile(now); if (config.dhcp_cb) { char *argv[2] = {config.dhcp_cb, NULL}; -- 2.30.2