1 /* vi: set sw=4 ts=4: */
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.
11 #ifdef BB_FEATURE_SIMPLE_TAIL
13 /* tail -- output the last part of file(s)
14 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
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)
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.
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.
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>.
34 Rewrote the option parser, removed locales support,
35 and generally busyboxed, Erik Andersen <andersen@lineo.com>
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>.
46 #include <sys/types.h>
50 #define BB_DECLARE_EXTERN
55 #define XWRITE(fd, buffer, n_bytes) \
57 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
58 errorMsg("write error"); \
61 /* Number of items to tail. */
62 #define DEFAULT_N_LINES 10
64 /* Size of atomic reads. */
66 #define BUFSIZ (512 * 8)
69 /* If nonzero, read from the end of one file until killed. */
72 /* If nonzero, print filename headers. */
73 static int print_headers;
75 const char tail_usage[] =
76 "tail [OPTION] [FILE]...\n"
77 #ifndef BB_FEATURE_TRIVIAL_HELP
78 "\nPrint last 10 lines of each FILE to standard output.\n"
79 "With more than one FILE, precede each with a header giving the\n"
80 "file name. With no FILE, or when FILE is -, read standard input.\n\n"
82 "\t-n NUM\t\tPrint last NUM lines instead of first 10\n"
84 "\t-f\t\tOutput data as the file grows. This version\n"
85 "\t\t\tof 'tail -f' supports only one file at a time.\n"
90 static void write_header(const char *filename)
92 static int first_file = 1;
94 printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
98 /* Print the last N_LINES lines from the end of file FD.
99 Go backward through the file, reading `BUFSIZ' bytes at a time (except
100 probably the first), until we hit the start of the file or have
101 read NUMBER newlines.
102 POS starts out as the length of the file (the offset of the last
103 byte of the file + 1).
104 Return 0 if successful, 1 if an error occurred. */
107 file_lines(int fd, long int n_lines, off_t pos)
111 int i; /* Index into `buffer' for scanning. */
116 /* Set `bytes_read' to the size of the last, probably partial, buffer;
117 0 < `bytes_read' <= `BUFSIZ'. */
118 bytes_read = pos % BUFSIZ;
121 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
122 reads will be on block boundaries, which might increase efficiency. */
124 lseek(fd, pos, SEEK_SET);
125 bytes_read = fullRead(fd, buffer, bytes_read);
126 if (bytes_read == -1)
127 errorMsg("read error");
129 /* Count the incomplete line on files that don't end with a newline. */
130 if (bytes_read && buffer[bytes_read - 1] != '\n')
134 /* Scan backward, counting the newlines in this bufferfull. */
135 for (i = bytes_read - 1; i >= 0; i--) {
136 /* Have we counted the requested number of newlines yet? */
137 if (buffer[i] == '\n' && n_lines-- == 0) {
138 /* If this newline wasn't the last character in the buffer,
139 print the text after it. */
140 if (i != bytes_read - 1)
141 XWRITE(STDOUT_FILENO, &buffer[i + 1],
142 bytes_read - (i + 1));
146 /* Not enough newlines in that bufferfull. */
148 /* Not enough lines in the file; print the entire file. */
149 lseek(fd, (off_t) 0, SEEK_SET);
153 lseek(fd, pos, SEEK_SET);
155 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
156 if (bytes_read == -1)
157 errorMsg("read error");
162 /* Print the last N_LINES lines from the end of the standard input,
163 open for reading as pipe FD.
164 Buffer the text as a linked list of LBUFFERs, adding them as needed.
165 Return 0 if successful, 1 if an error occured. */
167 static int pipe_lines(int fd, long int n_lines)
172 struct linebuffer *next;
174 typedef struct linebuffer LBUFFER;
175 LBUFFER *first, *last, *tmp;
176 int i; /* Index into buffers. */
177 int total_lines = 0; /* Total number of newlines in all buffers. */
180 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
181 first->nbytes = first->nlines = 0;
183 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
185 /* Input is always read into a fresh buffer. */
186 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
190 /* Count the number of newlines just read. */
191 for (i = 0; i < tmp->nbytes; i++)
192 if (tmp->buffer[i] == '\n')
194 total_lines += tmp->nlines;
196 /* If there is enough room in the last buffer read, just append the new
197 one to it. This is because when reading from a pipe, `nbytes' can
198 often be very small. */
199 if (tmp->nbytes + last->nbytes < BUFSIZ) {
200 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
201 last->nbytes += tmp->nbytes;
202 last->nlines += tmp->nlines;
204 /* If there's not enough room, link the new buffer onto the end of
205 the list, then either free up the oldest buffer for the next
206 read if that would leave enough lines, or else malloc a new one.
207 Some compaction mechanism is possible but probably not
209 last = last->next = tmp;
210 if (total_lines - first->nlines > n_lines) {
212 total_lines -= first->nlines;
215 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
218 if (tmp->nbytes == -1)
219 errorMsg("read error");
223 /* This prevents a core dump when the pipe contains no newlines. */
227 /* Count the incomplete line on files that don't end with a newline. */
228 if (last->buffer[last->nbytes - 1] != '\n') {
233 /* Run through the list, printing lines. First, skip over unneeded
235 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
236 total_lines -= tmp->nlines;
238 /* Find the correct beginning, then print the rest of the file. */
239 if (total_lines > n_lines) {
242 /* Skip `total_lines' - `n_lines' newlines. We made sure that
243 `total_lines' - `n_lines' <= `tmp->nlines'. */
245 for (i = total_lines - n_lines; i; --i)
246 while (*cp++ != '\n')
248 i = cp - tmp->buffer;
251 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
253 for (tmp = tmp->next; tmp; tmp = tmp->next)
254 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
259 free((char *) first);
265 /* Display file FILENAME from the current position in FD to the end.
266 If `forever' is nonzero, keep reading from the end of the file
267 until killed. Return the number of bytes read from the file. */
269 static long dump_remainder(int fd)
277 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
278 XWRITE(STDOUT_FILENO, buffer, bytes_read);
281 if (bytes_read == -1)
282 errorMsg("read error");
292 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
293 Return 0 if successful, 1 if an error occurred. */
295 static int tail_lines(const char *filename, int fd, long int n_lines)
301 write_header(filename);
303 if (fstat(fd, &stats))
304 errorMsg("fstat error");
306 /* Use file_lines only if FD refers to a regular file with
307 its file pointer positioned at beginning of file. */
308 /* FIXME: adding the lseek conjunct is a kludge.
309 Once there's a reasonable test suite, fix the true culprit:
310 file_lines. file_lines shouldn't presume that the input
311 file pointer is initially positioned to beginning of file. */
312 if (S_ISREG(stats.st_mode)
313 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
314 length = lseek(fd, (off_t) 0, SEEK_END);
315 if (length != 0 && file_lines(fd, n_lines, length))
319 return pipe_lines(fd, n_lines);
324 /* Display the last N_UNITS lines of file FILENAME.
325 "-" for FILENAME means the standard input.
326 Return 0 if successful, 1 if an error occurred. */
328 static int tail_file(const char *filename, off_t n_units)
332 if (!strcmp(filename, "-")) {
333 filename = "standard input";
334 errors = tail_lines(filename, 0, (long) n_units);
336 /* Not standard input. */
337 fd = open(filename, O_RDONLY);
341 errors = tail_lines(filename, fd, (long) n_units);
348 extern int tail_main(int argc, char **argv)
351 int n_units = DEFAULT_N_LINES;
355 forever = print_headers = 0;
358 for (i = 1; i < argc; i++) {
359 if (argv[i][0] == '-') {
368 n_tmp = atoi(argv[i]);
377 if ((n_units = atoi(&argv[i][1])) < 1) {
378 errorMsg("invalid option -- %c\n", opt);
389 errorMsg("option -f is invalid with multiple files\n");
396 exit_status |= tail_file("-", n_units);
398 for (; i < argc; i++)
399 exit_status |= tail_file(argv[i], n_units);
402 return(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
407 // Here follows the code for the full featured tail code
410 /* tail -- output the last part of file(s)
411 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
413 This program is free software; you can redistribute it and/or modify
414 it under the terms of the GNU General Public License as published by
415 the Free Software Foundation; either version 2, or (at your option)
418 This program is distributed in the hope that it will be useful,
419 but WITHOUT ANY WARRANTY; without even the implied warranty of
420 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
421 GNU General Public License for more details.
423 You should have received a copy of the GNU General Public License
424 along with this program; if not, write to the Free Software
425 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
427 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
428 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
429 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
431 Rewrote the option parser, removed locales support,
432 and generally busyboxed, Erik Andersen <andersen@lineo.com>
436 #include "internal.h"
442 #include <sys/types.h>
443 #include <sys/types.h>
444 #include <sys/stat.h>
450 /* Disable assertions. Some systems have broken assert macros. */
454 static void detailed_error(int i, int errnum, char *fmt, ...)
455 __attribute__ ((format (printf, 3, 4)));
456 static void detailed_error(int i, int errnum, char *fmt, ...)
460 va_start(arguments, fmt);
461 vfprintf(stderr, fmt, arguments);
462 fprintf(stderr, "\n%s\n", strerror(errnum));
468 #define XWRITE(fd, buffer, n_bytes) \
471 assert ((fd) == 1); \
472 assert ((n_bytes) >= 0); \
473 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
474 detailed_error (EXIT_FAILURE, errno, "write error"); \
478 /* Number of items to tail. */
479 #define DEFAULT_N_LINES 10
481 /* Size of atomic reads. */
483 #define BUFSIZ (512 * 8)
486 /* If nonzero, interpret the numeric argument as the number of lines.
487 Otherwise, interpret it as the number of bytes. */
488 static int count_lines;
490 /* If nonzero, read from the end of one file until killed. */
493 /* If nonzero, read from the end of multiple files until killed. */
494 static int forever_multiple;
496 /* Array of file descriptors if forever_multiple is 1. */
497 static int *file_descs;
499 /* Array of file sizes if forever_multiple is 1. */
500 static off_t *file_sizes;
502 /* If nonzero, count from start of file instead of end. */
503 static int from_start;
505 /* If nonzero, print filename headers. */
506 static int print_headers;
508 /* When to print the filename banners. */
510 multiple_files, always, never
513 /* The name this program was run with. */
516 /* Nonzero if we have ever read standard input. */
517 static int have_read_stdin;
520 static const char tail_usage[] = "tail [OPTION]... [FILE]...\n"
521 #ifndef BB_FEATURE_TRIVIAL_HELP
522 "\nPrint last 10 lines of each FILE to standard output.\n\
523 With more than one FILE, precede each with a header giving the file name.\n\
524 With no FILE, or when FILE is -, read standard input.\n\
526 -c=N[kbm] output the last N bytes\n\
527 -f output appended data as the file grows\n\
528 -n=N output the last N lines, instead of last 10\n\
529 -q never output headers giving file names\n\
530 -v always output headers giving file names\n\
532 If the first character of N (bytes or lines) is a `+', output begins with \n\
533 the Nth item from the start of each file, otherwise, print the last N items\n\
534 in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n"
538 static void write_header(const char *filename, const char *comment)
540 static int first_file = 1;
542 printf("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
543 (comment ? ": " : ""), (comment ? comment : ""));
547 /* Print the last N_LINES lines from the end of file FD.
548 Go backward through the file, reading `BUFSIZ' bytes at a time (except
549 probably the first), until we hit the start of the file or have
550 read NUMBER newlines.
551 POS starts out as the length of the file (the offset of the last
552 byte of the file + 1).
553 Return 0 if successful, 1 if an error occurred. */
556 file_lines(const char *filename, int fd, long int n_lines, off_t pos)
560 int i; /* Index into `buffer' for scanning. */
565 /* Set `bytes_read' to the size of the last, probably partial, buffer;
566 0 < `bytes_read' <= `BUFSIZ'. */
567 bytes_read = pos % BUFSIZ;
570 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
571 reads will be on block boundaries, which might increase efficiency. */
573 lseek(fd, pos, SEEK_SET);
574 bytes_read = fullRead(fd, buffer, bytes_read);
575 if (bytes_read == -1) {
576 detailed_error(0, errno, "%s", filename);
580 /* Count the incomplete line on files that don't end with a newline. */
581 if (bytes_read && buffer[bytes_read - 1] != '\n')
585 /* Scan backward, counting the newlines in this bufferfull. */
586 for (i = bytes_read - 1; i >= 0; i--) {
587 /* Have we counted the requested number of newlines yet? */
588 if (buffer[i] == '\n' && n_lines-- == 0) {
589 /* If this newline wasn't the last character in the buffer,
590 print the text after it. */
591 if (i != bytes_read - 1)
592 XWRITE(STDOUT_FILENO, &buffer[i + 1],
593 bytes_read - (i + 1));
597 /* Not enough newlines in that bufferfull. */
599 /* Not enough lines in the file; print the entire file. */
600 lseek(fd, (off_t) 0, SEEK_SET);
604 lseek(fd, pos, SEEK_SET);
606 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
607 if (bytes_read == -1) {
608 detailed_error(0, errno, "%s", filename);
614 /* Print the last N_LINES lines from the end of the standard input,
615 open for reading as pipe FD.
616 Buffer the text as a linked list of LBUFFERs, adding them as needed.
617 Return 0 if successful, 1 if an error occured. */
619 static int pipe_lines(int fd, long int n_lines)
624 struct linebuffer *next;
626 typedef struct linebuffer LBUFFER;
627 LBUFFER *first, *last, *tmp;
628 int i; /* Index into buffers. */
629 int total_lines = 0; /* Total number of newlines in all buffers. */
632 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
633 first->nbytes = first->nlines = 0;
635 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
637 /* Input is always read into a fresh buffer. */
638 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
642 /* Count the number of newlines just read. */
643 for (i = 0; i < tmp->nbytes; i++)
644 if (tmp->buffer[i] == '\n')
646 total_lines += tmp->nlines;
648 /* If there is enough room in the last buffer read, just append the new
649 one to it. This is because when reading from a pipe, `nbytes' can
650 often be very small. */
651 if (tmp->nbytes + last->nbytes < BUFSIZ) {
652 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
653 last->nbytes += tmp->nbytes;
654 last->nlines += tmp->nlines;
656 /* If there's not enough room, link the new buffer onto the end of
657 the list, then either free up the oldest buffer for the next
658 read if that would leave enough lines, or else malloc a new one.
659 Some compaction mechanism is possible but probably not
661 last = last->next = tmp;
662 if (total_lines - first->nlines > n_lines) {
664 total_lines -= first->nlines;
667 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
670 if (tmp->nbytes == -1) {
671 detailed_error(0, errno, "%s", filename);
679 /* This prevents a core dump when the pipe contains no newlines. */
683 /* Count the incomplete line on files that don't end with a newline. */
684 if (last->buffer[last->nbytes - 1] != '\n') {
689 /* Run through the list, printing lines. First, skip over unneeded
691 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
692 total_lines -= tmp->nlines;
694 /* Find the correct beginning, then print the rest of the file. */
695 if (total_lines > n_lines) {
698 /* Skip `total_lines' - `n_lines' newlines. We made sure that
699 `total_lines' - `n_lines' <= `tmp->nlines'. */
701 for (i = total_lines - n_lines; i; --i)
702 while (*cp++ != '\n')
704 i = cp - tmp->buffer;
707 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
709 for (tmp = tmp->next; tmp; tmp = tmp->next)
710 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
715 free((char *) first);
721 /* Print the last N_BYTES characters from the end of pipe FD.
722 This is a stripped down version of pipe_lines.
723 Return 0 if successful, 1 if an error occurred. */
725 static int pipe_bytes(const char *filename, int fd, off_t n_bytes)
730 struct charbuffer *next;
732 typedef struct charbuffer CBUFFER;
733 CBUFFER *first, *last, *tmp;
734 int i; /* Index into buffers. */
735 int total_bytes = 0; /* Total characters in all buffers. */
738 first = last = (CBUFFER *) xmalloc(sizeof(CBUFFER));
741 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
743 /* Input is always read into a fresh buffer. */
744 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
747 total_bytes += tmp->nbytes;
748 /* If there is enough room in the last buffer read, just append the new
749 one to it. This is because when reading from a pipe, `nbytes' can
750 often be very small. */
751 if (tmp->nbytes + last->nbytes < BUFSIZ) {
752 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
753 last->nbytes += tmp->nbytes;
755 /* If there's not enough room, link the new buffer onto the end of
756 the list, then either free up the oldest buffer for the next
757 read if that would leave enough characters, or else malloc a new
758 one. Some compaction mechanism is possible but probably not
760 last = last->next = tmp;
761 if (total_bytes - first->nbytes > n_bytes) {
763 total_bytes -= first->nbytes;
766 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
770 if (tmp->nbytes == -1) {
771 detailed_error(0, errno, "%s", filename);
779 /* Run through the list, printing characters. First, skip over unneeded
781 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
782 total_bytes -= tmp->nbytes;
784 /* Find the correct beginning, then print the rest of the file.
785 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
786 if (total_bytes > n_bytes)
787 i = total_bytes - n_bytes;
790 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
792 for (tmp = tmp->next; tmp; tmp = tmp->next)
793 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
798 free((char *) first);
804 /* Skip N_BYTES characters from the start of pipe FD, and print
805 any extra characters that were read beyond that.
806 Return 1 on error, 0 if ok. */
808 static int start_bytes(const char *filename, int fd, off_t n_bytes)
813 while (n_bytes > 0 && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0)
814 n_bytes -= bytes_read;
815 if (bytes_read == -1) {
816 detailed_error(0, errno, "%s", filename);
818 } else if (n_bytes < 0)
819 XWRITE(STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
823 /* Skip N_LINES lines at the start of file or pipe FD, and print
824 any extra characters that were read beyond that.
825 Return 1 on error, 0 if ok. */
827 static int start_lines(const char *filename, int fd, long int n_lines)
831 int bytes_to_skip = 0;
833 while (n_lines && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
835 while (bytes_to_skip < bytes_read)
836 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
839 if (bytes_read == -1) {
840 detailed_error(0, errno, "%s", filename);
842 } else if (bytes_to_skip < bytes_read) {
843 XWRITE(STDOUT_FILENO, &buffer[bytes_to_skip],
844 bytes_read - bytes_to_skip);
849 /* Display file FILENAME from the current position in FD to the end.
850 If `forever' is nonzero, keep reading from the end of the file
851 until killed. Return the number of bytes read from the file. */
853 static long dump_remainder(int fd)
861 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
862 XWRITE(STDOUT_FILENO, buffer, bytes_read);
865 if (bytes_read == -1)
866 detailed_error(EXIT_FAILURE, errno, "%s", filename);
872 if (forever_multiple)
879 /* Tail NFILES (>1) files forever until killed. The file names are in
880 NAMES. The open file descriptors are in `file_descs', and the size
881 at which we stopped tailing them is in `file_sizes'. We loop over
882 each of them, doing an fstat to see if they have changed size. If
883 none of them have changed size in one iteration, we sleep for a
884 second and try again. We do this until the user interrupts us. */
886 static void tail_forever(char **names, int nfiles)
897 for (i = 0; i < nfiles; i++) {
900 if (file_descs[i] < 0)
902 if (fstat(file_descs[i], &stats) < 0) {
903 detailed_error(0, errno, "%s", names[i]);
907 if (stats.st_size == file_sizes[i])
910 /* This file has changed size. Print out what we can, and
911 then keep looping. */
915 if (stats.st_size < file_sizes[i]) {
916 write_header(names[i], "file truncated");
918 lseek(file_descs[i], stats.st_size, SEEK_SET);
919 file_sizes[i] = stats.st_size;
925 write_header(names[i], NULL);
928 file_sizes[i] += dump_remainder(file_descs[i]);
931 /* If none of the files changed size, sleep. */
937 /* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
938 Return 0 if successful, 1 if an error occurred. */
940 static int tail_bytes(const char *filename, int fd, off_t n_bytes)
944 /* FIXME: resolve this like in dd.c. */
945 /* Use fstat instead of checking for errno == ESPIPE because
946 lseek doesn't work on some special files but doesn't return an
948 if (fstat(fd, &stats)) {
949 detailed_error(0, errno, "%s", filename);
954 if (S_ISREG(stats.st_mode))
955 lseek(fd, n_bytes, SEEK_CUR);
956 else if (start_bytes(filename, fd, n_bytes))
960 if (S_ISREG(stats.st_mode)) {
961 off_t current_pos, end_pos;
962 size_t bytes_remaining;
964 if ((current_pos = lseek(fd, (off_t) 0, SEEK_CUR)) != -1
965 && (end_pos = lseek(fd, (off_t) 0, SEEK_END)) != -1) {
968 /* Be careful here. The current position may actually be
969 beyond the end of the file. */
970 bytes_remaining = (diff =
971 end_pos - current_pos) < 0 ? 0 : diff;
973 detailed_error(0, errno, "%s", filename);
977 if (bytes_remaining <= n_bytes) {
978 /* From the current position to end of file, there are no
979 more bytes than have been requested. So reposition the
980 file pointer to the incoming current position and print
981 everything after that. */
982 lseek(fd, current_pos, SEEK_SET);
984 /* There are more bytes remaining than were requested.
986 lseek(fd, -n_bytes, SEEK_END);
988 dump_remainder(filename, fd);
990 return pipe_bytes(filename, fd, n_bytes);
995 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
996 Return 0 if successful, 1 if an error occurred. */
998 static int tail_lines(const char *filename, int fd, long int n_lines)
1003 if (fstat(fd, &stats)) {
1004 detailed_error(0, errno, "%s", filename);
1009 if (start_lines(filename, fd, n_lines))
1011 dump_remainder(filename, fd);
1013 /* Use file_lines only if FD refers to a regular file with
1014 its file pointer positioned at beginning of file. */
1015 /* FIXME: adding the lseek conjunct is a kludge.
1016 Once there's a reasonable test suite, fix the true culprit:
1017 file_lines. file_lines shouldn't presume that the input
1018 file pointer is initially positioned to beginning of file. */
1019 if (S_ISREG(stats.st_mode)
1020 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
1021 length = lseek(fd, (off_t) 0, SEEK_END);
1022 if (length != 0 && file_lines(filename, fd, n_lines, length))
1026 return pipe_lines(fd, n_lines);
1031 /* Display the last N_UNITS units of file FILENAME, open for reading
1033 Return 0 if successful, 1 if an error occurred. */
1035 static int tail(const char *filename, int fd, off_t n_units)
1038 return tail_lines(filename, fd, (long) n_units);
1040 return tail_bytes(filename, fd, n_units);
1043 /* Display the last N_UNITS units of file FILENAME.
1044 "-" for FILENAME means the standard input.
1045 FILENUM is this file's index in the list of files the user gave.
1046 Return 0 if successful, 1 if an error occurred. */
1048 static int tail_file(const char *filename, off_t n_units, int filenum)
1053 if (!strcmp(filename, "-")) {
1054 have_read_stdin = 1;
1055 filename = "standard input";
1057 write_header(filename, NULL);
1058 errors = tail(filename, 0, n_units);
1059 if (forever_multiple) {
1060 if (fstat(0, &stats) < 0) {
1061 detailed_error(0, errno, "standard input");
1063 } else if (!S_ISREG(stats.st_mode)) {
1064 detailed_error(0, 0,
1065 "standard input: cannot follow end of non-regular file");
1069 file_descs[filenum] = -1;
1071 file_descs[filenum] = 0;
1072 file_sizes[filenum] = stats.st_size;
1076 /* Not standard input. */
1077 fd = open(filename, O_RDONLY);
1079 if (forever_multiple)
1080 file_descs[filenum] = -1;
1081 detailed_error(0, errno, "%s", filename);
1085 write_header(filename, NULL);
1086 errors = tail(filename, fd, n_units);
1087 if (forever_multiple) {
1088 if (fstat(fd, &stats) < 0) {
1089 detailed_error(0, errno, "%s", filename);
1091 } else if (!S_ISREG(stats.st_mode)) {
1092 detailed_error(0, 0,
1093 "%s: cannot follow end of non-regular file",
1099 file_descs[filenum] = -1;
1101 file_descs[filenum] = fd;
1102 file_sizes[filenum] = stats.st_size;
1106 detailed_error(0, errno, "%s", filename);
1116 extern int tail_main(int argc, char **argv)
1119 enum header_mode header_mode = multiple_files;
1120 int exit_status = 0;
1122 /* If from_start, the number of items to skip before printing; otherwise,
1123 the number of items at the end of the file to print. Initially, -1
1124 means the value has not been set. */
1129 program_name = argv[0];
1130 have_read_stdin = 0;
1132 forever = forever_multiple = from_start = print_headers = 0;
1134 /* Parse any options */
1135 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1136 while (--argc > 0 && (**(++argv) == '-' || **argv == '+')) {
1137 if (**argv == '+') {
1141 while (stopit == 0 && *(++(*argv))) {
1149 n_units = getNum(*(++argv));
1163 n_units = atol(*(++argv));
1168 header_mode = never;
1172 header_mode = always;
1183 n_units = DEFAULT_N_LINES;
1185 /* To start printing with item N_UNITS from the start of the file, skip
1186 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
1187 compatibility it's treated the same as `tail +1'. */
1196 if (n_files > 1 && forever) {
1197 forever_multiple = 1;
1199 file_descs = (int *) xmalloc(n_files * sizeof(int));
1201 file_sizes = (off_t *) xmalloc(n_files * sizeof(off_t));
1204 if (header_mode == always
1205 || (header_mode == multiple_files && n_files > 1))
1209 exit_status |= tail_file("-", n_units, 0);
1213 for (i = 0; i < n_files; i++)
1214 exit_status |= tail_file(file[i], n_units, i);
1216 if (forever_multiple)
1217 tail_forever(file, n_files);
1220 if (have_read_stdin && close(0) < 0)
1221 detailed_error(EXIT_FAILURE, errno, "-");
1222 if (fclose(stdout) == EOF)
1223 detailed_error(EXIT_FAILURE, errno, "write error");
1224 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);