From 55a44676fa586b749718f7d24d6c579a02e2a398 Mon Sep 17 00:00:00 2001
From: Rob Landley <rob@landley.net>
Date: Mon, 21 Dec 2015 14:34:36 -0600
Subject: Cleanup tail -f.

---
 toys/posix/tail.c | 94 +++++++++++++++++++------------------------------------
 1 file changed, 32 insertions(+), 62 deletions(-)

diff --git a/toys/posix/tail.c b/toys/posix/tail.c
index c2f71cbd..a00bfa0c 100644
--- a/toys/posix/tail.c
+++ b/toys/posix/tail.c
@@ -29,21 +29,13 @@ config TAIL_SEEK
 
 #define FOR_tail
 #include "toys.h"
-
 #include <sys/inotify.h>
 
-struct file_info {
-  int fd;
-  int wd;
-  const char* path;
-};
-
 GLOBALS(
   long lines;
   long bytes;
 
-  int file_no;
-  struct file_info *files;
+  int file_no, ffd, *files;
 )
 
 struct line_list {
@@ -143,16 +135,21 @@ static void do_tail(int fd, char *name)
   long bytes = TT.bytes, lines = TT.lines;
   int linepop = 1;
 
+  if (toys.optflags & FLAG_f) {
+    int f = TT.file_no*2;
+    char *s = name;
+
+    if (!fd) sprintf(s = toybuf, "/proc/self/fd/%d", fd);
+    TT.files[f++] = fd;
+    if (0 > (TT.files[f] = inotify_add_watch(TT.ffd, s, IN_MODIFY)))
+      perror_msg("bad -f on '%s'", name);
+  }
+
   if (toys.optc > 1) {
-    if (TT.file_no > 0) xputc('\n');
+    if (TT.file_no++) xputc('\n');
     xprintf("==> %s <==\n", name);
   }
 
-  // -f support: cache name/descriptor
-  TT.files[TT.file_no].fd = dup(fd);
-  TT.files[TT.file_no].path = strdup(name);
-  ++TT.file_no;
-
   // Are we measuring from the end of the file?
 
   if (bytes<0 || lines<0) {
@@ -240,60 +237,33 @@ void tail_main(void)
     TT.lines = -10;
   }
 
-  TT.files = xmalloc(toys.optc * sizeof(struct file_info));
-  loopfiles(args, do_tail);
+  // Allocate 2 ints per optarg for -f
+  if (toys.optflags&FLAG_f) {
+    if ((TT.ffd = inotify_init()) < 0) perror_exit("inotify_init");
+    TT.files = xmalloc(toys.optc*8);
+  }
+  loopfiles_rw(args, O_RDONLY|(O_CLOEXEC*!(toys.optflags&FLAG_f)),
+    0, 0, do_tail);
 
-  // do -f stuff
   if (toys.optflags & FLAG_f) {
-    int infd, last_wd, i;
-
-    infd = inotify_init();
-    if (infd < 0) {
-      perror_exit("failed to create inotify fd");
-    }
-
-    for (i = 0; i < TT.file_no; ++i) {
-      #define STR(x) #x
-      char path[sizeof("/proc/self/fd/" STR(INT_MIN))];
+    int len, last_fd = TT.files[(TT.file_no-1)*2], i, fd;
+    struct inotify_event ev;
 
-      snprintf(path, sizeof(path), "/proc/self/fd/%d", TT.files[i].fd);
-
-      TT.files[i].wd = inotify_add_watch(infd, path, IN_MODIFY);
-      if (TT.files[i].wd < 0) {
-        perror_msg("failed to add inotify watch for %s", TT.files[i].path);
-        continue;
-      }
-    }
-
-    last_wd = TT.files[TT.file_no - 1].wd;
-
-    while (1) {
-      struct inotify_event ev;
-      int len;
+    for (;;) {
+      if (sizeof(ev)!=read(TT.ffd, &ev, sizeof(ev))) perror_exit("inotify");
 
-      len = read(infd, &ev, sizeof(ev));
-      if (len < 0) {
-        perror_exit("inotify read failed");
-      }
+      for (i = 0; i<TT.file_no && ev.wd!=TT.files[(i*2)+1]; i++);
+      if (i==TT.file_no) continue;
+      fd = TT.files[i*2];
 
-      for (i = 0; i < TT.file_no; ++i) {
-        if (ev.wd != TT.files[i].wd) {
-          continue;
+      // Read new data.
+      while ((len = read(fd, toybuf, sizeof(toybuf)))>0) {
+        if (last_fd != fd) {
+          last_fd = fd;
+          xprintf("\n==> %s <==\n", args[i]);
         }
 
-        // Read until we hit the end.
-        while (1) {
-          len = read(TT.files[i].fd, toybuf, sizeof(toybuf));
-          if (len <= 0) break;
-
-          if (last_wd != TT.files[i].wd) {
-            last_wd = TT.files[i].wd;
-            xprintf("\n==> %s <==\n", TT.files[i].path);
-          }
-
-          xwrite(1, toybuf, len);
-        }
-        break;
+        xwrite(1, toybuf, len);
       }
     }
   }
-- 
cgit v1.2.3