]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: workaround an eglibc bug which truncates the pidfiles when nbproc > 1
authorWilly Tarreau <w@1wt.eu>
Wed, 5 Sep 2012 06:02:48 +0000 (08:02 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 5 Sep 2012 13:04:20 +0000 (15:04 +0200)
Thomas Heil reported that when using nbproc > 1, his pidfiles were
regularly truncated. The issue could be tracked down to the presence
of a call to lseek(pidfile, 0, SEEK_SET) just before the close() call
in the children, resulting in the file being truncated by the children
while the parent was feeding it. This unexpected lseek() is transparently
performed by fclose().

Since there is no way to have the file automatically closed during the
fork, the only solution is to bypass the libc and use open/write/close
instead of fprintf() and fclose().

The issue was observed on eglibc 2.15.

src/haproxy.c

index 4e75080306b46b652599d95af5b3b94d5fd02ad2..7439a4c98c4567b824d2f32b4516f16a56f4519a 100644 (file)
@@ -1148,8 +1148,8 @@ int main(int argc, char **argv)
 {
        int err, retry;
        struct rlimit limit;
-       FILE *pidfile = NULL;
        char errmsg[100];
+       int pidfd = -1;
 
        init(argc, argv);
        signal_register_fct(SIGQUIT, dump, SIGQUIT);
@@ -1264,7 +1264,6 @@ int main(int argc, char **argv)
 
        /* open log & pid files before the chroot */
        if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
-               int pidfd;
                unlink(global.pidfile);
                pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
                if (pidfd < 0) {
@@ -1274,7 +1273,6 @@ int main(int argc, char **argv)
                        protocol_unbind_all();
                        exit(1);
                }
-               pidfile = fdopen(pidfd, "w");
        }
 
 #ifdef CONFIG_HAP_CTTPROXY
@@ -1362,15 +1360,18 @@ int main(int argc, char **argv)
                        }
                        else if (ret == 0) /* child breaks here */
                                break;
-                       if (pidfile != NULL) {
-                               fprintf(pidfile, "%d\n", ret);
-                               fflush(pidfile);
+                       if (pidfd >= 0) {
+                               char pidstr[100];
+                               snprintf(pidstr, sizeof(pidstr), "%d\n", ret);
+                               write(pidfd, pidstr, strlen(pidstr));
                        }
                        relative_pid++; /* each child will get a different one */
                }
                /* close the pidfile both in children and father */
-               if (pidfile != NULL)
-                       fclose(pidfile);
+               if (pidfd >= 0) {
+                       //lseek(pidfd, 0, SEEK_SET);  /* debug: emulate eglibc bug */
+                       close(pidfd);
+               }
 
                /* We won't ever use this anymore */
                free(oldpids);        oldpids = NULL;