From: David Härdeman Date: Fri, 7 Nov 2025 16:53:22 +0000 (+0100) Subject: statefiles: use dirfd in dhcpv6_ia_write_statefile() X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=310846535d06b1fe71d9ad3815c3dfaa1c65003e;p=project%2Fodhcpd.git statefiles: use dirfd in dhcpv6_ia_write_statefile() Similarly to the hostsfile, use a dirfd to keep track of the directory where the statefile is stored, simplifying the code a bit and avoiding some more allocations. Signed-off-by: David Härdeman Link: https://github.com/openwrt/odhcpd/pull/302 Signed-off-by: Álvaro Fernández Rojas --- diff --git a/src/config.c b/src/config.c index 8bc8953..0cb6d55 100644 --- a/src/config.c +++ b/src/config.c @@ -39,6 +39,7 @@ struct config config = { .main_dhcpv4 = false, .dhcp_cb = NULL, .dhcp_statefile = NULL, + .dhcp_statedir_fd = -1, .dhcp_hostsfile = NULL, .dhcp_hostsdir_fd = -1, .ra_piofolder = NULL, @@ -2308,9 +2309,16 @@ void odhcpd_reload(void) uci_unload(uci, system); if (config.dhcp_statefile) { - char *path = strdupa(config.dhcp_statefile); + char *dir = dirname(strdupa(config.dhcp_statefile)); + char *file = basename(config.dhcp_statefile); - mkdir_p(dirname(path), 0755); + memmove(config.dhcp_statefile, file, strlen(file) + 1); + mkdir_p(dir, 0755); + + close(config.dhcp_statedir_fd); + config.dhcp_statedir_fd = open(dir, O_PATH | O_DIRECTORY | O_CLOEXEC); + if (config.dhcp_statedir_fd < 0) + error("Unable to open statedir: '%s': %m", dir); } if (config.dhcp_hostsfile) { diff --git a/src/odhcpd.h b/src/odhcpd.h index 54bb973..337236d 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -201,7 +201,9 @@ struct config { bool enable_tz; bool main_dhcpv4; char *dhcp_cb; + char *dhcp_statefile; + int dhcp_statedir_fd; char *dhcp_hostsfile; int dhcp_hostsdir_fd; diff --git a/src/statefiles.c b/src/statefiles.c index 5cb4b5d..0e86940 100644 --- a/src/statefiles.c +++ b/src/statefiles.c @@ -224,60 +224,38 @@ err: void dhcpv6_ia_write_statefile(void) { struct write_ctxt ctxt; - unsigned statefile_strlen = strlen(config.dhcp_statefile) + 1; - unsigned tmp_statefile_strlen = statefile_strlen + 1; /* space for . */ - char *tmp_statefile = alloca(tmp_statefile_strlen); - - char *dir_statefile; - char *base_statefile; - char *pdir_statefile; - char *pbase_statefile; - + size_t tmp_statefile_strlen; + char *tmp_statefile; time_t now = odhcpd_time(), wall_time = time(NULL); - int fd, ret; char leasebuf[512]; + int fd; - if (!config.dhcp_statefile) + if (config.dhcp_statedir_fd < 0 || !config.dhcp_statefile) return; - md5_begin(&ctxt.md5); - dir_statefile = strndup(config.dhcp_statefile, statefile_strlen); - base_statefile = strndup(config.dhcp_statefile, statefile_strlen); - - pdir_statefile = dirname(dir_statefile); - pbase_statefile = basename(base_statefile); - - snprintf(tmp_statefile, tmp_statefile_strlen, "%s/.%s", pdir_statefile, pbase_statefile); - - free(dir_statefile); - free(base_statefile); + tmp_statefile_strlen = strlen(config.dhcp_statefile) + 2; + tmp_statefile = alloca(tmp_statefile_strlen); + sprintf(tmp_statefile, ".%s", config.dhcp_statefile); - fd = open(tmp_statefile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644); + fd = openat(config.dhcp_statedir_fd, tmp_statefile, 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; ctxt.buf = leasebuf; ctxt.buf_len = sizeof(leasebuf); + md5_begin(&ctxt.md5); 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)) @@ -364,7 +342,8 @@ void dhcpv6_ia_write_statefile(void) uint8_t newmd5[16]; md5_end(newmd5, &ctxt.md5); - rename(tmp_statefile, config.dhcp_statefile); + renameat(config.dhcp_statedir_fd, tmp_statefile, + config.dhcp_statedir_fd, config.dhcp_statefile); if (memcmp(newmd5, statemd5, sizeof(newmd5))) { memcpy(statemd5, newmd5, sizeof(statemd5)); @@ -379,5 +358,10 @@ void dhcpv6_ia_write_statefile(void) } } } -} + return; + +err: + error("Unable to write statefile: %m"); + close(fd); +}