On Thu, Dec 28, 2017 at 12:54:27AM +0100, William Lallemand wrote:
> I think that's better to open /dev/null and dup2 with 0, 1, 2 so we won't 
> have any
> surprise with an fprintf(stderr, "..  anywhere in the code.
> 

Hi,

I made a patch which does exactly that, however I think we will do a cleanup of
how the quiet & verbose mode work for 1.9. It's a little bit messy, we should
never edit the mode.global flags outside of the configuration and command line
parsing.

Two patches attached, including Pieter's one which was reformated.

Regards,

-- 
William Lallemand
>From 74af850251e890bb1656c233bb3fd503eaea13bf Mon Sep 17 00:00:00 2001
From: PiBa-NL <[email protected]>
Date: Mon, 25 Dec 2017 21:03:31 +0100
Subject: [PATCH 1/2] BUG/MEDIUM: mworker: don't close stdio several time

This patch makes sure that a frontend socket that gets created after
initialization won't be closed when the master gets re-executed.

When used in daemon mode, the master-worker is closing the FDs 0, 1, 2
after the fork of the children.

When the master was reloading, those FDs were assigned again during the
parsing of the configuration (probably for some listeners), and the
workers were closing them thinking it was the stdio.

This patch must be backported to 1.8.
---
 src/haproxy.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/haproxy.c b/src/haproxy.c
index ffd7ea05e..f3970f7b6 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -2580,9 +2580,18 @@ int main(int argc, char **argv)
 
 	/* MODE_QUIET can inhibit alerts and warnings below this line */
 
-	if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
-		/* detach from the tty */
-		fclose(stdin); fclose(stdout); fclose(stderr);
+	if (getenv("HAPROXY_MWORKER_REEXEC") != NULL) {
+		// either stdin/out/err are already closed or should stay as they are.
+		if ((global.mode & MODE_DAEMON)) {
+			// daemon mode re-executing, stdin/stdout/stderr are already closed so keep quiet
+			global.mode &= ~MODE_VERBOSE;
+			global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
+		}
+	} else {
+		if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
+			/* detach from the tty */
+			fclose(stdin); fclose(stdout); fclose(stderr);
+		}
 	}
 
 	/* open log & pid files before the chroot */
-- 
2.13.6

>From 7c84c87eac8bf48e62bc8ee79cf6cec3ce33996d Mon Sep 17 00:00:00 2001
From: William Lallemand <[email protected]>
Date: Thu, 28 Dec 2017 16:09:36 +0100
Subject: [PATCH 2/2] MINOR: don't close stdio anymore

Closing the standard IO FDs (0,1,2) can be troublesome, especially in
the case of the master-worker.

Instead of closing those FDs, they are now pointing to /dev/null which
prevents sending debugging messages to the wrong FDs.

This patch could be backported in 1.8.
---
 src/haproxy.c | 43 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/src/haproxy.c b/src/haproxy.c
index f3970f7b6..2926af3ff 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -889,6 +889,32 @@ static void dump(struct sig_handler *sh)
 	pool_gc(NULL);
 }
 
+/*
+ *  This function dup2 the stdio FDs (0,1,2) with <fd>, then closes <fd>
+ *  If <fd> < 0, it opens /dev/null and use it to dup
+ *
+ *  In the case of chrooting, you have to open /dev/null before the chroot, and
+ *  pass the <fd> to this function
+ */
+static void stdio_quiet(int fd)
+{
+
+	if (fd < 0)
+		fd = open("/dev/null", O_RDWR, 0);
+
+	if (fd > -1) {
+		dup2(fd, 0);
+		dup2(fd, 1);
+		dup2(fd, 2);
+		close(fd);
+		return;
+	}
+
+	ha_alert("Cannot open /dev/null\n");
+	exit(EXIT_FAILURE);
+}
+
+
 /* This function check if cfg_cfgfiles containes directories.
  * If it find one, it add all the files (and only files) it containes
  * in cfg_cfgfiles in place of the directory (and remove the directory).
@@ -2590,7 +2616,7 @@ int main(int argc, char **argv)
 	} else {
 		if ((global.mode & MODE_QUIET) && !(global.mode & MODE_VERBOSE)) {
 			/* detach from the tty */
-			fclose(stdin); fclose(stdout); fclose(stderr);
+			stdio_quiet(-1);
 		}
 	}
 
@@ -2683,6 +2709,7 @@ int main(int argc, char **argv)
 		struct peers *curpeers;
 		int ret = 0;
 		int proc;
+		int devnullfd = -1;
 
 		children = calloc(global.nbproc, sizeof(int));
 		/*
@@ -2797,7 +2824,9 @@ int main(int argc, char **argv)
 				if ((!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
 					(global.mode & MODE_DAEMON)) {
 					/* detach from the tty, this is required to properly daemonize. */
-					fclose(stdin); fclose(stdout); fclose(stderr);
+					if ((getenv("HAPROXY_MWORKER_REEXEC") == NULL))
+						stdio_quiet(-1);
+
 					global.mode &= ~MODE_VERBOSE;
 					global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
 					setsid();
@@ -2816,6 +2845,14 @@ int main(int argc, char **argv)
 		/* child must never use the atexit function */
 		atexit_flag = 0;
 
+		if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
+			devnullfd = open("/dev/null", O_RDWR, 0);
+			if (devnullfd < 0) {
+				ha_alert("Cannot open /dev/null\n");
+				exit(EXIT_FAILURE);
+			}
+		}
+
 		/* Must chroot and setgid/setuid in the children */
 		/* chroot if needed */
 		if (global.chroot != NULL) {
@@ -2908,7 +2945,7 @@ int main(int argc, char **argv)
 		 */
 		if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
 			/* detach from the tty */
-			fclose(stdin); fclose(stdout); fclose(stderr);
+			stdio_quiet(devnullfd);
 			global.mode &= ~MODE_VERBOSE;
 			global.mode |= MODE_QUIET; /* ensure that we won't say anything from now */
 		}
-- 
2.13.6

Reply via email to