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