ntpd: default to FEATURE_NTP_AUTH=y
[oweals/busybox.git] / coreutils / tail.c
index 19fd8f6952a1e3b5a802ec186f35ec35f8250275..7335ba11e2e51449bbe36fac307bafb36fde4945 100644 (file)
@@ -6,11 +6,6 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
-
-/* BB_AUDIT SUSv3 compliant (need fancy for -c) */
-/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */
-/* http://www.opengroup.org/onlinepubs/007904975/utilities/tail.html */
-
 /* Mar 16, 2003      Manuel Novoa III   (mjn3@codepoet.org)
  *
  * Pretty much rewritten to fix numerous bugs and reduce realloc() calls.
  * 6) no check for lseek error
  * 7) lseek attempted when count==0 even if arg was +0 (from top)
  */
+//config:config TAIL
+//config:      bool "tail (7.1 kb)"
+//config:      default y
+//config:      help
+//config:      tail is used to print the last specified number of lines
+//config:      from files.
+//config:
+//config:config FEATURE_FANCY_TAIL
+//config:      bool "Enable -q, -s, -v, and -F options"
+//config:      default y
+//config:      depends on TAIL
+//config:      help
+//config:      These options are provided by GNU tail, but
+//config:      are not specified in the SUSv3 standard:
+//config:              -q      Never output headers giving file names
+//config:              -s SEC  Wait SEC seconds between reads with -f
+//config:              -v      Always output headers giving file names
+//config:              -F      Same as -f, but keep retrying
+
+//applet:IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP))
 
 //kbuild:lib-$(CONFIG_TAIL) += tail.o
-//kbuild:lib-$(CONFIG_TAIL) += head_tail.o
+
+/* BB_AUDIT SUSv3 compliant (need fancy for -c) */
+/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */
+/* http://www.opengroup.org/onlinepubs/007904975/utilities/tail.html */
 
 //usage:#define tail_trivial_usage
 //usage:       "[OPTIONS] [FILE]..."
 //usage:       "Print last 10 lines of each FILE (or stdin) to stdout.\n"
 //usage:       "With more than one FILE, precede each with a filename header.\n"
 //usage:     "\n       -f              Print data as file grows"
-//usage:       IF_FEATURE_FANCY_TAIL(
-//usage:     "\n       -s SECONDS      Wait SECONDS between reads with -f"
-//usage:       )
+//usage:     "\n       -c [+]N[kbm]    Print last N bytes"
 //usage:     "\n       -n N[kbm]       Print last N lines"
 //usage:     "\n       -n +N[kbm]      Start on Nth line and print the rest"
 //usage:       IF_FEATURE_FANCY_TAIL(
-//usage:     "\n       -c [+]N[kbm]    Print last N bytes"
 //usage:     "\n       -q              Never print headers"
+//usage:     "\n       -s SECONDS      Wait SECONDS between reads with -f"
 //usage:     "\n       -v              Always print headers"
+//usage:     "\n       -F              Same as -f, but keep retrying"
 //usage:     "\n"
 //usage:     "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)."
 //usage:       )
 //usage:       "nameserver 10.0.0.1\n"
 
 #include "libbb.h"
-#include "head_tail.h"
+#include "common_bufsiz.h"
 
 struct globals {
        bool from_top;
        bool exitcode;
 } FIX_ALIASING;
-#define G (*(struct globals*)&bb_common_bufsiz1)
-#define INIT_G() do { } while (0)
+#define G (*(struct globals*)bb_common_bufsiz1)
+#define INIT_G() do { setup_common_bufsiz(); } while (0)
 
 static void tail_xprint_header(const char *fmt, const char *filename)
 {
@@ -69,15 +86,6 @@ static void tail_xprint_header(const char *fmt, const char *filename)
 static ssize_t tail_read(int fd, char *buf, size_t count)
 {
        ssize_t r;
-       off_t current;
-       struct stat sbuf;
-
-       /* /proc files report zero st_size, don't lseek them. */
-       if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) {
-               current = lseek(fd, 0, SEEK_CUR);
-               if (sbuf.st_size < current)
-                       xlseek(fd, 0, SEEK_SET);
-       }
 
        r = full_read(fd, buf, count);
        if (r < 0) {
@@ -98,7 +106,7 @@ static unsigned eat_num(const char *p)
                p++;
                G.from_top = 1;
        }
-       return xatou_sfx(p, head_tail_suffixes);
+       return xatou_sfx(p, bkm_suffixes);
 }
 
 int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -116,6 +124,7 @@ int tail_main(int argc, char **argv)
 
        int *fds;
        const char *fmt;
+       int prev_fd;
 
        INIT_G();
 
@@ -131,9 +140,11 @@ int tail_main(int argc, char **argv)
 #endif
 
        /* -s NUM, -F imlies -f */
-       IF_FEATURE_FANCY_TAIL(opt_complementary = "s+:Ff";)
-       opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:vF"),
-                       &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period));
+       opt = getopt32(argv, IF_FEATURE_FANCY_TAIL("^")
+                       "fc:n:"IF_FEATURE_FANCY_TAIL("qs:+vF")
+                       IF_FEATURE_FANCY_TAIL("\0" "Ff"),
+                       &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period)
+       );
 #define FOLLOW (opt & 0x1)
 #define COUNT_BYTES (opt & 0x2)
        //if (opt & 0x1) // -f
@@ -320,6 +331,7 @@ int tail_main(int argc, char **argv)
                        xwrite(STDOUT_FILENO, tailbuf, taillen);
                }
        } while (++i < nfiles);
+       prev_fd = fds[i-1];
 
        tailbuf = xrealloc(tailbuf, BUFSIZ);
 
@@ -363,10 +375,23 @@ int tail_main(int argc, char **argv)
                        if (nfiles > header_threshhold) {
                                fmt = header_fmt_str;
                        }
-                       while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) {
-                               if (fmt) {
+                       for (;;) {
+                               /* tail -f keeps following files even if they are truncated */
+                               struct stat sbuf;
+                               /* /proc files report zero st_size, don't lseek them */
+                               if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) {
+                                       off_t current = lseek(fd, 0, SEEK_CUR);
+                                       if (sbuf.st_size < current)
+                                               xlseek(fd, 0, SEEK_SET);
+                               }
+
+                               nread = tail_read(fd, tailbuf, BUFSIZ);
+                               if (nread <= 0)
+                                       break;
+                               if (fmt && (fd != prev_fd)) {
                                        tail_xprint_header(fmt, filename);
                                        fmt = NULL;
+                                       prev_fd = fd;
                                }
                                xwrite(STDOUT_FILENO, tailbuf, nread);
                        }