diff -Naur a/toys/posix/tail.c b/toys/posix/tail.c
--- a/toys/posix/tail.c	2014-10-02 18:23:27.000000000 +0530
+++ b/toys/posix/tail.c	2014-10-07 09:43:22.789569474 +0530
@@ -1,6 +1,7 @@
 /* tail.c - copy last lines from input to stdout.
  *
  * Copyright 2012 Timothy Elliott <tle@holymonkey.com>
+ * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
  *
  * See http://opengroup.org/onlinepubs/9699919799/utilities/tail.html
 
@@ -33,8 +34,6 @@
 GLOBALS(
   long lines;
   long bytes;
-
-  int file_no;
 )
 
 struct line_list {
@@ -128,90 +127,138 @@
   return 1;
 }
 
-// Called for each file listed on command line, and/or stdin
-static void do_tail(int fd, char *name)
+// loops thru each file listed on command line, and/or stdin
+void tail_main(void)
 {
-  long bytes = TT.bytes, lines = TT.lines;
-  int linepop = 1;
+  long bytes, lines;
+  int fd = fd, fd_prev, linepop = 1, i = 0, file_no = 0, fnum = 0, *fds;
+  char **ss = toys.optargs;
 
-  if (toys.optc > 1) {
-    if (TT.file_no++) xputc('\n');
-    xprintf("==> %s <==\n", name);
-  }
+  //incase of no files, fd = 0,stdin
+  fds = xzalloc(sizeof(*fds) * (toys.optc + 1));
 
-  // Are we measuring from the end of the file?
+  // if nothing specified, default -n to -10
+  if (!(toys.optflags&(FLAG_n|FLAG_c))) TT.lines = -10;
+  bytes = TT.bytes, lines = TT.lines;
 
-  if (bytes<0 || lines<0) {
-    struct line_list *list = 0, *new;
+  do {
+    if (ss[i]) {
+      if (!strcmp(ss[i], "-")) fd = 0;
+      else fd = open(ss[i], O_RDONLY);
+      if (fd >= 0) fds[fnum++] = fd;
+    }
+    if (toys.optc && fd < 0) {
+      perror_msg("%s",ss[i]);
+      continue;
+    }
+    if (toys.optc > 1) {
+      if (file_no++) xputc('\n');
+      xprintf("==> %s <==\n", toys.optargs[i]);
+    }
 
-    // The slow codepath is always needed, and can handle all input,
-    // so make lseek support optional.
-    if (CFG_TAIL_SEEK && try_lseek(fd, bytes, lines)) return;
-
-    // Read data until we run out, keep a trailing buffer
-    for (;;) {
-      // Read next page of data, appending to linked list in order
-      if (!(new = get_chunk(fd, sizeof(toybuf)))) break;
-      dlist_add_nomalloc((void *)&list, (void *)new);
-
-      // If tracing bytes, add until we have enough, discarding overflow.
-      if (TT.bytes) {
-        bytes += new->len;
-        if (bytes > 0) {
-          while (list->len <= bytes) {
-            bytes -= list->len;
-            free(dlist_pop(&list));
+    if (!toys.optc) fd = 0;
+    // Are we measuring from the end of the file?
+
+    if (bytes<0 || lines<0) {
+      struct line_list *list = 0, *new;
+
+      // The slow codepath is always needed, and can handle all input,
+      // so make lseek support optional.
+      try_lseek(fd, bytes, lines);
+      // Read data until we run out, keep a trailing buffer
+      for (;;) {
+        // Read next page of data, appending to linked list in order
+        if (!(new = get_chunk(fd, sizeof(toybuf)))) break;
+        dlist_add_nomalloc((void *)&list, (void *)new);
+
+        // If tracing bytes, add until we have enough, discarding overflow.
+        if (TT.bytes) {
+          bytes += new->len;
+          if (bytes > 0) {
+            while (list->len <= bytes) {
+              bytes -= list->len;
+              free(dlist_pop(&list));
+            }
           }
-          list->data += bytes;
-          list->len -= bytes;
-        }
-      } else {
-        int len = new->len, count;
-        char *try = new->data;
-
-        // First character _after_ a newline starts a new line, which
-        // works even if file doesn't end with a newline
-        for (count=0; count<len; count++) {
-          if (linepop) lines++;
-          linepop = try[count] == '\n';
-
-          if (lines > 0) {
-            do {
-              if (!--(list->len)) free(dlist_pop(&list));
-            } while (*(list->data++) != '\n');
-            lines--;
+        } else {
+          int len = new->len, count;
+          char *try = new->data;
+
+          // First character _after_ a newline starts a new line, which
+          // works even if file doesn't end with a newline
+          for (count=0; count<len; count++) {
+            if (linepop) lines++;
+            linepop = try[count] == '\n';
+
+            if (lines > 0) {
+              do {
+                if (!--(list->len)) free(dlist_pop(&list));
+              } while (*(list->data++) != '\n');
+              lines--;
+            }
           }
         }
       }
-    }
 
-    // Output/free the buffer.
-    llist_traverse(list, dump_chunk);
+      if (TT.bytes && bytes > 0) {
+        list->data += bytes;
+        list->len -= bytes;
+      }
+
+      // Output/free the buffer.
+      llist_traverse(list, dump_chunk);
 
-  // Measuring from the beginning of the file.
-  } else for (;;) {
-    int len, offset = 0;
-
-    // Error while reading does not exit.  Error writing does.
-    len = read(fd, toybuf, sizeof(toybuf));
-    if (len<1) break;
-    while (bytes > 1 || lines > 1) {
-      bytes--;
-      if (toybuf[offset++] == '\n') lines--;
-      if (offset >= len) break;
+      // Measuring from the beginning of the file.
+    } else for (;;) {
+      int len, offset = 0;
+
+      // Error while reading does not exit.  Error writing does.
+      len = read(fd, toybuf, sizeof(toybuf));
+
+      if (len<1) break;
+      while (bytes > 1 || lines > 1) {
+        bytes--;
+        if (toybuf[offset++] == '\n') lines--;
+        if (offset >= len) break;
+      }
+      if (offset<len) xwrite(1, toybuf+offset, len-offset);
     }
-    if (offset<len) xwrite(1, toybuf+offset, len-offset);
-  }
+  } while (++i < toys.optc);
 
-  // -f support: cache name/descriptor
-}
+  fd_prev = fnum?fds[fnum-1] : 0;
+  if (!fnum) return;
 
-void tail_main(void)
-{
-  // if nothing specified, default -n to -10
-  if (!(toys.optflags&(FLAG_n|FLAG_c))) TT.lines = -10;
+  if (toys.optflags & FLAG_f) {
+    while (1) {
+      i = 0;
+      usleep(10000);
+
+      do {
+        int rbytes;
+
+        fd = fds[i];
+        for (;;) {
+          struct stat st;
 
-  loopfiles(toys.optargs, do_tail);
+          if (!fstat(fd, &st) && st.st_size >= 0) {
+            off_t size = lseek(fd, 0, SEEK_CUR);
 
-  // do -f stuff
+            if (st.st_size < size) xlseek(fd, 0, SEEK_SET);
+          }
+          rbytes = read(fd, toybuf, sizeof(toybuf));
+          if (rbytes < 1) break;
+          if (fd != fd_prev) {
+            xprintf("\n==> %s <==\n", toys.optargs[i]);
+            fd_prev = fd;
+          }
+          xwrite(1, toybuf, rbytes);
+        }
+      } while (++i < fnum);
+    }
+  }
+
+  if (CFG_TOYBOX_FREE) {
+    for (i = 0; i < fnum && fds[i]>0; i++) close(fds[i]);
+    free(fds);
+  }
 }
