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