From b3fce6ef4d1db7b87c3b7294088a5fe62ca2fe8e Mon Sep 17 00:00:00 2001 From: Apollon Oikonomopoulos Date: Thu, 17 Apr 2014 16:39:28 +0300 Subject: [PATCH] MINOR: systemd wrapper: re-execute on SIGUSR2 Re-execute the systemd wrapper on SIGUSR2 and before reloading HAProxy, making it possible to load a completely new version of HAProxy (including a new version of the systemd wrapper) gracefully. Since the wrapper accepts no command-line arguments of its own, re-execution is signaled using the HAPROXY_SYSTEMD_REEXEC environment variable. This is primarily intended to help seamless upgrades of distribution packages. --- src/haproxy-systemd-wrapper.c | 54 ++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c index 8485dcd11d..e373483d50 100644 --- a/src/haproxy-systemd-wrapper.c +++ b/src/haproxy-systemd-wrapper.c @@ -18,9 +18,11 @@ #include #include +#define REEXEC_FLAG "HAPROXY_SYSTEMD_REEXEC" + static char *pid_file = "/run/haproxy.pid"; -static int main_argc; -static char **main_argv; +static int wrapper_argc; +static char **wrapper_argv; static void locate_haproxy(char *buffer, size_t buffer_size) { @@ -42,6 +44,11 @@ static void spawn_haproxy(char **pid_strv, int nb_pid) { char haproxy_bin[512]; pid_t pid; + int main_argc; + char **main_argv; + + main_argc = wrapper_argc - 1; + main_argv = wrapper_argv + 1; pid = fork(); if (!pid) { @@ -96,15 +103,10 @@ static int read_pids(char ***pid_strv) static void sigusr2_handler(int signum __attribute__((unused))) { - int i; - char **pid_strv = NULL; - int nb_pid = read_pids(&pid_strv); + setenv(REEXEC_FLAG, "1", 1); + printf("haproxy-systemd-wrapper: re-executing\n"); - spawn_haproxy(pid_strv, nb_pid); - - for (i = 0; i < nb_pid; ++i) - free(pid_strv[i]); - free(pid_strv); + execv(wrapper_argv[0], wrapper_argv); } static void sigint_handler(int signum __attribute__((unused))) @@ -140,16 +142,40 @@ int main(int argc, char **argv) { int status; - --argc; ++argv; - main_argc = argc; - main_argv = argv; + wrapper_argc = argc; + wrapper_argv = argv; + --argc; ++argv; init(argc, argv); signal(SIGINT, &sigint_handler); signal(SIGUSR2, &sigusr2_handler); - spawn_haproxy(NULL, 0); + if (getenv(REEXEC_FLAG) != NULL) { + /* We are being re-executed: restart HAProxy gracefully */ + int i; + char **pid_strv = NULL; + int nb_pid = read_pids(&pid_strv); + sigset_t sigs; + + unsetenv(REEXEC_FLAG); + spawn_haproxy(pid_strv, nb_pid); + + /* Unblock SIGUSR2 which was blocked by the signal handler + * before re-exec */ + sigprocmask(SIG_BLOCK, NULL, &sigs); + sigdelset(&sigs, SIGUSR2); + sigprocmask(SIG_SETMASK, &sigs, NULL); + + for (i = 0; i < nb_pid; ++i) + free(pid_strv[i]); + free(pid_strv); + } + else { + /* Start a fresh copy of HAProxy */ + spawn_haproxy(NULL, 0); + } + status = -1; while (-1 != wait(&status) || errno == EINTR) ;