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