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>
52 #define XWRITE(fd, buffer, n_bytes) \
54 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
55 errorMsg("write error"); \
58 /* Number of items to tail. */
59 #define DEFAULT_N_LINES 10
61 /* Size of atomic reads. */
63 #define BUFSIZ (512 * 8)
66 /* If nonzero, read from the end of one file until killed. */
69 /* If nonzero, print filename headers. */
70 static int print_headers;
72 const char tail_usage[] =
73 "tail [OPTION] [FILE]...\n\n"
74 "Print last 10 lines of each FILE to standard output.\n"
75 "With more than one FILE, precede each with a header giving the\n"
76 "file name. With no FILE, or when FILE is -, read standard input.\n\n"
78 "\t-n NUM\t\tPrint last NUM lines instead of first 10\n"
80 "\t-f\t\tOutput data as the file grows. This version\n"
81 "\t\t\tof 'tail -f' supports only one file at a time.\n";
84 static void write_header(const char *filename)
86 static int first_file = 1;
88 printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
92 /* Print the last N_LINES lines from the end of file FD.
93 Go backward through the file, reading `BUFSIZ' bytes at a time (except
94 probably the first), until we hit the start of the file or have
96 POS starts out as the length of the file (the offset of the last
97 byte of the file + 1).
98 Return 0 if successful, 1 if an error occurred. */
101 file_lines(const char *filename, int fd, long int n_lines, off_t pos)
105 int i; /* Index into `buffer' for scanning. */
110 /* Set `bytes_read' to the size of the last, probably partial, buffer;
111 0 < `bytes_read' <= `BUFSIZ'. */
112 bytes_read = pos % BUFSIZ;
115 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
116 reads will be on block boundaries, which might increase efficiency. */
118 lseek(fd, pos, SEEK_SET);
119 bytes_read = fullRead(fd, buffer, bytes_read);
120 if (bytes_read == -1)
121 errorMsg("read error");
123 /* Count the incomplete line on files that don't end with a newline. */
124 if (bytes_read && buffer[bytes_read - 1] != '\n')
128 /* Scan backward, counting the newlines in this bufferfull. */
129 for (i = bytes_read - 1; i >= 0; i--) {
130 /* Have we counted the requested number of newlines yet? */
131 if (buffer[i] == '\n' && n_lines-- == 0) {
132 /* If this newline wasn't the last character in the buffer,
133 print the text after it. */
134 if (i != bytes_read - 1)
135 XWRITE(STDOUT_FILENO, &buffer[i + 1],
136 bytes_read - (i + 1));
140 /* Not enough newlines in that bufferfull. */
142 /* Not enough lines in the file; print the entire file. */
143 lseek(fd, (off_t) 0, SEEK_SET);
147 lseek(fd, pos, SEEK_SET);
149 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
150 if (bytes_read == -1)
151 errorMsg("read error");
156 /* Print the last N_LINES lines from the end of the standard input,
157 open for reading as pipe FD.
158 Buffer the text as a linked list of LBUFFERs, adding them as needed.
159 Return 0 if successful, 1 if an error occured. */
161 static int pipe_lines(const char *filename, int fd, long int n_lines)
166 struct linebuffer *next;
168 typedef struct linebuffer LBUFFER;
169 LBUFFER *first, *last, *tmp;
170 int i; /* Index into buffers. */
171 int total_lines = 0; /* Total number of newlines in all buffers. */
174 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
175 first->nbytes = first->nlines = 0;
177 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
179 /* Input is always read into a fresh buffer. */
180 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
184 /* Count the number of newlines just read. */
185 for (i = 0; i < tmp->nbytes; i++)
186 if (tmp->buffer[i] == '\n')
188 total_lines += tmp->nlines;
190 /* If there is enough room in the last buffer read, just append the new
191 one to it. This is because when reading from a pipe, `nbytes' can
192 often be very small. */
193 if (tmp->nbytes + last->nbytes < BUFSIZ) {
194 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
195 last->nbytes += tmp->nbytes;
196 last->nlines += tmp->nlines;
198 /* If there's not enough room, link the new buffer onto the end of
199 the list, then either free up the oldest buffer for the next
200 read if that would leave enough lines, or else malloc a new one.
201 Some compaction mechanism is possible but probably not
203 last = last->next = tmp;
204 if (total_lines - first->nlines > n_lines) {
206 total_lines -= first->nlines;
209 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
212 if (tmp->nbytes == -1)
213 errorMsg("read error");
217 /* This prevents a core dump when the pipe contains no newlines. */
221 /* Count the incomplete line on files that don't end with a newline. */
222 if (last->buffer[last->nbytes - 1] != '\n') {
227 /* Run through the list, printing lines. First, skip over unneeded
229 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
230 total_lines -= tmp->nlines;
232 /* Find the correct beginning, then print the rest of the file. */
233 if (total_lines > n_lines) {
236 /* Skip `total_lines' - `n_lines' newlines. We made sure that
237 `total_lines' - `n_lines' <= `tmp->nlines'. */
239 for (i = total_lines - n_lines; i; --i)
240 while (*cp++ != '\n')
242 i = cp - tmp->buffer;
245 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
247 for (tmp = tmp->next; tmp; tmp = tmp->next)
248 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
253 free((char *) first);
259 /* Display file FILENAME from the current position in FD to the end.
260 If `forever' is nonzero, keep reading from the end of the file
261 until killed. Return the number of bytes read from the file. */
263 static long dump_remainder(const char *filename, int fd)
271 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
272 XWRITE(STDOUT_FILENO, buffer, bytes_read);
275 if (bytes_read == -1)
276 errorMsg("read error");
286 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
287 Return 0 if successful, 1 if an error occurred. */
289 static int tail_lines(const char *filename, int fd, long int n_lines)
295 write_header(filename);
297 if (fstat(fd, &stats))
298 errorMsg("fstat error");
300 /* Use file_lines only if FD refers to a regular file with
301 its file pointer positioned at beginning of file. */
302 /* FIXME: adding the lseek conjunct is a kludge.
303 Once there's a reasonable test suite, fix the true culprit:
304 file_lines. file_lines shouldn't presume that the input
305 file pointer is initially positioned to beginning of file. */
306 if (S_ISREG(stats.st_mode)
307 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
308 length = lseek(fd, (off_t) 0, SEEK_END);
309 if (length != 0 && file_lines(filename, fd, n_lines, length))
311 dump_remainder(filename, fd);
313 return pipe_lines(filename, fd, n_lines);
318 /* Display the last N_UNITS lines of file FILENAME.
319 "-" for FILENAME means the standard input.
320 Return 0 if successful, 1 if an error occurred. */
322 static int tail_file(const char *filename, off_t n_units)
326 if (!strcmp(filename, "-")) {
327 filename = "standard input";
328 errors = tail_lines(filename, 0, (long) n_units);
330 /* Not standard input. */
331 fd = open(filename, O_RDONLY);
333 fatalError("open error");
335 errors = tail_lines(filename, fd, (long) n_units);
342 extern int tail_main(int argc, char **argv)
345 int n_units = DEFAULT_N_LINES;
349 forever = print_headers = 0;
352 for (i = 1; i < argc; i++) {
353 if (argv[i][0] == '-') {
362 n_tmp = atoi(argv[i]);
371 fprintf(stderr, "tail: invalid option -- %c\n", opt);
382 "tail: option -f is invalid with multiple files\n");
389 exit_status |= tail_file("-", n_units);
391 for (; i < argc; i++)
392 exit_status |= tail_file(argv[i], n_units);
395 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
400 // Here follows the code for the full featured tail code
403 /* tail -- output the last part of file(s)
404 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
406 This program is free software; you can redistribute it and/or modify
407 it under the terms of the GNU General Public License as published by
408 the Free Software Foundation; either version 2, or (at your option)
411 This program is distributed in the hope that it will be useful,
412 but WITHOUT ANY WARRANTY; without even the implied warranty of
413 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
414 GNU General Public License for more details.
416 You should have received a copy of the GNU General Public License
417 along with this program; if not, write to the Free Software
418 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
420 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
421 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
422 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
424 Rewrote the option parser, removed locales support,
425 and generally busyboxed, Erik Andersen <andersen@lineo.com>
429 #include "internal.h"
435 #include <sys/types.h>
436 #include <sys/types.h>
437 #include <sys/stat.h>
443 /* Disable assertions. Some systems have broken assert macros. */
447 static void detailed_error(int i, int errnum, char *fmt, ...)
448 __attribute__ ((format (printf, 3, 4)));
449 static void detailed_error(int i, int errnum, char *fmt, ...)
453 va_start(arguments, fmt);
454 vfprintf(stderr, fmt, arguments);
455 fprintf(stderr, "\n%s\n", strerror(errnum));
461 #define XWRITE(fd, buffer, n_bytes) \
464 assert ((fd) == 1); \
465 assert ((n_bytes) >= 0); \
466 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
467 detailed_error (EXIT_FAILURE, errno, "write error"); \
471 /* Number of items to tail. */
472 #define DEFAULT_N_LINES 10
474 /* Size of atomic reads. */
476 #define BUFSIZ (512 * 8)
479 /* If nonzero, interpret the numeric argument as the number of lines.
480 Otherwise, interpret it as the number of bytes. */
481 static int count_lines;
483 /* If nonzero, read from the end of one file until killed. */
486 /* If nonzero, read from the end of multiple files until killed. */
487 static int forever_multiple;
489 /* Array of file descriptors if forever_multiple is 1. */
490 static int *file_descs;
492 /* Array of file sizes if forever_multiple is 1. */
493 static off_t *file_sizes;
495 /* If nonzero, count from start of file instead of end. */
496 static int from_start;
498 /* If nonzero, print filename headers. */
499 static int print_headers;
501 /* When to print the filename banners. */
503 multiple_files, always, never
506 /* The name this program was run with. */
509 /* Nonzero if we have ever read standard input. */
510 static int have_read_stdin;
513 static const char tail_usage[] = "tail [OPTION]... [FILE]...\n\
515 Print last 10 lines of each FILE to standard output.\n\
516 With more than one FILE, precede each with a header giving the file name.\n\
517 With no FILE, or when FILE is -, read standard input.\n\
519 -c=N[kbm] output the last N bytes\n\
520 -f output appended data as the file grows\n\
521 -n=N output the last N lines, instead of last 10\n\
522 -q never output headers giving file names\n\
523 -v always output headers giving file names\n\
524 --help display this help and exit\n\
526 If the first character of N (bytes or lines) is a `+', output begins with \n\
527 the Nth item from the start of each file, otherwise, print the last N items\n\
528 in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n";
530 static void write_header(const char *filename, const char *comment)
532 static int first_file = 1;
534 printf("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
535 (comment ? ": " : ""), (comment ? comment : ""));
539 /* Print the last N_LINES lines from the end of file FD.
540 Go backward through the file, reading `BUFSIZ' bytes at a time (except
541 probably the first), until we hit the start of the file or have
542 read NUMBER newlines.
543 POS starts out as the length of the file (the offset of the last
544 byte of the file + 1).
545 Return 0 if successful, 1 if an error occurred. */
548 file_lines(const char *filename, int fd, long int n_lines, off_t pos)
552 int i; /* Index into `buffer' for scanning. */
557 /* Set `bytes_read' to the size of the last, probably partial, buffer;
558 0 < `bytes_read' <= `BUFSIZ'. */
559 bytes_read = pos % BUFSIZ;
562 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
563 reads will be on block boundaries, which might increase efficiency. */
565 lseek(fd, pos, SEEK_SET);
566 bytes_read = fullRead(fd, buffer, bytes_read);
567 if (bytes_read == -1) {
568 detailed_error(0, errno, "%s", filename);
572 /* Count the incomplete line on files that don't end with a newline. */
573 if (bytes_read && buffer[bytes_read - 1] != '\n')
577 /* Scan backward, counting the newlines in this bufferfull. */
578 for (i = bytes_read - 1; i >= 0; i--) {
579 /* Have we counted the requested number of newlines yet? */
580 if (buffer[i] == '\n' && n_lines-- == 0) {
581 /* If this newline wasn't the last character in the buffer,
582 print the text after it. */
583 if (i != bytes_read - 1)
584 XWRITE(STDOUT_FILENO, &buffer[i + 1],
585 bytes_read - (i + 1));
589 /* Not enough newlines in that bufferfull. */
591 /* Not enough lines in the file; print the entire file. */
592 lseek(fd, (off_t) 0, SEEK_SET);
596 lseek(fd, pos, SEEK_SET);
598 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
599 if (bytes_read == -1) {
600 detailed_error(0, errno, "%s", filename);
606 /* Print the last N_LINES lines from the end of the standard input,
607 open for reading as pipe FD.
608 Buffer the text as a linked list of LBUFFERs, adding them as needed.
609 Return 0 if successful, 1 if an error occured. */
611 static int pipe_lines(const char *filename, int fd, long int n_lines)
616 struct linebuffer *next;
618 typedef struct linebuffer LBUFFER;
619 LBUFFER *first, *last, *tmp;
620 int i; /* Index into buffers. */
621 int total_lines = 0; /* Total number of newlines in all buffers. */
624 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
625 first->nbytes = first->nlines = 0;
627 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
629 /* Input is always read into a fresh buffer. */
630 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
634 /* Count the number of newlines just read. */
635 for (i = 0; i < tmp->nbytes; i++)
636 if (tmp->buffer[i] == '\n')
638 total_lines += tmp->nlines;
640 /* If there is enough room in the last buffer read, just append the new
641 one to it. This is because when reading from a pipe, `nbytes' can
642 often be very small. */
643 if (tmp->nbytes + last->nbytes < BUFSIZ) {
644 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
645 last->nbytes += tmp->nbytes;
646 last->nlines += tmp->nlines;
648 /* If there's not enough room, link the new buffer onto the end of
649 the list, then either free up the oldest buffer for the next
650 read if that would leave enough lines, or else malloc a new one.
651 Some compaction mechanism is possible but probably not
653 last = last->next = tmp;
654 if (total_lines - first->nlines > n_lines) {
656 total_lines -= first->nlines;
659 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
662 if (tmp->nbytes == -1) {
663 detailed_error(0, errno, "%s", filename);
671 /* This prevents a core dump when the pipe contains no newlines. */
675 /* Count the incomplete line on files that don't end with a newline. */
676 if (last->buffer[last->nbytes - 1] != '\n') {
681 /* Run through the list, printing lines. First, skip over unneeded
683 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
684 total_lines -= tmp->nlines;
686 /* Find the correct beginning, then print the rest of the file. */
687 if (total_lines > n_lines) {
690 /* Skip `total_lines' - `n_lines' newlines. We made sure that
691 `total_lines' - `n_lines' <= `tmp->nlines'. */
693 for (i = total_lines - n_lines; i; --i)
694 while (*cp++ != '\n')
696 i = cp - tmp->buffer;
699 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
701 for (tmp = tmp->next; tmp; tmp = tmp->next)
702 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
707 free((char *) first);
713 /* Print the last N_BYTES characters from the end of pipe FD.
714 This is a stripped down version of pipe_lines.
715 Return 0 if successful, 1 if an error occurred. */
717 static int pipe_bytes(const char *filename, int fd, off_t n_bytes)
722 struct charbuffer *next;
724 typedef struct charbuffer CBUFFER;
725 CBUFFER *first, *last, *tmp;
726 int i; /* Index into buffers. */
727 int total_bytes = 0; /* Total characters in all buffers. */
730 first = last = (CBUFFER *) xmalloc(sizeof(CBUFFER));
733 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
735 /* Input is always read into a fresh buffer. */
736 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
739 total_bytes += tmp->nbytes;
740 /* If there is enough room in the last buffer read, just append the new
741 one to it. This is because when reading from a pipe, `nbytes' can
742 often be very small. */
743 if (tmp->nbytes + last->nbytes < BUFSIZ) {
744 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
745 last->nbytes += tmp->nbytes;
747 /* If there's not enough room, link the new buffer onto the end of
748 the list, then either free up the oldest buffer for the next
749 read if that would leave enough characters, or else malloc a new
750 one. Some compaction mechanism is possible but probably not
752 last = last->next = tmp;
753 if (total_bytes - first->nbytes > n_bytes) {
755 total_bytes -= first->nbytes;
758 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
762 if (tmp->nbytes == -1) {
763 detailed_error(0, errno, "%s", filename);
771 /* Run through the list, printing characters. First, skip over unneeded
773 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
774 total_bytes -= tmp->nbytes;
776 /* Find the correct beginning, then print the rest of the file.
777 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
778 if (total_bytes > n_bytes)
779 i = total_bytes - n_bytes;
782 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
784 for (tmp = tmp->next; tmp; tmp = tmp->next)
785 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
790 free((char *) first);
796 /* Skip N_BYTES characters from the start of pipe FD, and print
797 any extra characters that were read beyond that.
798 Return 1 on error, 0 if ok. */
800 static int start_bytes(const char *filename, int fd, off_t n_bytes)
805 while (n_bytes > 0 && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0)
806 n_bytes -= bytes_read;
807 if (bytes_read == -1) {
808 detailed_error(0, errno, "%s", filename);
810 } else if (n_bytes < 0)
811 XWRITE(STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
815 /* Skip N_LINES lines at the start of file or pipe FD, and print
816 any extra characters that were read beyond that.
817 Return 1 on error, 0 if ok. */
819 static int start_lines(const char *filename, int fd, long int n_lines)
823 int bytes_to_skip = 0;
825 while (n_lines && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
827 while (bytes_to_skip < bytes_read)
828 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
831 if (bytes_read == -1) {
832 detailed_error(0, errno, "%s", filename);
834 } else if (bytes_to_skip < bytes_read) {
835 XWRITE(STDOUT_FILENO, &buffer[bytes_to_skip],
836 bytes_read - bytes_to_skip);
841 /* Display file FILENAME from the current position in FD to the end.
842 If `forever' is nonzero, keep reading from the end of the file
843 until killed. Return the number of bytes read from the file. */
845 static long dump_remainder(const char *filename, int fd)
853 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
854 XWRITE(STDOUT_FILENO, buffer, bytes_read);
857 if (bytes_read == -1)
858 detailed_error(EXIT_FAILURE, errno, "%s", filename);
864 if (forever_multiple)
871 /* Tail NFILES (>1) files forever until killed. The file names are in
872 NAMES. The open file descriptors are in `file_descs', and the size
873 at which we stopped tailing them is in `file_sizes'. We loop over
874 each of them, doing an fstat to see if they have changed size. If
875 none of them have changed size in one iteration, we sleep for a
876 second and try again. We do this until the user interrupts us. */
878 static void tail_forever(char **names, int nfiles)
889 for (i = 0; i < nfiles; i++) {
892 if (file_descs[i] < 0)
894 if (fstat(file_descs[i], &stats) < 0) {
895 detailed_error(0, errno, "%s", names[i]);
899 if (stats.st_size == file_sizes[i])
902 /* This file has changed size. Print out what we can, and
903 then keep looping. */
907 if (stats.st_size < file_sizes[i]) {
908 write_header(names[i], "file truncated");
910 lseek(file_descs[i], stats.st_size, SEEK_SET);
911 file_sizes[i] = stats.st_size;
917 write_header(names[i], NULL);
920 file_sizes[i] += dump_remainder(names[i], file_descs[i]);
923 /* If none of the files changed size, sleep. */
929 /* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
930 Return 0 if successful, 1 if an error occurred. */
932 static int tail_bytes(const char *filename, int fd, off_t n_bytes)
936 /* FIXME: resolve this like in dd.c. */
937 /* Use fstat instead of checking for errno == ESPIPE because
938 lseek doesn't work on some special files but doesn't return an
940 if (fstat(fd, &stats)) {
941 detailed_error(0, errno, "%s", filename);
946 if (S_ISREG(stats.st_mode))
947 lseek(fd, n_bytes, SEEK_CUR);
948 else if (start_bytes(filename, fd, n_bytes))
950 dump_remainder(filename, fd);
952 if (S_ISREG(stats.st_mode)) {
953 off_t current_pos, end_pos;
954 size_t bytes_remaining;
956 if ((current_pos = lseek(fd, (off_t) 0, SEEK_CUR)) != -1
957 && (end_pos = lseek(fd, (off_t) 0, SEEK_END)) != -1) {
960 /* Be careful here. The current position may actually be
961 beyond the end of the file. */
962 bytes_remaining = (diff =
963 end_pos - current_pos) < 0 ? 0 : diff;
965 detailed_error(0, errno, "%s", filename);
969 if (bytes_remaining <= n_bytes) {
970 /* From the current position to end of file, there are no
971 more bytes than have been requested. So reposition the
972 file pointer to the incoming current position and print
973 everything after that. */
974 lseek(fd, current_pos, SEEK_SET);
976 /* There are more bytes remaining than were requested.
978 lseek(fd, -n_bytes, SEEK_END);
980 dump_remainder(filename, fd);
982 return pipe_bytes(filename, fd, n_bytes);
987 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
988 Return 0 if successful, 1 if an error occurred. */
990 static int tail_lines(const char *filename, int fd, long int n_lines)
995 if (fstat(fd, &stats)) {
996 detailed_error(0, errno, "%s", filename);
1001 if (start_lines(filename, fd, n_lines))
1003 dump_remainder(filename, fd);
1005 /* Use file_lines only if FD refers to a regular file with
1006 its file pointer positioned at beginning of file. */
1007 /* FIXME: adding the lseek conjunct is a kludge.
1008 Once there's a reasonable test suite, fix the true culprit:
1009 file_lines. file_lines shouldn't presume that the input
1010 file pointer is initially positioned to beginning of file. */
1011 if (S_ISREG(stats.st_mode)
1012 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
1013 length = lseek(fd, (off_t) 0, SEEK_END);
1014 if (length != 0 && file_lines(filename, fd, n_lines, length))
1016 dump_remainder(filename, fd);
1018 return pipe_lines(filename, fd, n_lines);
1023 /* Display the last N_UNITS units of file FILENAME, open for reading
1025 Return 0 if successful, 1 if an error occurred. */
1027 static int tail(const char *filename, int fd, off_t n_units)
1030 return tail_lines(filename, fd, (long) n_units);
1032 return tail_bytes(filename, fd, n_units);
1035 /* Display the last N_UNITS units of file FILENAME.
1036 "-" for FILENAME means the standard input.
1037 FILENUM is this file's index in the list of files the user gave.
1038 Return 0 if successful, 1 if an error occurred. */
1040 static int tail_file(const char *filename, off_t n_units, int filenum)
1045 if (!strcmp(filename, "-")) {
1046 have_read_stdin = 1;
1047 filename = "standard input";
1049 write_header(filename, NULL);
1050 errors = tail(filename, 0, n_units);
1051 if (forever_multiple) {
1052 if (fstat(0, &stats) < 0) {
1053 detailed_error(0, errno, "standard input");
1055 } else if (!S_ISREG(stats.st_mode)) {
1056 detailed_error(0, 0,
1057 "standard input: cannot follow end of non-regular file");
1061 file_descs[filenum] = -1;
1063 file_descs[filenum] = 0;
1064 file_sizes[filenum] = stats.st_size;
1068 /* Not standard input. */
1069 fd = open(filename, O_RDONLY);
1071 if (forever_multiple)
1072 file_descs[filenum] = -1;
1073 detailed_error(0, errno, "%s", filename);
1077 write_header(filename, NULL);
1078 errors = tail(filename, fd, n_units);
1079 if (forever_multiple) {
1080 if (fstat(fd, &stats) < 0) {
1081 detailed_error(0, errno, "%s", filename);
1083 } else if (!S_ISREG(stats.st_mode)) {
1084 detailed_error(0, 0,
1085 "%s: cannot follow end of non-regular file",
1091 file_descs[filenum] = -1;
1093 file_descs[filenum] = fd;
1094 file_sizes[filenum] = stats.st_size;
1098 detailed_error(0, errno, "%s", filename);
1108 extern int tail_main(int argc, char **argv)
1111 enum header_mode header_mode = multiple_files;
1112 int exit_status = 0;
1114 /* If from_start, the number of items to skip before printing; otherwise,
1115 the number of items at the end of the file to print. Initially, -1
1116 means the value has not been set. */
1121 program_name = argv[0];
1122 have_read_stdin = 0;
1124 forever = forever_multiple = from_start = print_headers = 0;
1126 /* Parse any options */
1127 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1128 while (--argc > 0 && (**(++argv) == '-' || **argv == '+')) {
1129 if (**argv == '+') {
1133 while (stopit == 0 && *(++(*argv))) {
1141 n_units = getNum(*(++argv));
1155 n_units = atol(*(++argv));
1160 header_mode = never;
1164 header_mode = always;
1175 n_units = DEFAULT_N_LINES;
1177 /* To start printing with item N_UNITS from the start of the file, skip
1178 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
1179 compatibility it's treated the same as `tail +1'. */
1188 if (n_files > 1 && forever) {
1189 forever_multiple = 1;
1191 file_descs = (int *) xmalloc(n_files * sizeof(int));
1193 file_sizes = (off_t *) xmalloc(n_files * sizeof(off_t));
1196 if (header_mode == always
1197 || (header_mode == multiple_files && n_files > 1))
1201 exit_status |= tail_file("-", n_units, 0);
1205 for (i = 0; i < n_files; i++)
1206 exit_status |= tail_file(file[i], n_units, i);
1208 if (forever_multiple)
1209 tail_forever(file, n_files);
1212 if (have_read_stdin && close(0) < 0)
1213 detailed_error(EXIT_FAILURE, errno, "-");
1214 if (fclose(stdout) == EOF)
1215 detailed_error(EXIT_FAILURE, errno, "write error");
1216 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);