From 21253610f9ef87db8e2a75b863b7fcfbd0cdb421 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <darrick.wong@oracle.com>
Date: Tue, 25 Jul 2017 13:45:01 -0500
Subject: [PATCH] In patch 4944defad4 ("xfs_db: redirect printfs when
 metadumping to stdout"), we solved the problem of xfs_db printfs ending up in
 the metadump stream by reassigning stdout for the duration of a stdout
 metadump.  Unfortunately, musl doesn't allow stdout to be reassigned (in
 their view "extern FILE *stdout" means "extern FILE * const stdout"), so we
 abandon the old approach in favor of playing games with dup() to switch the
 raw file descriptors.

While we're at it, fix a regression where an unconverted outf test
allows progress info to end up in the metadump stream.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 db/metadump.c | 47 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 11 deletions(-)

diff --git a/db/metadump.c b/db/metadump.c
index 96641e0..4e2f648 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -78,6 +78,7 @@ static int		obfuscate = 1;
 static int		zero_stale_data = 1;
 static int		show_warnings = 0;
 static int		progress_since_warning = 0;
+static bool		stdout_metadump;
 
 void
 metadump_init(void)
@@ -137,7 +138,7 @@ print_progress(const char *fmt, ...)
 	va_end(ap);
 	buf[sizeof(buf)-1] = '\0';
 
-	f = (outf == stdout) ? stderr : stdout;
+	f = stdout_metadump ? stderr : stdout;
 	fprintf(f, "\r%-59s", buf);
 	fflush(f);
 	progress_since_warning = 1;
@@ -2750,7 +2751,8 @@ metadump_f(
 	xfs_agnumber_t	agno;
 	int		c;
 	int		start_iocur_sp;
-	bool		stdout_metadump = false;
+	int		outfd = -1;
+	int		ret;
 	char		*p;
 
 	exitcode = 1;
@@ -2870,16 +2872,35 @@ metadump_f(
 		 * metadump operation so that dbprintf and other messages
 		 * are sent to the console instead of polluting the
 		 * metadump stream.
+		 *
+		 * We get to do this the hard way because musl doesn't
+		 * allow reassignment of stdout.
 		 */
-		outf = stdout;
-		stdout = stderr;
+		fflush(stdout);
+		outfd = dup(STDOUT_FILENO);
+		if (outfd < 0) {
+			perror("opening dump stream");
+			goto out;
+		}
+		ret = dup2(STDERR_FILENO, STDOUT_FILENO);
+		if (ret < 0) {
+			perror("redirecting stdout");
+			close(outfd);
+			goto out;
+		}
+		outf = fdopen(outfd, "a");
+		if (outf == NULL) {
+			fprintf(stderr, "cannot create dump stream\n");
+			dup2(outfd, 1);
+			close(outfd);
+			goto out;
+		}
 		stdout_metadump = true;
 	} else {
 		outf = fopen(argv[optind], "wb");
 		if (outf == NULL) {
 			print_warning("cannot create dump file");
-			free(metablock);
-			return 0;
+			goto out;
 		}
 	}
 
@@ -2907,15 +2928,19 @@ metadump_f(
 	if (progress_since_warning)
 		fputc('\n', stdout_metadump ? stderr : stdout);
 
-	if (stdout_metadump)
-		stdout = outf;
-	else
-		fclose(outf);
+	if (stdout_metadump) {
+		fflush(outf);
+		fflush(stdout);
+		ret = dup2(outfd, STDOUT_FILENO);
+		if (ret < 0)
+			perror("un-redirecting stdout");
+	}
+	fclose(outf);
 
 	/* cleanup iocur stack */
 	while (iocur_sp > start_iocur_sp)
 		pop_cur();
-
+out:
 	free(metablock);
 
 	return 0;
-- 
2.13.3
