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