From a92c0a73d018cd6453dcf253d9617f97311becab Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Fri, 21 Oct 2022 14:28:59 +0100 Subject: dhcpv6-ia: make tmp lease file hidden Use a hidden . prefixed temporary lease file instead of appending '.tmp'. Dnsmasq is capable of scanning files/directories using inotify to receive file change notifications and updating its view of hostname ip address mapping without being SIGHUPped. Until dnsmasq v2.88 this mechanism allows additions to hostnames, no deletions. dnsmasq v2.88 when released will understand how to remove mappings. Unfortunately without this change dnsmasq sees odhcpd's temporary lease file via inotify and it also sees the change when odhcpd atomically renames the file from '.tmp' to the correct name. dnsmasq excludes hidden '.' files from it's inotify scans, thus changing odhcpd to use a hidden temporary lease file reduces load and makes sense. Also, while here, only rename the temporary file if it actually contains different content. Signed-off-by: Kevin Darbyshire-Bryant --- src/dhcpv6-ia.c | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index e8255b5..99fd2fd 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -320,13 +321,29 @@ void dhcpv6_ia_write_statefile(void) md5_begin(&ctxt.md5); if (config.dhcp_statefile) { - unsigned tmp_statefile_strlen = strlen(config.dhcp_statefile) + strlen(".tmp") + 1; + 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; + time_t now = odhcpd_time(), wall_time = time(NULL); int fd, ret; char leasebuf[512]; - snprintf(tmp_statefile, tmp_statefile_strlen, "%s.tmp", config.dhcp_statefile); + 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); fd = open(tmp_statefile, O_CREAT | O_WRONLY | O_CLOEXEC, 0644); if (fd < 0) @@ -437,18 +454,22 @@ void dhcpv6_ia_write_statefile(void) fclose(ctxt.fp); - rename(tmp_statefile, config.dhcp_statefile); - } + uint8_t newmd5[16]; + md5_end(newmd5, &ctxt.md5); - uint8_t newmd5[16]; - md5_end(newmd5, &ctxt.md5); + if (memcmp(newmd5, statemd5, sizeof(newmd5))) { + memcpy(statemd5, newmd5, sizeof(statemd5)); + rename(tmp_statefile, config.dhcp_statefile); - if (config.dhcp_cb && memcmp(newmd5, statemd5, sizeof(newmd5))) { - memcpy(statemd5, newmd5, sizeof(statemd5)); - char *argv[2] = {config.dhcp_cb, NULL}; - if (!vfork()) { - execv(argv[0], argv); - _exit(128); + if (config.dhcp_cb) { + char *argv[2] = {config.dhcp_cb, NULL}; + if (!vfork()) { + execv(argv[0], argv); + _exit(128); + } + } + } else { + unlink(tmp_statefile); } } } -- cgit v1.2.3