0ab8f11b01b2a962395e39de242d5671dc72cdf3
[oweals/busybox.git] / tail.c
1 #include "internal.h"
2 /* This file contains _two_ implementations of tail.  One is
3  * a bit more full featured, but costs 6k.  The other (i.e. the
4  * SIMPLE_TAIL one) is less capable, but is good enough for about
5  * 99% of the things folks want to use tail for, and only costs 2k.
6  */
7
8
9 #ifdef BB_FEATURE_SIMPLE_TAIL
10
11 /* tail -- output the last part of file(s)
12    Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
13
14    This program is free software; you can redistribute it and/or modify
15    it under the terms of the GNU General Public License as published by
16    the Free Software Foundation; either version 2, or (at your option)
17    any later version.
18
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License for more details.
23
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
28    Original version by Paul Rubin <phr@ocf.berkeley.edu>.
29    Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
30    tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.  
31
32    Rewrote the option parser, removed locales support,
33     and generally busyboxed, Erik Andersen <andersen@lineo.com>
34
35    Removed superfluous options and associated code ("-c", "-n", "-q").
36    Removed "tail -f" support for multiple files.
37    Both changes by Friedrich Vedder <fwv@myrtle.lahn.de>.
38
39  */
40
41
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <ctype.h>
48
49
50 #define XWRITE(fd, buffer, n_bytes)                                     \
51   do {                                                                  \
52       if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0)  \
53           error("write error");                                 \
54   } while (0)
55
56 /* Number of items to tail.  */
57 #define DEFAULT_N_LINES 10
58
59 /* Size of atomic reads.  */
60 #ifndef BUFSIZ
61 #define BUFSIZ (512 * 8)
62 #endif
63
64 /* If nonzero, read from the end of one file until killed.  */
65 static int forever;
66
67 /* If nonzero, print filename headers.  */
68 static int print_headers;
69
70 const char tail_usage[] =
71     "tail [OPTION] [FILE]...\n\n"
72     "Print last 10 lines of each FILE to standard output.\n"
73     "With more than one FILE, precede each with a header giving the\n"
74     "file name. With no FILE, or when FILE is -, read standard input.\n\n"
75     "Options:\n"
76     "\t-n NUM\t\tPrint last NUM lines instead of first 10\n"
77     "\t-f\t\tOutput data as the file grows.  This version\n"
78     "\t\t\tof 'tail -f' supports only one file at a time.\n";
79
80
81 static void write_header(const char *filename)
82 {
83     static int first_file = 1;
84
85     printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
86     first_file = 0;
87 }
88
89 /* Print the last N_LINES lines from the end of file FD.
90    Go backward through the file, reading `BUFSIZ' bytes at a time (except
91    probably the first), until we hit the start of the file or have
92    read NUMBER newlines.
93    POS starts out as the length of the file (the offset of the last
94    byte of the file + 1).
95    Return 0 if successful, 1 if an error occurred.  */
96
97 static int
98 file_lines(const char *filename, int fd, long int n_lines, off_t pos)
99 {
100     char buffer[BUFSIZ];
101     int bytes_read;
102     int i;                      /* Index into `buffer' for scanning.  */
103
104     if (n_lines == 0)
105         return 0;
106
107     /* Set `bytes_read' to the size of the last, probably partial, buffer;
108        0 < `bytes_read' <= `BUFSIZ'.  */
109     bytes_read = pos % BUFSIZ;
110     if (bytes_read == 0)
111         bytes_read = BUFSIZ;
112     /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
113        reads will be on block boundaries, which might increase efficiency.  */
114     pos -= bytes_read;
115     lseek(fd, pos, SEEK_SET);
116     bytes_read = fullRead(fd, buffer, bytes_read);
117     if (bytes_read == -1)
118         error("read error");
119
120     /* Count the incomplete line on files that don't end with a newline.  */
121     if (bytes_read && buffer[bytes_read - 1] != '\n')
122         --n_lines;
123
124     do {
125         /* Scan backward, counting the newlines in this bufferfull.  */
126         for (i = bytes_read - 1; i >= 0; i--) {
127             /* Have we counted the requested number of newlines yet?  */
128             if (buffer[i] == '\n' && n_lines-- == 0) {
129                 /* If this newline wasn't the last character in the buffer,
130                    print the text after it.  */
131                 if (i != bytes_read - 1)
132                     XWRITE(STDOUT_FILENO, &buffer[i + 1],
133                            bytes_read - (i + 1));
134                 return 0;
135             }
136         }
137         /* Not enough newlines in that bufferfull.  */
138         if (pos == 0) {
139             /* Not enough lines in the file; print the entire file.  */
140             lseek(fd, (off_t) 0, SEEK_SET);
141             return 0;
142         }
143         pos -= BUFSIZ;
144         lseek(fd, pos, SEEK_SET);
145     }
146     while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
147     if (bytes_read == -1)
148         error("read error");
149
150     return 0;
151 }
152
153 /* Print the last N_LINES lines from the end of the standard input,
154    open for reading as pipe FD.
155    Buffer the text as a linked list of LBUFFERs, adding them as needed.
156    Return 0 if successful, 1 if an error occured.  */
157
158 static int pipe_lines(const char *filename, int fd, long int n_lines)
159 {
160     struct linebuffer {
161         int nbytes, nlines;
162         char buffer[BUFSIZ];
163         struct linebuffer *next;
164     };
165     typedef struct linebuffer LBUFFER;
166     LBUFFER *first, *last, *tmp;
167     int i;                      /* Index into buffers.  */
168     int total_lines = 0;        /* Total number of newlines in all buffers.  */
169     int errors = 0;
170
171     first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
172     first->nbytes = first->nlines = 0;
173     first->next = NULL;
174     tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
175
176     /* Input is always read into a fresh buffer.  */
177     while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
178         tmp->nlines = 0;
179         tmp->next = NULL;
180
181         /* Count the number of newlines just read.  */
182         for (i = 0; i < tmp->nbytes; i++)
183             if (tmp->buffer[i] == '\n')
184                 ++tmp->nlines;
185         total_lines += tmp->nlines;
186
187         /* If there is enough room in the last buffer read, just append the new
188            one to it.  This is because when reading from a pipe, `nbytes' can
189            often be very small.  */
190         if (tmp->nbytes + last->nbytes < BUFSIZ) {
191             memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
192             last->nbytes += tmp->nbytes;
193             last->nlines += tmp->nlines;
194         } else {
195             /* If there's not enough room, link the new buffer onto the end of
196                the list, then either free up the oldest buffer for the next
197                read if that would leave enough lines, or else malloc a new one.
198                Some compaction mechanism is possible but probably not
199                worthwhile.  */
200             last = last->next = tmp;
201             if (total_lines - first->nlines > n_lines) {
202                 tmp = first;
203                 total_lines -= first->nlines;
204                 first = first->next;
205             } else
206                 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
207         }
208     }
209     if (tmp->nbytes == -1)
210         error("read error");
211
212     free((char *) tmp);
213
214     /* This prevents a core dump when the pipe contains no newlines.  */
215     if (n_lines == 0)
216         goto free_lbuffers;
217
218     /* Count the incomplete line on files that don't end with a newline.  */
219     if (last->buffer[last->nbytes - 1] != '\n') {
220         ++last->nlines;
221         ++total_lines;
222     }
223
224     /* Run through the list, printing lines.  First, skip over unneeded
225        buffers.  */
226     for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
227         total_lines -= tmp->nlines;
228
229     /* Find the correct beginning, then print the rest of the file.  */
230     if (total_lines > n_lines) {
231         char *cp;
232
233         /* Skip `total_lines' - `n_lines' newlines.  We made sure that
234            `total_lines' - `n_lines' <= `tmp->nlines'.  */
235         cp = tmp->buffer;
236         for (i = total_lines - n_lines; i; --i)
237             while (*cp++ != '\n')
238                 /* Do nothing.  */ ;
239         i = cp - tmp->buffer;
240     } else
241         i = 0;
242     XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
243
244     for (tmp = tmp->next; tmp; tmp = tmp->next)
245         XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
246
247   free_lbuffers:
248     while (first) {
249         tmp = first->next;
250         free((char *) first);
251         first = tmp;
252     }
253     return errors;
254 }
255
256 /* Display file FILENAME from the current position in FD to the end.
257    If `forever' is nonzero, keep reading from the end of the file
258    until killed.  Return the number of bytes read from the file.  */
259
260 static long dump_remainder(const char *filename, int fd)
261 {
262     char buffer[BUFSIZ];
263     int bytes_read;
264     long total;
265
266     total = 0;
267   output:
268     while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
269         XWRITE(STDOUT_FILENO, buffer, bytes_read);
270         total += bytes_read;
271     }
272     if (bytes_read == -1)
273         error("read error");
274     if (forever) {
275         fflush(stdout);
276         sleep(1);
277         goto output;
278     }
279
280     return total;
281 }
282
283 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
284    Return 0 if successful, 1 if an error occurred.  */
285
286 static int tail_lines(const char *filename, int fd, long int n_lines)
287 {
288     struct stat stats;
289     off_t length;
290
291     if (print_headers)
292         write_header(filename);
293
294     if (fstat(fd, &stats))
295         error("fstat error");
296
297     /* Use file_lines only if FD refers to a regular file with
298        its file pointer positioned at beginning of file.  */
299     /* FIXME: adding the lseek conjunct is a kludge.
300        Once there's a reasonable test suite, fix the true culprit:
301        file_lines.  file_lines shouldn't presume that the input
302        file pointer is initially positioned to beginning of file.  */
303     if (S_ISREG(stats.st_mode)
304         && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
305         length = lseek(fd, (off_t) 0, SEEK_END);
306         if (length != 0 && file_lines(filename, fd, n_lines, length))
307             return 1;
308         dump_remainder(filename, fd);
309     } else
310         return pipe_lines(filename, fd, n_lines);
311
312     return 0;
313 }
314
315 /* Display the last N_UNITS lines of file FILENAME.
316    "-" for FILENAME means the standard input.
317    Return 0 if successful, 1 if an error occurred.  */
318
319 static int tail_file(const char *filename, off_t n_units)
320 {
321     int fd, errors;
322
323     if (!strcmp(filename, "-")) {
324         filename = "standard input";
325         errors = tail_lines(filename, 0, (long) n_units);
326     } else {
327         /* Not standard input.  */
328         fd = open(filename, O_RDONLY);
329         if (fd == -1)
330             error("open error");
331
332         errors = tail_lines(filename, fd, (long) n_units);
333         close(fd);
334     }
335
336     return errors;
337 }
338
339 extern int tail_main(int argc, char **argv)
340 {
341     int exit_status = 0;
342     int n_units = DEFAULT_N_LINES;
343     int n_tmp, i;
344     char opt;
345
346     forever = print_headers = 0;
347
348     /* parse argv[] */
349     for (i = 1; i < argc; i++) {
350         if (argv[i][0] == '-') {
351             opt = argv[i][1];
352             switch (opt) {
353             case 'f':
354                 forever = 1;
355                 break;
356             case 'n':
357                 n_tmp = 0;
358                 if (++i < argc)
359                     n_tmp = atoi(argv[i]);
360                 if (n_tmp < 1)
361                     usage(tail_usage);
362                 n_units = n_tmp;
363                 break;
364             case '-':
365             case 'h':
366                 usage(tail_usage);
367             default:
368                 fprintf(stderr, "tail: invalid option -- %c\n", opt);
369                 usage(tail_usage);
370             }
371         } else {
372             break;
373         }
374     }
375
376     if (i + 1 < argc) {
377         if (forever) {
378             fprintf(stderr,
379                     "tail: option -f is invalid with multiple files\n");
380             usage(tail_usage);
381         }
382         print_headers = 1;
383     }
384
385     if (i >= argc) {
386         exit_status |= tail_file("-", n_units);
387     } else {
388         for (; i < argc; i++)
389             exit_status |= tail_file(argv[i], n_units);
390     }
391
392     exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
393 }
394
395
396 #else
397 // Here follows the code for the full featured tail code
398
399
400 /* tail -- output the last part of file(s)
401    Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
402
403    This program is free software; you can redistribute it and/or modify
404    it under the terms of the GNU General Public License as published by
405    the Free Software Foundation; either version 2, or (at your option)
406    any later version.
407
408    This program is distributed in the hope that it will be useful,
409    but WITHOUT ANY WARRANTY; without even the implied warranty of
410    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
411    GNU General Public License for more details.
412
413    You should have received a copy of the GNU General Public License
414    along with this program; if not, write to the Free Software
415    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
416
417    Original version by Paul Rubin <phr@ocf.berkeley.edu>.
418    Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
419    tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.  
420
421    Rewrote the option parser, removed locales support,
422     and generally busyboxed, Erik Andersen <andersen@lineo.com>
423  
424  */
425
426 #include "internal.h"
427
428 #include <stdio.h>
429 #include <stdarg.h>
430 #include <assert.h>
431 #include <errno.h>
432 #include <sys/types.h>
433 #include <sys/types.h>
434 #include <sys/stat.h>
435 #include <fcntl.h>
436 #include <ctype.h>
437
438
439
440 /* Disable assertions.  Some systems have broken assert macros.  */
441 #define NDEBUG 1
442
443
444 static void detailed_error(int i, int errnum, char* fmt, ...)
445 {
446     va_list arguments;
447
448     va_start(arguments, fmt);
449     vfprintf(stderr, fmt, arguments);
450     fprintf(stderr, "\n%s\n", strerror( errnum));
451     va_end(arguments);
452     exit(i);
453 }
454
455
456 #define XWRITE(fd, buffer, n_bytes)                                     \
457   do                                                                    \
458     {                                                                   \
459       assert ((fd) == 1);                                               \
460       assert ((n_bytes) >= 0);                                          \
461       if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0)  \
462         detailed_error (EXIT_FAILURE, errno, "write error");                    \
463     }                                                                   \
464   while (0)
465
466 /* Number of items to tail.  */
467 #define DEFAULT_N_LINES 10
468
469 /* Size of atomic reads.  */
470 #ifndef BUFSIZ
471 #define BUFSIZ (512 * 8)
472 #endif
473
474 /* If nonzero, interpret the numeric argument as the number of lines.
475    Otherwise, interpret it as the number of bytes.  */
476 static int count_lines;
477
478 /* If nonzero, read from the end of one file until killed.  */
479 static int forever;
480
481 /* If nonzero, read from the end of multiple files until killed.  */
482 static int forever_multiple;
483
484 /* Array of file descriptors if forever_multiple is 1.  */
485 static int *file_descs;
486
487 /* Array of file sizes if forever_multiple is 1.  */
488 static off_t *file_sizes;
489
490 /* If nonzero, count from start of file instead of end.  */
491 static int from_start;
492
493 /* If nonzero, print filename headers.  */
494 static int print_headers;
495
496 /* When to print the filename banners.  */
497 enum header_mode
498 {
499   multiple_files, always, never
500 };
501
502 /* The name this program was run with.  */
503 char *program_name;
504
505 /* Nonzero if we have ever read standard input.  */
506 static int have_read_stdin;
507
508
509 static const char tail_usage[] = 
510 "tail [OPTION]... [FILE]...\n\
511 \n\
512 Print last 10 lines of each FILE to standard output.\n\
513 With more than one FILE, precede each with a header giving the file name.\n\
514 With no FILE, or when FILE is -, read standard input.\n\
515 \n\
516   -c=N[kbm]       output the last N bytes\n\
517   -f              output appended data as the file grows\n\
518   -n=N            output the last N lines, instead of last 10\n\
519   -q              never output headers giving file names\n\
520   -v              always output headers giving file names\n\
521   --help          display this help and exit\n\
522 \n\
523 If the first character of N (bytes or lines) is a `+', output begins with \n\
524 the Nth item from the start of each file, otherwise, print the last N items\n\
525 in the file.  N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n";
526
527 static void
528 write_header (const char *filename, const char *comment)
529 {
530   static int first_file = 1;
531
532   printf ("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
533           (comment ? ": " : ""),
534           (comment ? comment : ""));
535   first_file = 0;
536 }
537
538 /* Print the last N_LINES lines from the end of file FD.
539    Go backward through the file, reading `BUFSIZ' bytes at a time (except
540    probably the first), until we hit the start of the file or have
541    read NUMBER newlines.
542    POS starts out as the length of the file (the offset of the last
543    byte of the file + 1).
544    Return 0 if successful, 1 if an error occurred.  */
545
546 static int
547 file_lines (const char *filename, int fd, long int n_lines, off_t pos)
548 {
549   char buffer[BUFSIZ];
550   int bytes_read;
551   int i;                        /* Index into `buffer' for scanning.  */
552
553   if (n_lines == 0)
554     return 0;
555
556   /* Set `bytes_read' to the size of the last, probably partial, buffer;
557      0 < `bytes_read' <= `BUFSIZ'.  */
558   bytes_read = pos % BUFSIZ;
559   if (bytes_read == 0)
560     bytes_read = BUFSIZ;
561   /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
562      reads will be on block boundaries, which might increase efficiency.  */
563   pos -= bytes_read;
564   lseek (fd, pos, SEEK_SET);
565   bytes_read = fullRead (fd, buffer, bytes_read);
566   if (bytes_read == -1)
567     {
568       detailed_error (0, errno, "%s", filename);
569       return 1;
570     }
571
572   /* Count the incomplete line on files that don't end with a newline.  */
573   if (bytes_read && buffer[bytes_read - 1] != '\n')
574     --n_lines;
575
576   do
577     {
578       /* Scan backward, counting the newlines in this bufferfull.  */
579       for (i = bytes_read - 1; i >= 0; i--)
580         {
581           /* Have we counted the requested number of newlines yet?  */
582           if (buffer[i] == '\n' && n_lines-- == 0)
583             {
584               /* If this newline wasn't the last character in the buffer,
585                  print the text after it.  */
586               if (i != bytes_read - 1)
587                 XWRITE (STDOUT_FILENO, &buffer[i + 1], bytes_read - (i + 1));
588               return 0;
589             }
590         }
591       /* Not enough newlines in that bufferfull.  */
592       if (pos == 0)
593         {
594           /* Not enough lines in the file; print the entire file.  */
595           lseek (fd, (off_t) 0, SEEK_SET);
596           return 0;
597         }
598       pos -= BUFSIZ;
599       lseek (fd, pos, SEEK_SET);
600     }
601   while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0);
602   if (bytes_read == -1)
603     {
604       detailed_error (0, errno, "%s", filename);
605       return 1;
606     }
607   return 0;
608 }
609
610 /* Print the last N_LINES lines from the end of the standard input,
611    open for reading as pipe FD.
612    Buffer the text as a linked list of LBUFFERs, adding them as needed.
613    Return 0 if successful, 1 if an error occured.  */
614
615 static int
616 pipe_lines (const char *filename, int fd, long int n_lines)
617 {
618   struct linebuffer
619   {
620     int nbytes, nlines;
621     char buffer[BUFSIZ];
622     struct linebuffer *next;
623   };
624   typedef struct linebuffer LBUFFER;
625   LBUFFER *first, *last, *tmp;
626   int i;                        /* Index into buffers.  */
627   int total_lines = 0;          /* Total number of newlines in all buffers.  */
628   int errors = 0;
629
630   first = last = (LBUFFER *) xmalloc (sizeof (LBUFFER));
631   first->nbytes = first->nlines = 0;
632   first->next = NULL;
633   tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
634
635   /* Input is always read into a fresh buffer.  */
636   while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
637     {
638       tmp->nlines = 0;
639       tmp->next = NULL;
640
641       /* Count the number of newlines just read.  */
642       for (i = 0; i < tmp->nbytes; i++)
643         if (tmp->buffer[i] == '\n')
644           ++tmp->nlines;
645       total_lines += tmp->nlines;
646
647       /* If there is enough room in the last buffer read, just append the new
648          one to it.  This is because when reading from a pipe, `nbytes' can
649          often be very small.  */
650       if (tmp->nbytes + last->nbytes < BUFSIZ)
651         {
652           memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
653           last->nbytes += tmp->nbytes;
654           last->nlines += tmp->nlines;
655         }
656       else
657         {
658           /* If there's not enough room, link the new buffer onto the end of
659              the list, then either free up the oldest buffer for the next
660              read if that would leave enough lines, or else malloc a new one.
661              Some compaction mechanism is possible but probably not
662              worthwhile.  */
663           last = last->next = tmp;
664           if (total_lines - first->nlines > n_lines)
665             {
666               tmp = first;
667               total_lines -= first->nlines;
668               first = first->next;
669             }
670           else
671             tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
672         }
673     }
674   if (tmp->nbytes == -1)
675     {
676       detailed_error (0, errno, "%s", filename);
677       errors = 1;
678       free ((char *) tmp);
679       goto free_lbuffers;
680     }
681
682   free ((char *) tmp);
683
684   /* This prevents a core dump when the pipe contains no newlines.  */
685   if (n_lines == 0)
686     goto free_lbuffers;
687
688   /* Count the incomplete line on files that don't end with a newline.  */
689   if (last->buffer[last->nbytes - 1] != '\n')
690     {
691       ++last->nlines;
692       ++total_lines;
693     }
694
695   /* Run through the list, printing lines.  First, skip over unneeded
696      buffers.  */
697   for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
698     total_lines -= tmp->nlines;
699
700   /* Find the correct beginning, then print the rest of the file.  */
701   if (total_lines > n_lines)
702     {
703       char *cp;
704
705       /* Skip `total_lines' - `n_lines' newlines.  We made sure that
706          `total_lines' - `n_lines' <= `tmp->nlines'.  */
707       cp = tmp->buffer;
708       for (i = total_lines - n_lines; i; --i)
709         while (*cp++ != '\n')
710           /* Do nothing.  */ ;
711       i = cp - tmp->buffer;
712     }
713   else
714     i = 0;
715   XWRITE (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
716
717   for (tmp = tmp->next; tmp; tmp = tmp->next)
718     XWRITE (STDOUT_FILENO, tmp->buffer, tmp->nbytes);
719
720 free_lbuffers:
721   while (first)
722     {
723       tmp = first->next;
724       free ((char *) first);
725       first = tmp;
726     }
727   return errors;
728 }
729
730 /* Print the last N_BYTES characters from the end of pipe FD.
731    This is a stripped down version of pipe_lines.
732    Return 0 if successful, 1 if an error occurred.  */
733
734 static int
735 pipe_bytes (const char *filename, int fd, off_t n_bytes)
736 {
737   struct charbuffer
738   {
739     int nbytes;
740     char buffer[BUFSIZ];
741     struct charbuffer *next;
742   };
743   typedef struct charbuffer CBUFFER;
744   CBUFFER *first, *last, *tmp;
745   int i;                        /* Index into buffers.  */
746   int total_bytes = 0;          /* Total characters in all buffers.  */
747   int errors = 0;
748
749   first = last = (CBUFFER *) xmalloc (sizeof (CBUFFER));
750   first->nbytes = 0;
751   first->next = NULL;
752   tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
753
754   /* Input is always read into a fresh buffer.  */
755   while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
756     {
757       tmp->next = NULL;
758
759       total_bytes += tmp->nbytes;
760       /* If there is enough room in the last buffer read, just append the new
761          one to it.  This is because when reading from a pipe, `nbytes' can
762          often be very small.  */
763       if (tmp->nbytes + last->nbytes < BUFSIZ)
764         {
765           memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
766           last->nbytes += tmp->nbytes;
767         }
768       else
769         {
770           /* If there's not enough room, link the new buffer onto the end of
771              the list, then either free up the oldest buffer for the next
772              read if that would leave enough characters, or else malloc a new
773              one.  Some compaction mechanism is possible but probably not
774              worthwhile.  */
775           last = last->next = tmp;
776           if (total_bytes - first->nbytes > n_bytes)
777             {
778               tmp = first;
779               total_bytes -= first->nbytes;
780               first = first->next;
781             }
782           else
783             {
784               tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
785             }
786         }
787     }
788   if (tmp->nbytes == -1)
789     {
790       detailed_error (0, errno, "%s", filename);
791       errors = 1;
792       free ((char *) tmp);
793       goto free_cbuffers;
794     }
795
796   free ((char *) tmp);
797
798   /* Run through the list, printing characters.  First, skip over unneeded
799      buffers.  */
800   for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
801     total_bytes -= tmp->nbytes;
802
803   /* Find the correct beginning, then print the rest of the file.
804      We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'.  */
805   if (total_bytes > n_bytes)
806     i = total_bytes - n_bytes;
807   else
808     i = 0;
809   XWRITE (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
810
811   for (tmp = tmp->next; tmp; tmp = tmp->next)
812     XWRITE (STDOUT_FILENO, tmp->buffer, tmp->nbytes);
813
814 free_cbuffers:
815   while (first)
816     {
817       tmp = first->next;
818       free ((char *) first);
819       first = tmp;
820     }
821   return errors;
822 }
823
824 /* Skip N_BYTES characters from the start of pipe FD, and print
825    any extra characters that were read beyond that.
826    Return 1 on error, 0 if ok.  */
827
828 static int
829 start_bytes (const char *filename, int fd, off_t n_bytes)
830 {
831   char buffer[BUFSIZ];
832   int bytes_read = 0;
833
834   while (n_bytes > 0 && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
835     n_bytes -= bytes_read;
836   if (bytes_read == -1)
837     {
838       detailed_error (0, errno, "%s", filename);
839       return 1;
840     }
841   else if (n_bytes < 0)
842     XWRITE (STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
843   return 0;
844 }
845
846 /* Skip N_LINES lines at the start of file or pipe FD, and print
847    any extra characters that were read beyond that.
848    Return 1 on error, 0 if ok.  */
849
850 static int
851 start_lines (const char *filename, int fd, long int n_lines)
852 {
853   char buffer[BUFSIZ];
854   int bytes_read = 0;
855   int bytes_to_skip = 0;
856
857   while (n_lines && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
858     {
859       bytes_to_skip = 0;
860       while (bytes_to_skip < bytes_read)
861         if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
862           break;
863     }
864   if (bytes_read == -1)
865     {
866       detailed_error (0, errno, "%s", filename);
867       return 1;
868     }
869   else if (bytes_to_skip < bytes_read)
870     {
871       XWRITE (STDOUT_FILENO, &buffer[bytes_to_skip],
872               bytes_read - bytes_to_skip);
873     }
874   return 0;
875 }
876
877 /* Display file FILENAME from the current position in FD to the end.
878    If `forever' is nonzero, keep reading from the end of the file
879    until killed.  Return the number of bytes read from the file.  */
880
881 static long
882 dump_remainder (const char *filename, int fd)
883 {
884   char buffer[BUFSIZ];
885   int bytes_read;
886   long total;
887
888   total = 0;
889 output:
890   while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
891     {
892       XWRITE (STDOUT_FILENO, buffer, bytes_read);
893       total += bytes_read;
894     }
895   if (bytes_read == -1)
896     detailed_error (EXIT_FAILURE, errno, "%s", filename);
897   if (forever)
898     {
899       fflush (stdout);
900       sleep (1);
901       goto output;
902     }
903   else
904     {
905       if (forever_multiple)
906         fflush (stdout);
907     }
908
909   return total;
910 }
911
912 /* Tail NFILES (>1) files forever until killed.  The file names are in
913    NAMES.  The open file descriptors are in `file_descs', and the size
914    at which we stopped tailing them is in `file_sizes'.  We loop over
915    each of them, doing an fstat to see if they have changed size.  If
916    none of them have changed size in one iteration, we sleep for a
917    second and try again.  We do this until the user interrupts us.  */
918
919 static void
920 tail_forever (char **names, int nfiles)
921 {
922   int last;
923
924   last = -1;
925
926   while (1)
927     {
928       int i;
929       int changed;
930
931       changed = 0;
932       for (i = 0; i < nfiles; i++)
933         {
934           struct stat stats;
935
936           if (file_descs[i] < 0)
937             continue;
938           if (fstat (file_descs[i], &stats) < 0)
939             {
940               detailed_error (0, errno, "%s", names[i]);
941               file_descs[i] = -1;
942               continue;
943             }
944           if (stats.st_size == file_sizes[i])
945             continue;
946
947           /* This file has changed size.  Print out what we can, and
948              then keep looping.  */
949
950           changed = 1;
951
952           if (stats.st_size < file_sizes[i])
953             {
954               write_header (names[i], "file truncated");
955               last = i;
956               lseek (file_descs[i], stats.st_size, SEEK_SET);
957               file_sizes[i] = stats.st_size;
958               continue;
959             }
960
961           if (i != last)
962             {
963               if (print_headers)
964                 write_header (names[i], NULL);
965               last = i;
966             }
967           file_sizes[i] += dump_remainder (names[i], file_descs[i]);
968         }
969
970       /* If none of the files changed size, sleep.  */
971       if (! changed)
972         sleep (1);
973     }
974 }
975
976 /* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
977    Return 0 if successful, 1 if an error occurred.  */
978
979 static int
980 tail_bytes (const char *filename, int fd, off_t n_bytes)
981 {
982   struct stat stats;
983
984   /* FIXME: resolve this like in dd.c.  */
985   /* Use fstat instead of checking for errno == ESPIPE because
986      lseek doesn't work on some special files but doesn't return an
987      error, either.  */
988   if (fstat (fd, &stats))
989     {
990       detailed_error (0, errno, "%s", filename);
991       return 1;
992     }
993
994   if (from_start)
995     {
996       if (S_ISREG (stats.st_mode))
997         lseek (fd, n_bytes, SEEK_CUR);
998       else if (start_bytes (filename, fd, n_bytes))
999         return 1;
1000       dump_remainder (filename, fd);
1001     }
1002   else
1003     {
1004       if (S_ISREG (stats.st_mode))
1005         {
1006           off_t current_pos, end_pos;
1007           size_t bytes_remaining;
1008
1009           if ((current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
1010               && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
1011             {
1012               off_t diff;
1013               /* Be careful here.  The current position may actually be
1014                  beyond the end of the file.  */
1015               bytes_remaining = (diff = end_pos - current_pos) < 0 ? 0 : diff;
1016             }
1017           else
1018             {
1019               detailed_error (0, errno, "%s", filename);
1020               return 1;
1021             }
1022
1023           if (bytes_remaining <= n_bytes)
1024             {
1025               /* From the current position to end of file, there are no
1026                  more bytes than have been requested.  So reposition the
1027                  file pointer to the incoming current position and print
1028                  everything after that.  */
1029               lseek (fd, current_pos, SEEK_SET);
1030             }
1031           else
1032             {
1033               /* There are more bytes remaining than were requested.
1034                  Back up.  */
1035               lseek (fd, -n_bytes, SEEK_END);
1036             }
1037           dump_remainder (filename, fd);
1038         }
1039       else
1040         return pipe_bytes (filename, fd, n_bytes);
1041     }
1042   return 0;
1043 }
1044
1045 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
1046    Return 0 if successful, 1 if an error occurred.  */
1047
1048 static int
1049 tail_lines (const char *filename, int fd, long int n_lines)
1050 {
1051   struct stat stats;
1052   off_t length;
1053
1054   if (fstat (fd, &stats))
1055     {
1056       detailed_error (0, errno, "%s", filename);
1057       return 1;
1058     }
1059
1060   if (from_start)
1061     {
1062       if (start_lines (filename, fd, n_lines))
1063         return 1;
1064       dump_remainder (filename, fd);
1065     }
1066   else
1067     {
1068       /* Use file_lines only if FD refers to a regular file with
1069          its file pointer positioned at beginning of file.  */
1070       /* FIXME: adding the lseek conjunct is a kludge.
1071          Once there's a reasonable test suite, fix the true culprit:
1072          file_lines.  file_lines shouldn't presume that the input
1073          file pointer is initially positioned to beginning of file.  */
1074       if (S_ISREG (stats.st_mode)
1075           && lseek (fd, (off_t) 0, SEEK_CUR) == (off_t) 0)
1076         {
1077           length = lseek (fd, (off_t) 0, SEEK_END);
1078           if (length != 0 && file_lines (filename, fd, n_lines, length))
1079             return 1;
1080           dump_remainder (filename, fd);
1081         }
1082       else
1083         return pipe_lines (filename, fd, n_lines);
1084     }
1085   return 0;
1086 }
1087
1088 /* Display the last N_UNITS units of file FILENAME, open for reading
1089    in FD.
1090    Return 0 if successful, 1 if an error occurred.  */
1091
1092 static int
1093 tail (const char *filename, int fd, off_t n_units)
1094 {
1095   if (count_lines)
1096     return tail_lines (filename, fd, (long) n_units);
1097   else
1098     return tail_bytes (filename, fd, n_units);
1099 }
1100
1101 /* Display the last N_UNITS units of file FILENAME.
1102    "-" for FILENAME means the standard input.
1103    FILENUM is this file's index in the list of files the user gave.
1104    Return 0 if successful, 1 if an error occurred.  */
1105
1106 static int
1107 tail_file (const char *filename, off_t n_units, int filenum)
1108 {
1109   int fd, errors;
1110   struct stat stats;
1111
1112   if (!strcmp (filename, "-"))
1113     {
1114       have_read_stdin = 1;
1115       filename = "standard input";
1116       if (print_headers)
1117         write_header (filename, NULL);
1118       errors = tail (filename, 0, n_units);
1119       if (forever_multiple)
1120         {
1121           if (fstat (0, &stats) < 0)
1122             {
1123               detailed_error (0, errno, "standard input");
1124               errors = 1;
1125             }
1126           else if (!S_ISREG (stats.st_mode))
1127             {
1128               detailed_error (0, 0,
1129                      "standard input: cannot follow end of non-regular file");
1130               errors = 1;
1131             }
1132           if (errors)
1133             file_descs[filenum] = -1;
1134           else
1135             {
1136               file_descs[filenum] = 0;
1137               file_sizes[filenum] = stats.st_size;
1138             }
1139         }
1140     }
1141   else
1142     {
1143       /* Not standard input.  */
1144       fd = open (filename, O_RDONLY);
1145       if (fd == -1)
1146         {
1147           if (forever_multiple)
1148             file_descs[filenum] = -1;
1149           detailed_error (0, errno, "%s", filename);
1150           errors = 1;
1151         }
1152       else
1153         {
1154           if (print_headers)
1155             write_header (filename, NULL);
1156           errors = tail (filename, fd, n_units);
1157           if (forever_multiple)
1158             {
1159               if (fstat (fd, &stats) < 0)
1160                 {
1161                   detailed_error (0, errno, "%s", filename);
1162                   errors = 1;
1163                 }
1164               else if (!S_ISREG (stats.st_mode))
1165                 {
1166                   detailed_error (0, 0, "%s: cannot follow end of non-regular file",
1167                          filename);
1168                   errors = 1;
1169                 }
1170               if (errors)
1171                 {
1172                   close (fd);
1173                   file_descs[filenum] = -1;
1174                 }
1175               else
1176                 {
1177                   file_descs[filenum] = fd;
1178                   file_sizes[filenum] = stats.st_size;
1179                 }
1180             }
1181           else
1182             {
1183               if (close (fd))
1184                 {
1185                   detailed_error (0, errno, "%s", filename);
1186                   errors = 1;
1187                 }
1188             }
1189         }
1190     }
1191
1192   return errors;
1193 }
1194
1195 extern int
1196 tail_main (int argc, char **argv)
1197 {
1198   int stopit = 0;
1199   enum header_mode header_mode = multiple_files;
1200   int exit_status = 0;
1201   /* If from_start, the number of items to skip before printing; otherwise,
1202      the number of items at the end of the file to print.  Initially, -1
1203      means the value has not been set.  */
1204   off_t n_units = -1;
1205   int n_files;
1206   char **file;
1207
1208   program_name = argv[0];
1209   have_read_stdin = 0;
1210   count_lines = 1;
1211   forever = forever_multiple = from_start = print_headers = 0;
1212       
1213   /* Parse any options */
1214   //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1215     while (--argc > 0 && ( **(++argv) == '-' || **argv == '+' )) {
1216         if (**argv == '+') {
1217             from_start = 1;
1218         }
1219         stopit = 0;
1220         while (stopit == 0 && *(++(*argv))) {
1221             switch (**argv) {
1222                 case 'c':
1223                   count_lines = 0;
1224
1225                   if (--argc < 1) {
1226                       usage(tail_usage);
1227                   }
1228                   n_units = getNum(*(++argv));
1229                   stopit = 1;
1230                   break;
1231
1232                 case 'f':
1233                   forever = 1;
1234                   break;
1235
1236                 case 'n':
1237                   count_lines = 1;
1238
1239                   if (--argc < 1) {
1240                       usage(tail_usage);
1241                   }
1242                   n_units = atol(*(++argv));
1243                   stopit = 1;
1244                   break;
1245
1246                 case 'q':
1247                   header_mode = never;
1248                   break;
1249
1250                 case 'v':
1251                   header_mode = always;
1252                   break;
1253
1254                 default:
1255                   usage (tail_usage);
1256             }
1257         }
1258     }
1259
1260
1261   if (n_units == -1)
1262     n_units = DEFAULT_N_LINES;
1263
1264   /* To start printing with item N_UNITS from the start of the file, skip
1265      N_UNITS - 1 items.  `tail +0' is actually meaningless, but for Unix
1266      compatibility it's treated the same as `tail +1'.  */
1267   if (from_start)
1268     {
1269       if (n_units)
1270         --n_units;
1271     }
1272
1273   n_files = argc;
1274   file = argv;
1275
1276   if (n_files > 1 && forever)
1277     {
1278       forever_multiple = 1;
1279       forever = 0;
1280       file_descs = (int *) xmalloc (n_files * sizeof (int));
1281       file_sizes = (off_t *) xmalloc (n_files * sizeof (off_t));
1282     }
1283
1284   if (header_mode == always
1285       || (header_mode == multiple_files && n_files > 1))
1286     print_headers = 1;
1287
1288   if (n_files == 0)
1289     {
1290       exit_status |= tail_file ("-", n_units, 0);
1291     }
1292   else
1293     {
1294       int i;
1295       for (i = 0; i < n_files; i++)
1296         exit_status |= tail_file (file[i], n_units, i);
1297
1298       if (forever_multiple)
1299         tail_forever (file, n_files);
1300     }
1301
1302   if (have_read_stdin && close (0) < 0)
1303     detailed_error (EXIT_FAILURE, errno, "-");
1304   if (fclose (stdout) == EOF)
1305     detailed_error (EXIT_FAILURE, errno, "write error");
1306   exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1307 }
1308
1309
1310 #endif