lineedit: do not hang on error, but return error indicator.
[oweals/busybox.git] / coreutils / tail.c
index 5f98bff820ee292cb6aefba69abf657f499fbb26..44698f304d38e575e30e9b7a95241387f0be5755 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
  *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 
 /* BB_AUDIT SUSv3 compliant (need fancy for -c) */
@@ -30,12 +30,12 @@ static const struct suffix_mult tail_suffixes[] = {
        { "b", 512 },
        { "k", 1024 },
        { "m", 1024*1024 },
-       { }
+       { "", 0 }
 };
 
 struct globals {
        bool status;
-};
+} FIX_ALIASING;
 #define G (*(struct globals*)&bb_common_bufsiz1)
 
 static void tail_xprint_header(const char *fmt, const char *filename)
@@ -51,10 +51,10 @@ static ssize_t tail_read(int fd, char *buf, size_t count)
        struct stat sbuf;
 
        /* /proc files report zero st_size, don't lseek them. */
-       if (fstat(fd, &sbuf) == 0 && sbuf.st_size) {
+       if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) {
                current = lseek(fd, 0, SEEK_CUR);
                if (sbuf.st_size < current)
-                       lseek(fd, 0, SEEK_SET);
+                       xlseek(fd, 0, SEEK_SET);
        }
 
        r = full_read(fd, buf, count);
@@ -66,7 +66,7 @@ static ssize_t tail_read(int fd, char *buf, size_t count)
        return r;
 }
 
-static const char header_fmt[] ALIGN1 = "\n==> %s <==\n";
+#define header_fmt_str "\n==> %s <==\n"
 
 static unsigned eat_num(const char *p)
 {
@@ -166,7 +166,7 @@ int tail_main(int argc, char **argv)
        tailbuf = xmalloc(tailbufsize);
 
        /* tail the files */
-       fmt = header_fmt + 1; /* skip header leading newline on first output */
+       fmt = header_fmt_str + 1; /* skip header leading newline on first output */
        i = 0;
        do {
                char *buf;
@@ -174,39 +174,56 @@ int tail_main(int argc, char **argv)
                int newlines_seen;
                unsigned seen;
                int nread;
+               int fd = fds[i];
 
-               if (ENABLE_FEATURE_FANCY_TAIL && fds[i] < 0)
+               if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)
                        continue; /* may happen with -E */
 
                if (nfiles > header_threshhold) {
                        tail_xprint_header(fmt, argv[i]);
-                       fmt = header_fmt;
+                       fmt = header_fmt_str;
                }
 
-               /* Optimizing count-bytes case if the file is seekable.
-                * Beware of backing up too far.
-                * Also we exclude files with size 0 (because of /proc/xxx) */
-               if (COUNT_BYTES && !from_top) {
-                       off_t current = lseek(fds[i], 0, SEEK_END);
+               if (!from_top) {
+                       off_t current = lseek(fd, 0, SEEK_END);
                        if (current > 0) {
-                               if (count == 0)
-                                       continue; /* showing zero bytes is easy :) */
-                               current -= count;
+                               unsigned off;
+                               if (COUNT_BYTES) {
+                               /* Optimizing count-bytes case if the file is seekable.
+                                * Beware of backing up too far.
+                                * Also we exclude files with size 0 (because of /proc/xxx) */
+                                       if (count == 0)
+                                               continue; /* showing zero bytes is easy :) */
+                                       current -= count;
+                                       if (current < 0)
+                                               current = 0;
+                                       xlseek(fd, current, SEEK_SET);
+                                       bb_copyfd_size(fd, STDOUT_FILENO, count);
+                                       continue;
+                               }
+#if 1 /* This is technically incorrect for *LONG* strings, but very useful */
+                               /* Optimizing count-lines case if the file is seekable.
+                                * We assume the lines are <64k.
+                                * (Users complain that tail takes too long
+                                * on multi-gigabyte files) */
+                               off = (count | 0xf); /* for small counts, be more paranoid */
+                               if (off > (INT_MAX / (64*1024)))
+                                       off = (INT_MAX / (64*1024));
+                               current -= off * (64*1024);
                                if (current < 0)
                                        current = 0;
-                               xlseek(fds[i], current, SEEK_SET);
-                               bb_copyfd_size(fds[i], STDOUT_FILENO, count);
-                               continue;
+                               xlseek(fd, current, SEEK_SET);
+#endif
                        }
                }
 
                buf = tailbuf;
                taillen = 0;
                /* "We saw 1st line/byte".
-                * Used only by +N code ("start from Nth", 1-based) */
+                * Used only by +N code ("start from Nth", 1-based): */
                seen = 1;
                newlines_seen = 0;
-               while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
+               while ((nread = tail_read(fd, buf, tailbufsize-taillen)) > 0) {
                        if (from_top) {
                                int nwrite = nread;
                                if (seen < count) {
@@ -224,7 +241,8 @@ int tail_main(int argc, char **argv)
                                                } while (nwrite);
                                        }
                                }
-                               xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite);
+                               if (nwrite > 0)
+                                       xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite);
                        } else if (count) {
                                if (COUNT_BYTES) {
                                        taillen += nread;
@@ -315,7 +333,7 @@ int tail_main(int argc, char **argv)
                        if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)
                                continue;
                        if (nfiles > header_threshhold) {
-                               fmt = header_fmt;
+                               fmt = header_fmt_str;
                        }
                        while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) {
                                if (fmt) {