diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c index f4fcab106..b426f96c0 100644 --- a/src/haproxy-systemd-wrapper.c +++ b/src/haproxy-systemd-wrapper.c @@ -65,16 +65,30 @@ static void locate_haproxy(char *buffer, size_t buffer_size) return; } +/* Note: this function must not exit in case of error (except in the child), as + * it is only dedicated the starting a new haproxy process. By keeping the + * process alive it will ensure that future signal delivery may get rid of + * the issue. If the first startup fails, the wrapper will notice it and + * return an error thanks to wait() returning ECHILD. + */ static void spawn_haproxy(char **pid_strv, int nb_pid) { char haproxy_bin[512]; pid_t pid; int main_argc; char **main_argv; + int pipefd[2]; + char fdstr[20]; + int ret; main_argc = wrapper_argc - 1; main_argv = wrapper_argv + 1; + if (pipe(pipefd) != 0) { + fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: failed to create a pipe, please try again later.\n"); + return; + } + pid = fork(); if (!pid) { char **argv; @@ -89,6 +103,15 @@ static void spawn_haproxy(char **pid_strv, int nb_pid) } reset_signal_handler(); + + close(pipefd[0]); /* close the read side */ + + snprintf(fdstr, sizeof(fdstr), "%d", pipefd[1]); + if (setenv("HAPROXY_WRAPPER_FD", fdstr, 1) != 0) { + fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: failed to setenv(), please try again later.\n"); + exit(1); + } + locate_haproxy(haproxy_bin, 512); argv[argno++] = haproxy_bin; for (i = 0; i < main_argc; ++i) @@ -113,6 +136,19 @@ static void spawn_haproxy(char **pid_strv, int nb_pid) else if (pid == -1) { fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: failed to fork(), please try again later.\n"); } + + /* The parent closes the write side and waits for the child to close it + * as well. Also deal the case where the fd would unexpectedly be 1 or 2 + * by silently draining all data. + */ + close(pipefd[1]); + + do { + char c; + ret = read(pipefd[0], &c, sizeof(c)); + } while ((ret > 0) || (ret == -1 && errno == EINTR)); + /* the child has finished starting up */ + close(pipefd[0]); } static int read_pids(char ***pid_strv) diff --git a/src/haproxy.c b/src/haproxy.c index b1c10b66d..8198e4efc 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1962,6 +1962,7 @@ int main(int argc, char **argv) int ret = 0; int *children = calloc(global.nbproc, sizeof(int)); int proc; + char *wrapper_fd; /* the father launches the required number of processes */ for (proc = 0; proc < global.nbproc; proc++) { @@ -1998,6 +1999,15 @@ int main(int argc, char **argv) close(pidfd); } + /* each child must notify the wrapper that it's ready by closing the requested fd */ + wrapper_fd = getenv("HAPROXY_WRAPPER_FD"); + if (wrapper_fd) { + int pipe_fd = atoi(wrapper_fd); + + if (pipe_fd >= 0) + close(pipe_fd); + } + /* We won't ever use this anymore */ free(oldpids); oldpids = NULL; free(global.chroot); global.chroot = NULL;