]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cat: fix plain ‘cat’ bug
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 14 Feb 2025 21:10:02 +0000 (13:10 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 14 Feb 2025 21:13:08 +0000 (13:13 -0800)
* src/cat.c (main): Do not fail with plain ‘cat’ where input and
output are both /dev/tty, if the output happens to have O_APPEND set.
Problem reported by lilydjwg <https://bugs.gnu.org/76255>.
Also, don’t report an error if the seek position is at or after EOF,
even if O_APPEND is set.

NEWS
src/cat.c

diff --git a/NEWS b/NEWS
index c9ba5f1965cd90435fda8133095f01ad5eb25f0d..c6edf16d41ed58bf8fc5fb9a0bc83403d29fdfc9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,7 +4,11 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** Bug fixes
 
-  `ls -Z dir` would crash.
+  'cat' would fail with "input file is output file" if input and
+  output are the same terminal device and the output is append-only.
+  [bug introduced in coreutils-9.6]
+
+  'ls -Z dir' would crash.
   [bug introduced in coreutils-9.6]
 
 
index 274f844a16a14959d60e65c28fcaa70ef5150e9a..c02210301d6cda1eb4a992258004cf416bb9ffa0 100644 (file)
--- a/src/cat.c
+++ b/src/cat.c
@@ -717,20 +717,20 @@ main (int argc, char **argv)
           && have_out_dev
           && stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino)
         {
-          if (out_flags < -1)
-            out_flags = fcntl (STDOUT_FILENO, F_GETFL);
-          bool exhausting = 0 <= out_flags && out_flags & O_APPEND;
-          if (!exhausting)
+          off_t in_pos = lseek (input_desc, 0, SEEK_CUR);
+          if (0 <= in_pos)
             {
-              off_t in_pos = lseek (input_desc, 0, SEEK_CUR);
-              if (0 <= in_pos)
-                exhausting = in_pos < lseek (STDOUT_FILENO, 0, SEEK_CUR);
-            }
-          if (exhausting)
-            {
-              error (0, 0, _("%s: input file is output file"), quotef (infile));
-              ok = false;
-              goto contin;
+              if (out_flags < -1)
+                out_flags = fcntl (STDOUT_FILENO, F_GETFL);
+              int whence = (0 <= out_flags && out_flags & O_APPEND
+                            ? SEEK_END : SEEK_CUR);
+              if (in_pos < lseek (STDOUT_FILENO, 0, whence))
+                {
+                  error (0, 0, _("%s: input file is output file"),
+                         quotef (infile));
+                  ok = false;
+                  goto contin;
+                }
             }
         }