coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] tail: do not let failed lseek cause immediate exit


From: Jim Meyering
Subject: [PATCH] tail: do not let failed lseek cause immediate exit
Date: Fri, 03 Aug 2012 16:45:14 +0200

Here is a proposed patch.
It's a nice-to-have change, but big and complicated enough
that it's not a shoe-in this close to a release.
I'm posting it for the record, but am inclined not to push it
until after 8.18.

Also, it doesn't have a NEWS entry, though considering how hard
it is to trigger an lseek failure on a known-open-and-valid
read-only file descriptor, maybe it doesn't deserve one.
WDYT?


>From a714f9a350a3b69aec03ee2a0c74b627d8138542 Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Wed, 25 Jul 2012 18:26:35 +0200
Subject: [PATCH] tail: do not let failed lseek cause immediate exit

It is long-standing coreutils policy that an error in operating on
one of many input files must not terminate execution when it can be
useful to continue processing the remaining input files.  However,
tail has been using an lseek wrapper (xlseek) that exits upon failure.
That could make tail exit before processing all files listed on
the command line, or (with -f) make tail terminate.
* src/tail.c (xlseek): Don't exit.  Return offset or -1.
Adjust most uses.
Convert one use to a simple lseek call with diagnosed failure.
* TODO: Remove corresponding entry.
---
 TODO       |  3 ---
 src/tail.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/TODO b/TODO
index cd434e5..1326f0e 100644
--- a/TODO
+++ b/TODO
@@ -64,9 +64,6 @@ I don't plan to do that, since a few tests demonstrate no 
significant benefit.

 printf: consider adapting builtins/printf.def from bash

-tail: don't use xlseek; it *exits*.
-  Instead, maybe use a macro and return nonzero.
-
 tr: support nontrivial equivalence classes, e.g. [=e=] with LC_COLLATE=fr_FR

 lib/strftime.c: Since %N is the only format that we need but that
diff --git a/src/tail.c b/src/tail.c
index 290ada4..0b47453 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -430,7 +430,7 @@ dump_remainder (const char *pretty_filename, int fd, 
uintmax_t n_bytes)

 /* Call lseek with the specified arguments, where file descriptor FD
    corresponds to the file, FILENAME.
-   Give a diagnostic and exit nonzero if lseek fails.
+   Give a diagnostic and return -1 if lseek fails.
    Otherwise, return the resulting offset.  */

 static off_t
@@ -461,8 +461,7 @@ xlseek (int fd, off_t offset, int whence, char const 
*filename)
     default:
       abort ();
     }
-
-  exit (EXIT_FAILURE);
+  return new_offset;
 }

 /* Print the last N_LINES lines from the end of file FD.
@@ -493,7 +492,8 @@ file_lines (const char *pretty_filename, int fd, uintmax_t 
n_lines,
   /* Make 'pos' a multiple of 'BUFSIZ' (0 if the file is short), so that all
      reads will be on block boundaries, which might increase efficiency.  */
   pos -= bytes_read;
