dhcpv6-ia: make tmp lease file hidden
authorKevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
Fri, 21 Oct 2022 13:28:59 +0000 (14:28 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Mon, 24 Oct 2022 19:52:14 +0000 (21:52 +0200)
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 <ldir@darbyshire-bryant.me.uk>
src/dhcpv6-ia.c

index e8255b5c0381a45b6cbe8d6bf8bd43725430af93..99fd2fda61cab453158ef8e4ea05fe903d210994 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <libgen.h>
 #include <stdbool.h>
 #include <arpa/inet.h>
 #include <sys/timerfd.h>
@@ -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);
                }
        }
 }