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.
diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c
index 8485dcd..e373483 100644
--- a/src/haproxy-systemd-wrapper.c
+++ b/src/haproxy-systemd-wrapper.c
@@ -18,9 +18,11 @@
 #include <unistd.h>
 #include <sys/wait.h>
 
+#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 @@
 {
 	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 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 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)
 		;