-  xlseek (fd, pos, SEEK_SET, pretty_filename);
+  if (xlseek (fd, pos, SEEK_SET, pretty_filename) < 0)
+    return false;
   bytes_read = safe_read (fd, buffer, bytes_read);
   if (bytes_read == SAFE_READ_ERROR)
     {
@@ -535,13 +535,15 @@ file_lines (const char *pretty_filename, int fd, 
uintmax_t n_lines,
         {
           /* Not enough lines in the file; print everything from
              start_pos to the end.  */
-          xlseek (fd, start_pos, SEEK_SET, pretty_filename);
+          if (xlseek (fd, start_pos, SEEK_SET, pretty_filename) < 0)
+            return false;
           *read_pos = start_pos + dump_remainder (pretty_filename, fd,
                                                   end_pos);
           return true;
         }
       pos -= BUFSIZ;
-      xlseek (fd, pos, SEEK_SET, pretty_filename);
+      if (xlseek (fd, pos, SEEK_SET, pretty_filename) < 0)
+        return false;

       bytes_read = safe_read (fd, buffer, BUFSIZ);
       if (bytes_read == SAFE_READ_ERROR)
@@ -1050,7 +1052,14 @@ recheck (struct File_spec *f, bool blocking)
     {
       /* Start at the beginning of the file.  */
       record_open_fd (f, fd, 0, &new_stats, (is_stdin ? -1 : blocking));
-      xlseek (fd, 0, SEEK_SET, pretty_name (f));
+      if (xlseek (fd, 0, SEEK_SET, pretty_name (f)) < 0)
+        {
+          f->errnum = -1;
+          f->ignore = true;
+          close_fd (fd, pretty_name (f));
+          close_fd (f->fd, pretty_name (f));
+          f->fd = -1;
+        }
     }
 }

@@ -1172,7 +1181,15 @@ tail_forever (struct File_spec *f, size_t n_files, 
double sleep_interval)
                 {
                   error (0, 0, _("%s: file truncated"), name);
                   last = i;
-                  xlseek (fd, stats.st_size, SEEK_SET, name);
+                  if (lseek (fd, stats.st_size, SEEK_SET) < 0)
+                    {
+                      f[i].errnum = errno;
+                      f[i].fd = -1;
+                      error (0, errno,
+                             _("%s: failed to lseek to new end of file"), 
name);
+                      close (fd); /* ignore failure */
+                      continue;
+                    }
                   f[i].size = stats.st_size;
                   continue;
                 }
@@ -1286,8 +1303,14 @@ check_fspec (struct File_spec *fspec, int wd, int 
*prev_wd)
   if (S_ISREG (fspec->mode) && stats.st_size < fspec->size)
     {
       error (0, 0, _("%s: file truncated"), name);
+      if (xlseek (fspec->fd, stats.st_size, SEEK_SET, name) < 0)
+        {
+          fspec->errnum = errno;
+          close_fd (fspec->fd, name);
+          fspec->fd = -1;
+          return;
+        }
       *prev_wd = wd;
-      xlseek (fspec->fd, stats.st_size, SEEK_SET, name);
       fspec->size = stats.st_size;
     }
   else if (S_ISREG (fspec->mode) && stats.st_size == fspec->size
@@ -1599,7 +1622,8 @@ tail_bytes (const char *pretty_filename, int fd, 
uintmax_t n_bytes,
       if ( ! presume_input_pipe
            && S_ISREG (stats.st_mode) && n_bytes <= OFF_T_MAX)
         {
-          xlseek (fd, n_bytes, SEEK_CUR, pretty_filename);
+          if (xlseek (fd, n_bytes, SEEK_CUR, pretty_filename) < 0)
+            return false;
           *read_pos += n_bytes;
         }
       else
@@ -1617,11 +1641,14 @@ tail_bytes (const char *pretty_filename, int fd, 
uintmax_t n_bytes,
         {
           off_t current_pos = xlseek (fd, 0, SEEK_CUR, pretty_filename);
           off_t end_pos = xlseek (fd, 0, SEEK_END, pretty_filename);
+          if (current_pos < 0 || end_pos < 0)
+            return false;
           off_t diff = end_pos - current_pos;
           /* Be careful here.  The current position may actually be
              beyond the end of the file.  */
           off_t bytes_remaining = diff < 0 ? 0 : diff;
           off_t nb = n_bytes;
+          off_t pos;

           if (bytes_remaining <= nb)
             {
@@ -1629,14 +1656,17 @@ tail_bytes (const char *pretty_filename, int fd, 
uintmax_t n_bytes,
                  more bytes than have been requested.  So reposition the
                  file pointer to the incoming current position and print
                  everything after that.  */
-              *read_pos = xlseek (fd, current_pos, SEEK_SET, pretty_filename);
+              pos = xlseek (fd, current_pos, SEEK_SET, pretty_filename);
             }
           else
             {
               /* There are more bytes remaining than were requested.
                  Back up.  */
-              *read_pos = xlseek (fd, -nb, SEEK_END, pretty_filename);
+              pos = xlseek (fd, -nb, SEEK_END, pretty_filename);
             }
+          if (pos < 0)
+            return false;
+          *read_pos = pos;
           *read_pos += dump_remainder (pretty_filename, fd, n_bytes);
         }
       else
@@ -1692,7 +1722,10 @@ tail_lines (const char *pretty_filename, int fd, 
uintmax_t n_lines,
              via the 'lseek (...SEEK_END)' above.  In that case, reposition
              the file pointer back to start_pos before calling pipe_lines.  */
           if (start_pos != -1)
-            xlseek (fd, start_pos, SEEK_SET, pretty_filename);
+            {
+              if (xlseek (fd, start_pos, SEEK_SET, pretty_filename) < 0)
+                return false;
+            }

           return pipe_lines (pretty_filename, fd, n_lines, read_pos);
         }
--
1.7.12.rc1.10.g97c7934



reply via email to

[Prev in Thread] Current Thread [Next in Thread]