[PATCH] make should not turn the append mode on its stdout

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] make should not turn the append mode on its stdout

0xef967c36
Since O_APPEND is common to all the file descriptors referring to an
open file, this breaks other processes which have an open handle
to the same file.

On Linux, this behaviour of make cause a subsequent splice(2) or
sendfile(2) on the same file to fail, /even/ if the file is a tty
or a character device like /dev/null:

--------------------->snip<-----------------------
$ cat >scat.c <<'EOT'
#define _GNU_SOURCE
#include <fcntl.h>
#include <err.h>
int main(int ac, char **av){
        int r;
        while((r = splice(0, 0, 1, 0, 4096, 0))) if(r < 0) err(1, "splice");
}
EOT
$ cc -Wall scat.c -o scat
$ true | ./scat # OK the first time
$ make 2>/dev/null
$ true | ./scat
scat: splice: Invalid argument # WHY?

$ true | ./scat >/dev/null
$ { make 2>/dev/null; true | ./scat; } >/dev/null
scat: splice: Invalid argument
--------------------->snip<-----------------------

A real fix would be to get rid of this behavior (and maybe just warn
if the output is a /seekable file/ /not/ in a append mode, so the user
should know to run ">log; make -j13 >> log" instead).

But in the meanwhile you could at least only set O_APPEND on
/regular/ files, not on ttys/devices, pipes, sockets, etc:

diff --git a/src/output.c b/src/output.c
index 2211749..16c3456 100644
--- a/src/output.c
+++ b/src/output.c
@@ -144,14 +144,18 @@ log_working_directory (int entering)
   return 1;
 }
 
-/* Set a file descriptor to be in O_APPEND mode.
-   If it fails, just ignore it.  */
+/* Set a file descriptor referring to a regular file
+   to be in O_APPEND mode.  If it fails, just ignore it.  */
 
 static void
 set_append_mode (int fd)
 {
 #if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
-  int flags = fcntl (fd, F_GETFL, 0);
+  struct stat stbuf;
+  int flags;
+  if (fstat (fd, &stbuf) != 0 || !S_ISREG (stbuf.st_mode))
+    return;
+  flags = fcntl (fd, F_GETFL, 0);
   if (flags >= 0)
     {
       int r;