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