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 static void write_header(const char *filename)
77 static int first_file = 1;
79 printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
83 /* Print the last N_LINES lines from the end of file FD.
84 Go backward through the file, reading `BUFSIZ' bytes at a time (except
85 probably the first), until we hit the start of the file or have
87 POS starts out as the length of the file (the offset of the last
88 byte of the file + 1).
89 Return 0 if successful, 1 if an error occurred. */
92 file_lines(int fd, long int n_lines, off_t pos)
96 int i; /* Index into `buffer' for scanning. */
101 /* Set `bytes_read' to the size of the last, probably partial, buffer;
102 0 < `bytes_read' <= `BUFSIZ'. */
103 bytes_read = pos % BUFSIZ;
106 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
107 reads will be on block boundaries, which might increase efficiency. */
109 lseek(fd, pos, SEEK_SET);
110 bytes_read = fullRead(fd, buffer, bytes_read);
111 if (bytes_read == -1)
112 errorMsg("read error");
114 /* Count the incomplete line on files that don't end with a newline. */
115 if (bytes_read && buffer[bytes_read - 1] != '\n')
119 /* Scan backward, counting the newlines in this bufferfull. */
120 for (i = bytes_read - 1; i >= 0; i--) {
121 /* Have we counted the requested number of newlines yet? */
122 if (buffer[i] == '\n' && n_lines-- == 0) {
123 /* If this newline wasn't the last character in the buffer,
124 print the text after it. */
125 if (i != bytes_read - 1)
126 XWRITE(STDOUT_FILENO, &buffer[i + 1],
127 bytes_read - (i + 1));
131 /* Not enough newlines in that bufferfull. */
133 /* Not enough lines in the file; print the entire file. */
134 lseek(fd, (off_t) 0, SEEK_SET);
138 lseek(fd, pos, SEEK_SET);
140 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
141 if (bytes_read == -1)
142 errorMsg("read error");
147 /* Print the last N_LINES lines from the end of the standard input,
148 open for reading as pipe FD.
149 Buffer the text as a linked list of LBUFFERs, adding them as needed.
150 Return 0 if successful, 1 if an error occured. */
152 static int pipe_lines(int fd, long int n_lines)
157 struct linebuffer *next;
159 typedef struct linebuffer LBUFFER;
160 LBUFFER *first, *last, *tmp;
161 int i; /* Index into buffers. */
162 int total_lines = 0; /* Total number of newlines in all buffers. */
165 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
166 first->nbytes = first->nlines = 0;
168 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
170 /* Input is always read into a fresh buffer. */
171 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
175 /* Count the number of newlines just read. */
176 for (i = 0; i < tmp->nbytes; i++)
177 if (tmp->buffer[i] == '\n')
179 total_lines += tmp->nlines;
181 /* If there is enough room in the last buffer read, just append the new
182 one to it. This is because when reading from a pipe, `nbytes' can
183 often be very small. */
184 if (tmp->nbytes + last->nbytes < BUFSIZ) {
185 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
186 last->nbytes += tmp->nbytes;
187 last->nlines += tmp->nlines;
189 /* If there's not enough room, link the new buffer onto the end of
190 the list, then either free up the oldest buffer for the next
191 read if that would leave enough lines, or else malloc a new one.
192 Some compaction mechanism is possible but probably not
194 last = last->next = tmp;
195 if (total_lines - first->nlines > n_lines) {
197 total_lines -= first->nlines;
200 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
203 if (tmp->nbytes == -1)
204 errorMsg("read error");
208 /* This prevents a core dump when the pipe contains no newlines. */
212 /* Count the incomplete line on files that don't end with a newline. */
213 if (last->buffer[last->nbytes - 1] != '\n') {
218 /* Run through the list, printing lines. First, skip over unneeded
220 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
221 total_lines -= tmp->nlines;
223 /* Find the correct beginning, then print the rest of the file. */
224 if (total_lines > n_lines) {
227 /* Skip `total_lines' - `n_lines' newlines. We made sure that
228 `total_lines' - `n_lines' <= `tmp->nlines'. */
230 for (i = total_lines - n_lines; i; --i)
231 while (*cp++ != '\n')
233 i = cp - tmp->buffer;
236 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
238 for (tmp = tmp->next; tmp; tmp = tmp->next)
239 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
244 free((char *) first);
250 /* Display file FILENAME from the current position in FD to the end.
251 If `forever' is nonzero, keep reading from the end of the file
252 until killed. Return the number of bytes read from the file. */
254 static long dump_remainder(int fd)
262 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
263 XWRITE(STDOUT_FILENO, buffer, bytes_read);
266 if (bytes_read == -1)
267 errorMsg("read error");
277 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
278 Return 0 if successful, 1 if an error occurred. */
280 static int tail_lines(const char *filename, int fd, long int n_lines)
286 write_header(filename);
288 if (fstat(fd, &stats))
289 errorMsg("fstat error");
291 /* Use file_lines only if FD refers to a regular file with
292 its file pointer positioned at beginning of file. */
293 /* FIXME: adding the lseek conjunct is a kludge.
294 Once there's a reasonable test suite, fix the true culprit:
295 file_lines. file_lines shouldn't presume that the input
296 file pointer is initially positioned to beginning of file. */
297 if (S_ISREG(stats.st_mode)
298 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
299 length = lseek(fd, (off_t) 0, SEEK_END);
300 if (length != 0 && file_lines(fd, n_lines, length))
304 return pipe_lines(fd, n_lines);
309 /* Display the last N_UNITS lines of file FILENAME.
310 "-" for FILENAME means the standard input.
311 Return 0 if successful, 1 if an error occurred. */
313 static int tail_file(const char *filename, off_t n_units)
317 if (!strcmp(filename, "-")) {
318 filename = "standard input";
319 errors = tail_lines(filename, 0, (long) n_units);
321 /* Not standard input. */
322 fd = open(filename, O_RDONLY);
326 errors = tail_lines(filename, fd, (long) n_units);
333 extern int tail_main(int argc, char **argv)
336 int n_units = DEFAULT_N_LINES;
340 forever = print_headers = 0;
343 for (i = 1; i < argc; i++) {
344 if (argv[i][0] == '-') {
353 n_tmp = atoi(argv[i]);
362 if ((n_units = atoi(&argv[i][1])) < 1) {
363 errorMsg("invalid option -- %c\n", opt);
374 errorMsg("option -f is invalid with multiple files\n");
381 exit_status |= tail_file("-", n_units);
383 for (; i < argc; i++)
384 exit_status |= tail_file(argv[i], n_units);
387 return(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
392 // Here follows the code for the full featured tail code
395 /* tail -- output the last part of file(s)
396 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
398 This program is free software; you can redistribute it and/or modify
399 it under the terms of the GNU General Public License as published by
400 the Free Software Foundation; either version 2, or (at your option)
403 This program is distributed in the hope that it will be useful,
404 but WITHOUT ANY WARRANTY; without even the implied warranty of
405 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
406 GNU General Public License for more details.
408 You should have received a copy of the GNU General Public License
409 along with this program; if not, write to the Free Software
410 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
412 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
413 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
414 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
416 Rewrote the option parser, removed locales support,
417 and generally busyboxed, Erik Andersen <andersen@lineo.com>
421 #include "internal.h"
427 #include <sys/types.h>
428 #include <sys/types.h>
429 #include <sys/stat.h>
435 /* Disable assertions. Some systems have broken assert macros. */
439 static void detailed_error(int i, int errnum, char *fmt, ...)
440 __attribute__ ((format (printf, 3, 4)));
441 static void detailed_error(int i, int errnum, char *fmt, ...)
445 va_start(arguments, fmt);
446 vfprintf(stderr, fmt, arguments);
447 fprintf(stderr, "\n%s\n", strerror(errnum));
453 #define XWRITE(fd, buffer, n_bytes) \
456 assert ((fd) == 1); \
457 assert ((n_bytes) >= 0); \
458 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
459 detailed_error (EXIT_FAILURE, errno, "write error"); \
463 /* Number of items to tail. */
464 #define DEFAULT_N_LINES 10
466 /* Size of atomic reads. */
468 #define BUFSIZ (512 * 8)
471 /* If nonzero, interpret the numeric argument as the number of lines.
472 Otherwise, interpret it as the number of bytes. */
473 static int count_lines;
475 /* If nonzero, read from the end of one file until killed. */
478 /* If nonzero, read from the end of multiple files until killed. */
479 static int forever_multiple;
481 /* Array of file descriptors if forever_multiple is 1. */
482 static int *file_descs;
484 /* Array of file sizes if forever_multiple is 1. */
485 static off_t *file_sizes;
487 /* If nonzero, count from start of file instead of end. */
488 static int from_start;
490 /* If nonzero, print filename headers. */
491 static int print_headers;
493 /* When to print the filename banners. */
495 multiple_files, always, never
498 /* The name this program was run with. */
501 /* Nonzero if we have ever read standard input. */
502 static int have_read_stdin;
504 static void write_header(const char *filename, const char *comment)
506 static int first_file = 1;
508 printf("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
509 (comment ? ": " : ""), (comment ? comment : ""));
513 /* Print the last N_LINES lines from the end of file FD.
514 Go backward through the file, reading `BUFSIZ' bytes at a time (except
515 probably the first), until we hit the start of the file or have
516 read NUMBER newlines.
517 POS starts out as the length of the file (the offset of the last
518 byte of the file + 1).
519 Return 0 if successful, 1 if an error occurred. */
522 file_lines(const char *filename, int fd, long int n_lines, off_t pos)
526 int i; /* Index into `buffer' for scanning. */
531 /* Set `bytes_read' to the size of the last, probably partial, buffer;
532 0 < `bytes_read' <= `BUFSIZ'. */
533 bytes_read = pos % BUFSIZ;
536 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
537 reads will be on block boundaries, which might increase efficiency. */
539 lseek(fd, pos, SEEK_SET);
540 bytes_read = fullRead(fd, buffer, bytes_read);
541 if (bytes_read == -1) {
542 detailed_error(0, errno, "%s", filename);
546 /* Count the incomplete line on files that don't end with a newline. */
547 if (bytes_read && buffer[bytes_read - 1] != '\n')
551 /* Scan backward, counting the newlines in this bufferfull. */
552 for (i = bytes_read - 1; i >= 0; i--) {
553 /* Have we counted the requested number of newlines yet? */
554 if (buffer[i] == '\n' && n_lines-- == 0) {
555 /* If this newline wasn't the last character in the buffer,
556 print the text after it. */
557 if (i != bytes_read - 1)
558 XWRITE(STDOUT_FILENO, &buffer[i + 1],
559 bytes_read - (i + 1));
563 /* Not enough newlines in that bufferfull. */
565 /* Not enough lines in the file; print the entire file. */
566 lseek(fd, (off_t) 0, SEEK_SET);
570 lseek(fd, pos, SEEK_SET);
572 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
573 if (bytes_read == -1) {
574 detailed_error(0, errno, "%s", filename);
580 /* Print the last N_LINES lines from the end of the standard input,
581 open for reading as pipe FD.
582 Buffer the text as a linked list of LBUFFERs, adding them as needed.
583 Return 0 if successful, 1 if an error occured. */
585 static int pipe_lines(int fd, long int n_lines)
590 struct linebuffer *next;
592 typedef struct linebuffer LBUFFER;
593 LBUFFER *first, *last, *tmp;
594 int i; /* Index into buffers. */
595 int total_lines = 0; /* Total number of newlines in all buffers. */
598 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
599 first->nbytes = first->nlines = 0;
601 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
603 /* Input is always read into a fresh buffer. */
604 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
608 /* Count the number of newlines just read. */
609 for (i = 0; i < tmp->nbytes; i++)
610 if (tmp->buffer[i] == '\n')
612 total_lines += tmp->nlines;
614 /* If there is enough room in the last buffer read, just append the new
615 one to it. This is because when reading from a pipe, `nbytes' can
616 often be very small. */
617 if (tmp->nbytes + last->nbytes < BUFSIZ) {
618 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
619 last->nbytes += tmp->nbytes;
620 last->nlines += tmp->nlines;
622 /* If there's not enough room, link the new buffer onto the end of
623 the list, then either free up the oldest buffer for the next
624 read if that would leave enough lines, or else malloc a new one.
625 Some compaction mechanism is possible but probably not
627 last = last->next = tmp;
628 if (total_lines - first->nlines > n_lines) {
630 total_lines -= first->nlines;
633 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
636 if (tmp->nbytes == -1) {
637 detailed_error(0, errno, "%s", filename);
645 /* This prevents a core dump when the pipe contains no newlines. */
649 /* Count the incomplete line on files that don't end with a newline. */
650 if (last->buffer[last->nbytes - 1] != '\n') {
655 /* Run through the list, printing lines. First, skip over unneeded
657 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
658 total_lines -= tmp->nlines;
660 /* Find the correct beginning, then print the rest of the file. */
661 if (total_lines > n_lines) {
664 /* Skip `total_lines' - `n_lines' newlines. We made sure that
665 `total_lines' - `n_lines' <= `tmp->nlines'. */
667 for (i = total_lines - n_lines; i; --i)
668 while (*cp++ != '\n')
670 i = cp - tmp->buffer;
673 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
675 for (tmp = tmp->next; tmp; tmp = tmp->next)
676 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
681 free((char *) first);
687 /* Print the last N_BYTES characters from the end of pipe FD.
688 This is a stripped down version of pipe_lines.
689 Return 0 if successful, 1 if an error occurred. */
691 static int pipe_bytes(const char *filename, int fd, off_t n_bytes)
696 struct charbuffer *next;
698 typedef struct charbuffer CBUFFER;
699 CBUFFER *first, *last, *tmp;
700 int i; /* Index into buffers. */
701 int total_bytes = 0; /* Total characters in all buffers. */
704 first = last = (CBUFFER *) xmalloc(sizeof(CBUFFER));
707 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
709 /* Input is always read into a fresh buffer. */
710 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
713 total_bytes += tmp->nbytes;
714 /* If there is enough room in the last buffer read, just append the new
715 one to it. This is because when reading from a pipe, `nbytes' can
716 often be very small. */
717 if (tmp->nbytes + last->nbytes < BUFSIZ) {
718 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
719 last->nbytes += tmp->nbytes;
721 /* If there's not enough room, link the new buffer onto the end of
722 the list, then either free up the oldest buffer for the next
723 read if that would leave enough characters, or else malloc a new
724 one. Some compaction mechanism is possible but probably not
726 last = last->next = tmp;
727 if (total_bytes - first->nbytes > n_bytes) {
729 total_bytes -= first->nbytes;
732 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
736 if (tmp->nbytes == -1) {
737 detailed_error(0, errno, "%s", filename);
745 /* Run through the list, printing characters. First, skip over unneeded
747 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
748 total_bytes -= tmp->nbytes;
750 /* Find the correct beginning, then print the rest of the file.
751 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
752 if (total_bytes > n_bytes)
753 i = total_bytes - n_bytes;
756 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
758 for (tmp = tmp->next; tmp; tmp = tmp->next)
759 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
764 free((char *) first);
770 /* Skip N_BYTES characters from the start of pipe FD, and print
771 any extra characters that were read beyond that.
772 Return 1 on error, 0 if ok. */
774 static int start_bytes(const char *filename, int fd, off_t n_bytes)
779 while (n_bytes > 0 && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0)
780 n_bytes -= bytes_read;
781 if (bytes_read == -1) {
782 detailed_error(0, errno, "%s", filename);
784 } else if (n_bytes < 0)
785 XWRITE(STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
789 /* Skip N_LINES lines at the start of file or pipe FD, and print
790 any extra characters that were read beyond that.
791 Return 1 on error, 0 if ok. */
793 static int start_lines(const char *filename, int fd, long int n_lines)
797 int bytes_to_skip = 0;
799 while (n_lines && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
801 while (bytes_to_skip < bytes_read)
802 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
805 if (bytes_read == -1) {
806 detailed_error(0, errno, "%s", filename);
808 } else if (bytes_to_skip < bytes_read) {
809 XWRITE(STDOUT_FILENO, &buffer[bytes_to_skip],
810 bytes_read - bytes_to_skip);
815 /* Display file FILENAME from the current position in FD to the end.
816 If `forever' is nonzero, keep reading from the end of the file
817 until killed. Return the number of bytes read from the file. */
819 static long dump_remainder(int fd)
827 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
828 XWRITE(STDOUT_FILENO, buffer, bytes_read);
831 if (bytes_read == -1)
832 detailed_error(EXIT_FAILURE, errno, "%s", filename);
838 if (forever_multiple)
845 /* Tail NFILES (>1) files forever until killed. The file names are in
846 NAMES. The open file descriptors are in `file_descs', and the size
847 at which we stopped tailing them is in `file_sizes'. We loop over
848 each of them, doing an fstat to see if they have changed size. If
849 none of them have changed size in one iteration, we sleep for a
850 second and try again. We do this until the user interrupts us. */
852 static void tail_forever(char **names, int nfiles)
863 for (i = 0; i < nfiles; i++) {
866 if (file_descs[i] < 0)
868 if (fstat(file_descs[i], &stats) < 0) {
869 detailed_error(0, errno, "%s", names[i]);
873 if (stats.st_size == file_sizes[i])
876 /* This file has changed size. Print out what we can, and
877 then keep looping. */
881 if (stats.st_size < file_sizes[i]) {
882 write_header(names[i], "file truncated");
884 lseek(file_descs[i], stats.st_size, SEEK_SET);
885 file_sizes[i] = stats.st_size;
891 write_header(names[i], NULL);
894 file_sizes[i] += dump_remainder(file_descs[i]);
897 /* If none of the files changed size, sleep. */
903 /* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
904 Return 0 if successful, 1 if an error occurred. */
906 static int tail_bytes(const char *filename, int fd, off_t n_bytes)
910 /* FIXME: resolve this like in dd.c. */
911 /* Use fstat instead of checking for errno == ESPIPE because
912 lseek doesn't work on some special files but doesn't return an
914 if (fstat(fd, &stats)) {
915 detailed_error(0, errno, "%s", filename);
920 if (S_ISREG(stats.st_mode))
921 lseek(fd, n_bytes, SEEK_CUR);
922 else if (start_bytes(filename, fd, n_bytes))
926 if (S_ISREG(stats.st_mode)) {
927 off_t current_pos, end_pos;
928 size_t bytes_remaining;
930 if ((current_pos = lseek(fd, (off_t) 0, SEEK_CUR)) != -1
931 && (end_pos = lseek(fd, (off_t) 0, SEEK_END)) != -1) {
934 /* Be careful here. The current position may actually be
935 beyond the end of the file. */
936 bytes_remaining = (diff =
937 end_pos - current_pos) < 0 ? 0 : diff;
939 detailed_error(0, errno, "%s", filename);
943 if (bytes_remaining <= n_bytes) {
944 /* From the current position to end of file, there are no
945 more bytes than have been requested. So reposition the
946 file pointer to the incoming current position and print
947 everything after that. */
948 lseek(fd, current_pos, SEEK_SET);
950 /* There are more bytes remaining than were requested.
952 lseek(fd, -n_bytes, SEEK_END);
954 dump_remainder(filename, fd);
956 return pipe_bytes(filename, fd, n_bytes);
961 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
962 Return 0 if successful, 1 if an error occurred. */
964 static int tail_lines(const char *filename, int fd, long int n_lines)
969 if (fstat(fd, &stats)) {
970 detailed_error(0, errno, "%s", filename);
975 if (start_lines(filename, fd, n_lines))
977 dump_remainder(filename, fd);
979 /* Use file_lines only if FD refers to a regular file with
980 its file pointer positioned at beginning of file. */
981 /* FIXME: adding the lseek conjunct is a kludge.
982 Once there's a reasonable test suite, fix the true culprit:
983 file_lines. file_lines shouldn't presume that the input
984 file pointer is initially positioned to beginning of file. */
985 if (S_ISREG(stats.st_mode)
986 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
987 length = lseek(fd, (off_t) 0, SEEK_END);
988 if (length != 0 && file_lines(filename, fd, n_lines, length))
992 return pipe_lines(fd, n_lines);
997 /* Display the last N_UNITS units of file FILENAME, open for reading
999 Return 0 if successful, 1 if an error occurred. */
1001 static int tail(const char *filename, int fd, off_t n_units)
1004 return tail_lines(filename, fd, (long) n_units);
1006 return tail_bytes(filename, fd, n_units);
1009 /* Display the last N_UNITS units of file FILENAME.
1010 "-" for FILENAME means the standard input.
1011 FILENUM is this file's index in the list of files the user gave.
1012 Return 0 if successful, 1 if an error occurred. */
1014 static int tail_file(const char *filename, off_t n_units, int filenum)
1019 if (!strcmp(filename, "-")) {
1020 have_read_stdin = 1;
1021 filename = "standard input";
1023 write_header(filename, NULL);
1024 errors = tail(filename, 0, n_units);
1025 if (forever_multiple) {
1026 if (fstat(0, &stats) < 0) {
1027 detailed_error(0, errno, "standard input");
1029 } else if (!S_ISREG(stats.st_mode)) {
1030 detailed_error(0, 0,
1031 "standard input: cannot follow end of non-regular file");
1035 file_descs[filenum] = -1;
1037 file_descs[filenum] = 0;
1038 file_sizes[filenum] = stats.st_size;
1042 /* Not standard input. */
1043 fd = open(filename, O_RDONLY);
1045 if (forever_multiple)
1046 file_descs[filenum] = -1;
1047 detailed_error(0, errno, "%s", filename);
1051 write_header(filename, NULL);
1052 errors = tail(filename, fd, n_units);
1053 if (forever_multiple) {
1054 if (fstat(fd, &stats) < 0) {
1055 detailed_error(0, errno, "%s", filename);
1057 } else if (!S_ISREG(stats.st_mode)) {
1058 detailed_error(0, 0,
1059 "%s: cannot follow end of non-regular file",
1065 file_descs[filenum] = -1;
1067 file_descs[filenum] = fd;
1068 file_sizes[filenum] = stats.st_size;
1072 detailed_error(0, errno, "%s", filename);
1082 extern int tail_main(int argc, char **argv)
1085 enum header_mode header_mode = multiple_files;
1086 int exit_status = 0;
1088 /* If from_start, the number of items to skip before printing; otherwise,
1089 the number of items at the end of the file to print. Initially, -1
1090 means the value has not been set. */
1095 program_name = argv[0];
1096 have_read_stdin = 0;
1098 forever = forever_multiple = from_start = print_headers = 0;
1100 /* Parse any options */
1101 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1102 while (--argc > 0 && (**(++argv) == '-' || **argv == '+')) {
1103 if (**argv == '+') {
1107 while (stopit == 0 && *(++(*argv))) {
1115 n_units = getNum(*(++argv));
1129 n_units = atol(*(++argv));
1134 header_mode = never;
1138 header_mode = always;
1149 n_units = DEFAULT_N_LINES;
1151 /* To start printing with item N_UNITS from the start of the file, skip
1152 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
1153 compatibility it's treated the same as `tail +1'. */
1162 if (n_files > 1 && forever) {
1163 forever_multiple = 1;
1165 file_descs = (int *) xmalloc(n_files * sizeof(int));
1167 file_sizes = (off_t *) xmalloc(n_files * sizeof(off_t));
1170 if (header_mode == always
1171 || (header_mode == multiple_files && n_files > 1))
1175 exit_status |= tail_file("-", n_units, 0);
1179 for (i = 0; i < n_files; i++)
1180 exit_status |= tail_file(file[i], n_units, i);
1182 if (forever_multiple)
1183 tail_forever(file, n_files);
1186 if (have_read_stdin && close(0) < 0)
1187 detailed_error(EXIT_FAILURE, errno, "-");
1188 if (fclose(stdout) == EOF)
1189 detailed_error(EXIT_FAILURE, errno, "write error");
1190 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);