tail: implement -F
authorEric Lammerts <busybox@lists.lammerts.org>
Tue, 21 Jul 2009 22:31:27 +0000 (00:31 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 21 Jul 2009 22:31:27 +0000 (00:31 +0200)
function                                             old     new   delta
tail_main                                           1190    1494    +304

Signed-off-by: Eric Lammerts <busybox@lists.lammerts.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/Config.in
coreutils/tail.c

index 1bc047c9a34cfe95d5d4bd9bb0202193d093075e..cacfb9661a602374d0ecbd2fd0f7eefac6be344b 100644 (file)
@@ -635,7 +635,7 @@ config TAIL
          from files.
 
 config FEATURE_FANCY_TAIL
-       bool "Enable extra tail options (-q, -s, and -v)"
+       bool "Enable extra tail options (-q, -s, -v, and -F)"
        default y
        depends on TAIL
        help
index 3ce6be0bdbd8d89e454d1573163024542fc5d696..ef1326c831d9f0c512d7789e4c7ac0b333d1f109 100644 (file)
@@ -85,18 +85,15 @@ int tail_main(int argc, char **argv)
        unsigned count = 10;
        unsigned sleep_period = 1;
        bool from_top;
-       int header_threshhold = 1;
        const char *str_c, *str_n;
 
        char *tailbuf;
        size_t tailbufsize;
-       int taillen = 0;
-       int newlines_seen = 0;
-       int nfiles, nread, nwrite, i, opt;
-       unsigned seen;
+       unsigned header_threshhold = 1;
+       unsigned nfiles;
+       int i, opt;
 
        int *fds;
-       char *s, *buf;
        const char *fmt;
 
 #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL
@@ -110,8 +107,9 @@ int tail_main(int argc, char **argv)
        }
 #endif
 
-       IF_FEATURE_FANCY_TAIL(opt_complementary = "s+";) /* -s N */
-       opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:v"),
+       /* -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));
 #define FOLLOW (opt & 0x1)
 #define COUNT_BYTES (opt & 0x2)
@@ -119,8 +117,12 @@ int tail_main(int argc, char **argv)
        if (opt & 0x2) count = eat_num(str_c); // -c
        if (opt & 0x4) count = eat_num(str_n); // -n
 #if ENABLE_FEATURE_FANCY_TAIL
-       if (opt & 0x8) header_threshhold = INT_MAX; // -q
+       /* q: make it impossible for nfiles to be > header_threshhold */
+       if (opt & 0x8) header_threshhold = UINT_MAX; // -q
        if (opt & 0x20) header_threshhold = 0; // -v
+#define FOLLOW_RETRY (opt & 0x40)
+#else
+#define FOLLOW_RETRY 0
 #endif
        argc -= optind;
        argv += optind;
@@ -128,19 +130,21 @@ int tail_main(int argc, char **argv)
        G.status = EXIT_SUCCESS;
 
        /* open all the files */
-       fds = xmalloc(sizeof(int) * (argc + 1));
+       fds = xmalloc(sizeof(fds[0]) * (argc + 1));
        if (!argv[0]) {
                struct stat statbuf;
 
-               if (!fstat(STDIN_FILENO, &statbuf) && S_ISFIFO(statbuf.st_mode)) {
+               if (fstat(STDIN_FILENO, &statbuf) == 0
+                && S_ISFIFO(statbuf.st_mode)
+               ) {
                        opt &= ~1; /* clear FOLLOW */
                }
-               *argv = (char *) bb_msg_standard_input;
+               argv[0] = (char *) bb_msg_standard_input;
        }
        nfiles = i = 0;
        do {
                int fd = open_or_warn_stdin(argv[i]);
-               if (fd < 0) {
+               if (fd < 0 && !FOLLOW_RETRY) {
                        G.status = EXIT_FAILURE;
                        continue;
                }
@@ -161,9 +165,18 @@ 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 + 1; /* skip header leading newline on first output */
        i = 0;
        do {
+               char *buf;
+               int taillen;
+               int newlines_seen;
+               unsigned seen;
+               int nread;
+
+               if (ENABLE_FEATURE_FANCY_TAIL && fds[i] < 0)
+                       continue; /* may happen with -E */
+
                if (nfiles > header_threshhold) {
                        tail_xprint_header(fmt, argv[i]);
                        fmt = header_fmt;
@@ -192,13 +205,13 @@ int tail_main(int argc, char **argv)
                newlines_seen = 0;
                while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
                        if (from_top) {
-                               nwrite = nread;
+                               int nwrite = nread;
                                if (seen < count) {
                                        if (COUNT_BYTES) {
                                                nwrite -= (count - seen);
                                                seen = count;
                                        } else {
-                                               s = buf;
+                                               char *s = buf;
                                                do {
                                                        --nwrite;
                                                        if (*s++ == '\n' && ++seen == count) {
@@ -231,6 +244,7 @@ int tail_main(int argc, char **argv)
                                                taillen += nread;
                                        } else {
                                                int extra = (buf[nread-1] != '\n');
+                                               char *s;
 
                                                k = newlines_seen + newlines_in_buf + extra - count;
                                                s = tailbuf;
@@ -257,23 +271,54 @@ int tail_main(int argc, char **argv)
                }
        } while (++i < nfiles);
 
-       buf = xrealloc(tailbuf, BUFSIZ);
+       tailbuf = xrealloc(tailbuf, BUFSIZ);
 
        fmt = NULL;
 
        if (FOLLOW) while (1) {
                sleep(sleep_period);
+
                i = 0;
                do {
+                       int nread;
+                       const char *filename = argv[i];
+                       int fd = fds[i];
+
+                       if (FOLLOW_RETRY) {
+                               struct stat sbuf, fsbuf;
+
+                               if (fd < 0
+                                || fstat(fd, &fsbuf) < 0
+                                || stat(filename, &sbuf) < 0
+                                || fsbuf.st_dev != sbuf.st_dev
+                                || fsbuf.st_ino != sbuf.st_ino
+                               ) {
+                                       int new_fd;
+
+                                       if (fd >= 0)
+                                               close(fd);
+                                       new_fd = open(filename, O_RDONLY);
+                                       if (new_fd >= 0) {
+                                               bb_error_msg("%s has %s; following end of new file",
+                                                       filename, (fd < 0) ? "appeared" : "been replaced"
+                                               );
+                                       } else if (fd >= 0) {
+                                               bb_perror_msg("%s has become inaccessible", filename);
+                                       }
+                                       fds[i] = fd = new_fd;
+                               }
+                       }
+                       if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)
+                               continue;
                        if (nfiles > header_threshhold) {
                                fmt = header_fmt;
                        }
-                       while ((nread = tail_read(fds[i], buf, BUFSIZ)) > 0) {
+                       while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) {
                                if (fmt) {
-                                       tail_xprint_header(fmt, argv[i]);
+                                       tail_xprint_header(fmt, filename);
                                        fmt = NULL;
                                }
-                               xwrite(STDOUT_FILENO, buf, nread);
+                               xwrite(STDOUT_FILENO, tailbuf, nread);
                        }
                } while (++i < nfiles);
        }