From 242603fa46bb68428d1bac66ded6fbf7ae8e2605 Mon Sep 17 00:00:00 2001
From: Paul Smith <psmith@gnu.org>
Date: Sun, 24 Mar 2024 15:19:11 -0400
Subject: [PATCH] [SV 65268] Un-set append mode for stdout/stderr on exit

It turns out that options set on stdout/stderr last after exit.
Leaving append-mode enabled can break other facilities, so reset the
flags on stdout/stderr before we exit.

* src/os.h: Add a new fd_reset_append() to reset flags on FDs.
Modify fd_set_append() to return the old flags.
* src/posixos.c (fd_reset_append): Set provided flags on the FD.
(fd_set_append): Return the previous flags set on the FD.
* src/output.c (output_init): Preserve old flags for stdout/stderr.
(output_close): Reset flags for stdout/stderr.
* src/w32/w32os.c: Implement dummy methods.
---
 src/os.h        | 23 ++++++++++++++---------
 src/output.c    |  9 +++++++--
 src/posixos.c   | 20 ++++++++++++++++++--
 src/w32/w32os.c |  9 +++++++--
 4 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/src/os.h b/src/os.h
index be98372d..3ab790b0 100644
--- a/src/os.h
+++ b/src/os.h
@@ -21,22 +21,27 @@ this program.  If not, see <https://www.gnu.org/licenses/>.  */
 #define IO_STDERR_OK            0x0010
 
 #if MK_OS_VMS || MK_OS_DOS
-# define check_io_state()  (IO_STDIN_OK|IO_STDOUT_OK|IO_STDERR_OK)
-# define fd_inherit(_i)    (0)
-# define fd_noinherit(_i)  (0)
-# define fd_set_append(_i) (void)(0)
-# define os_anontmp()      (-1)
+# define check_io_state()       (IO_STDIN_OK|IO_STDOUT_OK|IO_STDERR_OK)
+# define fd_inherit(_i)         (0)
+# define fd_noinherit(_i)       (0)
+# define fd_set_append(_i)      (-1)
+# define fd_reset_append(_i,_f) (void)(0)
+# define os_anontmp()           (-1)
 #else
 
 /* Determine the state of stdin/stdout/stderr.  */
 unsigned int check_io_state (void);
 
 /* Set a file descriptor to close/not close in a subprocess.  */
-void fd_inherit (int);
-void fd_noinherit (int);
+void fd_inherit (int fd);
+void fd_noinherit (int fd);
 
-/* If the file descriptor is for a file put it into append mode.  */
-void fd_set_append (int);
+/* If the file descriptor is for a file put it into append mode.
+   Return the original flags for the file descriptor, or -1 if not found.  */
+int fd_set_append (int fd);
+
+/* Reset the append mode to the flags returned by fd_set_append().  */
+void fd_reset_append (int fd, int flags);
 
 /* Return a file descriptor for a new anonymous temp file, or -1.  */
 int os_anontmp (void);
diff --git a/src/output.c b/src/output.c
index e6589817..775d1410 100644
--- a/src/output.c
+++ b/src/output.c
@@ -318,6 +318,9 @@ output_dump (struct output *out)
 #endif /* NO_OUTPUT_SYNC */
 
 
+static int stdout_flags = -1;
+static int stderr_flags = -1;
+
 void
 output_init (struct output *out)
 {
@@ -330,8 +333,8 @@ output_init (struct output *out)
 
   /* Force stdout/stderr into append mode (if they are files) to ensure
      parallel jobs won't lose output due to overlapping writes.  */
-  fd_set_append (fileno (stdout));
-  fd_set_append (fileno (stderr));
+  stdout_flags = fd_set_append (fileno (stdout));
+  stderr_flags = fd_set_append (fileno (stderr));
 }
 
 void
@@ -341,6 +344,8 @@ output_close (struct output *out)
     {
       if (stdio_traced)
         log_working_directory (0);
+      fd_reset_append(fileno (stdout), stdout_flags);
+      fd_reset_append(fileno (stderr), stderr_flags);
       return;
     }
 
diff --git a/src/posixos.c b/src/posixos.c
index bc6558df..7a723591 100644
--- a/src/posixos.c
+++ b/src/posixos.c
@@ -830,12 +830,12 @@ fd_noinherit (int fd)
 /* Set a file descriptor referring to a regular file to be in O_APPEND mode.
    If it fails, just ignore it.  */
 
-void
+int
 fd_set_append (int fd)
 {
+  int flags = -1;
 #if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
   struct stat stbuf;
-  int flags;
   if (fstat (fd, &stbuf) == 0 && S_ISREG (stbuf.st_mode))
     {
       flags = fcntl (fd, F_GETFL, 0);
@@ -845,6 +845,22 @@ fd_set_append (int fd)
           EINTRLOOP(r, fcntl (fd, F_SETFL, flags | O_APPEND));
         }
     }
+#endif
+  return flags;
+}
+
+/* Reset a file descriptor referring to a regular file to be in O_APPEND mode.
+   If it fails, just ignore it.  */
+
+void
+fd_reset_append (int fd, int flags)
+{
+#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
+  if (flags >= 0)
+    {
+      int r;
+      EINTRLOOP(r, fcntl (fd, F_SETFL, flags));
+    }
 #endif
 }
 
diff --git a/src/w32/w32os.c b/src/w32/w32os.c
index ae2a6853..ac8fc59c 100644
--- a/src/w32/w32os.c
+++ b/src/w32/w32os.c
@@ -512,10 +512,15 @@ fd_noinherit(int fd)
         SetHandleInformation (fh, HANDLE_FLAG_INHERIT, 0);
 }
 
-void
+int
 fd_set_append (int fd UNUSED)
-{}
+{
+  return -1;
+}
 
+void
+fd_reset_append (int fd UNUSED, int flags UNUSED)
+{}
 
 HANDLE
 get_handle_for_fd (int fd)