MEDIUM: mworker: wait mode on reload failure

In Master Worker mode, when the reloading of the configuration fail,
the process is exiting leaving the children without their father.

To handle this, we register an exit function with atexit(3), which is
reexecuting the binary in a special mode. This particular mode of
HAProxy don't reload the configuration, it only loops on wait().
diff --git a/src/haproxy.c b/src/haproxy.c
index 1f40a12..c196d51 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -181,6 +181,8 @@
  */
 char *swap_buffer = NULL;
 
+int atexit_flag = 0;
+
 int nb_oldpids = 0;
 const int zero = 0;
 const int one = 1;
@@ -592,6 +594,7 @@
 
 		if (exitpid == -1 && errno == ECHILD) {
 			Warning("All workers are left. Leaving... (%d)\n", status);
+			atexit_flag = 0;
 			exit(status); /* parent must leave using the latest status code known */
 		}
 
@@ -618,6 +621,22 @@
 	}
 }
 
+
+/*
+ * Reexec the process in failure mode, instead of exiting
+ */
+void reexec_on_failure()
+{
+	if (!atexit_flag)
+		return;
+
+	setenv("HAPROXY_MWORKER_WAIT_ONLY", "1", 1);
+
+	Warning("Reexecuting Master process in waitpid mode\n");
+	mworker_reload();
+
+	Warning("Failed to reexecute the master processs\n");
+}
 
 
 /*
@@ -1270,6 +1289,18 @@
 		(arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
 			     | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
 
+	/* Master workers wait mode */
+	if ((global.mode & MODE_MWORKER) && (getenv("HAPROXY_MWORKER_WAIT_ONLY") != NULL)) {
+
+		unsetenv("HAPROXY_MWORKER_WAIT_ONLY");
+		mworker_wait();
+	}
+
+	if ((global.mode & MODE_MWORKER) && (getenv("HAPROXY_MWORKER_REEXEC") != NULL)) {
+		atexit_flag = 1;
+		atexit(reexec_on_failure);
+	}
+
 	if (change_dir && chdir(change_dir) < 0) {
 		Alert("Could not change to directory %s : %s\n", change_dir, strerror(errno));
 		exit(1);
@@ -2422,9 +2453,13 @@
 #ifndef OPENSSL_NO_DH
 			ssl_free_dh();
 #endif
-			exit(0); /* parent must leave */
+			/* should never get there */
+			exit(EXIT_FAILURE);
 		}
 
+		/* child must never use the atexit function */
+		atexit_flag = 0;
+
 		/* Must chroot and setgid/setuid in the children */
 		/* chroot if needed */
 		if (global.chroot != NULL) {