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