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(const char *filename, 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(const char *filename, 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(const char *filename, 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(filename, fd, n_lines, length))
317 dump_remainder(filename, fd);
319 return pipe_lines(filename, 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);
339 fatalError("open error");
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 fprintf(stderr, "tail: invalid option -- %c\n", opt);
390 "tail: option -f is invalid with multiple files\n");
397 exit_status |= tail_file("-", n_units);
399 for (; i < argc; i++)
400 exit_status |= tail_file(argv[i], n_units);
403 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
408 // Here follows the code for the full featured tail code
411 /* tail -- output the last part of file(s)
412 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
414 This program is free software; you can redistribute it and/or modify
415 it under the terms of the GNU General Public License as published by
416 the Free Software Foundation; either version 2, or (at your option)
419 This program is distributed in the hope that it will be useful,
420 but WITHOUT ANY WARRANTY; without even the implied warranty of
421 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
422 GNU General Public License for more details.
424 You should have received a copy of the GNU General Public License
425 along with this program; if not, write to the Free Software
426 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
428 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
429 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
430 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
432 Rewrote the option parser, removed locales support,
433 and generally busyboxed, Erik Andersen <andersen@lineo.com>
437 #include "internal.h"
443 #include <sys/types.h>
444 #include <sys/types.h>
445 #include <sys/stat.h>
451 /* Disable assertions. Some systems have broken assert macros. */
455 static void detailed_error(int i, int errnum, char *fmt, ...)
456 __attribute__ ((format (printf, 3, 4)));
457 static void detailed_error(int i, int errnum, char *fmt, ...)
461 va_start(arguments, fmt);
462 vfprintf(stderr, fmt, arguments);
463 fprintf(stderr, "\n%s\n", strerror(errnum));
469 #define XWRITE(fd, buffer, n_bytes) \
472 assert ((fd) == 1); \
473 assert ((n_bytes) >= 0); \
474 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
475 detailed_error (EXIT_FAILURE, errno, "write error"); \
479 /* Number of items to tail. */
480 #define DEFAULT_N_LINES 10
482 /* Size of atomic reads. */
484 #define BUFSIZ (512 * 8)
487 /* If nonzero, interpret the numeric argument as the number of lines.
488 Otherwise, interpret it as the number of bytes. */
489 static int count_lines;
491 /* If nonzero, read from the end of one file until killed. */
494 /* If nonzero, read from the end of multiple files until killed. */
495 static int forever_multiple;
497 /* Array of file descriptors if forever_multiple is 1. */
498 static int *file_descs;
500 /* Array of file sizes if forever_multiple is 1. */
501 static off_t *file_sizes;
503 /* If nonzero, count from start of file instead of end. */
504 static int from_start;
506 /* If nonzero, print filename headers. */
507 static int print_headers;
509 /* When to print the filename banners. */
511 multiple_files, always, never
514 /* The name this program was run with. */
517 /* Nonzero if we have ever read standard input. */
518 static int have_read_stdin;
521 static const char tail_usage[] = "tail [OPTION]... [FILE]...\n"
522 #ifndef BB_FEATURE_TRIVIAL_HELP
523 "\nPrint last 10 lines of each FILE to standard output.\n\
524 With more than one FILE, precede each with a header giving the file name.\n\
525 With no FILE, or when FILE is -, read standard input.\n\
527 -c=N[kbm] output the last N bytes\n\
528 -f output appended data as the file grows\n\
529 -n=N output the last N lines, instead of last 10\n\
530 -q never output headers giving file names\n\
531 -v always output headers giving file names\n\
533 If the first character of N (bytes or lines) is a `+', output begins with \n\
534 the Nth item from the start of each file, otherwise, print the last N items\n\
535 in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n"
539 static void write_header(const char *filename, const char *comment)
541 static int first_file = 1;
543 printf("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
544 (comment ? ": " : ""), (comment ? comment : ""));
548 /* Print the last N_LINES lines from the end of file FD.
549 Go backward through the file, reading `BUFSIZ' bytes at a time (except
550 probably the first), until we hit the start of the file or have
551 read NUMBER newlines.
552 POS starts out as the length of the file (the offset of the last
553 byte of the file + 1).
554 Return 0 if successful, 1 if an error occurred. */
557 file_lines(const char *filename, int fd, long int n_lines, off_t pos)
561 int i; /* Index into `buffer' for scanning. */
566 /* Set `bytes_read' to the size of the last, probably partial, buffer;
567 0 < `bytes_read' <= `BUFSIZ'. */
568 bytes_read = pos % BUFSIZ;
571 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
572 reads will be on block boundaries, which might increase efficiency. */
574 lseek(fd, pos, SEEK_SET);
575 bytes_read = fullRead(fd, buffer, bytes_read);
576 if (bytes_read == -1) {
577 detailed_error(0, errno, "%s", filename);
581 /* Count the incomplete line on files that don't end with a newline. */
582 if (bytes_read && buffer[bytes_read - 1] != '\n')
586 /* Scan backward, counting the newlines in this bufferfull. */
587 for (i = bytes_read - 1; i >= 0; i--) {
588 /* Have we counted the requested number of newlines yet? */
589 if (buffer[i] == '\n' && n_lines-- == 0) {
590 /* If this newline wasn't the last character in the buffer,
591 print the text after it. */
592 if (i != bytes_read - 1)
593 XWRITE(STDOUT_FILENO, &buffer[i + 1],
594 bytes_read - (i + 1));
598 /* Not enough newlines in that bufferfull. */
600 /* Not enough lines in the file; print the entire file. */
601 lseek(fd, (off_t) 0, SEEK_SET);
605 lseek(fd, pos, SEEK_SET);
607 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
608 if (bytes_read == -1) {
609 detailed_error(0, errno, "%s", filename);
615 /* Print the last N_LINES lines from the end of the standard input,
616 open for reading as pipe FD.
617 Buffer the text as a linked list of LBUFFERs, adding them as needed.
618 Return 0 if successful, 1 if an error occured. */
620 static int pipe_lines(const char *filename, int fd, long int n_lines)
625 struct linebuffer *next;
627 typedef struct linebuffer LBUFFER;
628 LBUFFER *first, *last, *tmp;
629 int i; /* Index into buffers. */
630 int total_lines = 0; /* Total number of newlines in all buffers. */
633 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
634 first->nbytes = first->nlines = 0;
636 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
638 /* Input is always read into a fresh buffer. */
639 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
643 /* Count the number of newlines just read. */
644 for (i = 0; i < tmp->nbytes; i++)
645 if (tmp->buffer[i] == '\n')
647 total_lines += tmp->nlines;
649 /* If there is enough room in the last buffer read, just append the new
650 one to it. This is because when reading from a pipe, `nbytes' can
651 often be very small. */
652 if (tmp->nbytes + last->nbytes < BUFSIZ) {
653 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
654 last->nbytes += tmp->nbytes;
655 last->nlines += tmp->nlines;
657 /* If there's not enough room, link the new buffer onto the end of
658 the list, then either free up the oldest buffer for the next
659 read if that would leave enough lines, or else malloc a new one.
660 Some compaction mechanism is possible but probably not
662 last = last->next = tmp;
663 if (total_lines - first->nlines > n_lines) {
665 total_lines -= first->nlines;
668 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
671 if (tmp->nbytes == -1) {
672 detailed_error(0, errno, "%s", filename);
680 /* This prevents a core dump when the pipe contains no newlines. */
684 /* Count the incomplete line on files that don't end with a newline. */
685 if (last->buffer[last->nbytes - 1] != '\n') {
690 /* Run through the list, printing lines. First, skip over unneeded
692 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
693 total_lines -= tmp->nlines;
695 /* Find the correct beginning, then print the rest of the file. */
696 if (total_lines > n_lines) {
699 /* Skip `total_lines' - `n_lines' newlines. We made sure that
700 `total_lines' - `n_lines' <= `tmp->nlines'. */
702 for (i = total_lines - n_lines; i; --i)
703 while (*cp++ != '\n')
705 i = cp - tmp->buffer;
708 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
710 for (tmp = tmp->next; tmp; tmp = tmp->next)
711 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
716 free((char *) first);
722 /* Print the last N_BYTES characters from the end of pipe FD.
723 This is a stripped down version of pipe_lines.
724 Return 0 if successful, 1 if an error occurred. */
726 static int pipe_bytes(const char *filename, int fd, off_t n_bytes)
731 struct charbuffer *next;
733 typedef struct charbuffer CBUFFER;
734 CBUFFER *first, *last, *tmp;
735 int i; /* Index into buffers. */
736 int total_bytes = 0; /* Total characters in all buffers. */
739 first = last = (CBUFFER *) xmalloc(sizeof(CBUFFER));
742 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
744 /* Input is always read into a fresh buffer. */
745 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
748 total_bytes += tmp->nbytes;
749 /* If there is enough room in the last buffer read, just append the new
750 one to it. This is because when reading from a pipe, `nbytes' can
751 often be very small. */
752 if (tmp->nbytes + last->nbytes < BUFSIZ) {
753 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
754 last->nbytes += tmp->nbytes;
756 /* If there's not enough room, link the new buffer onto the end of
757 the list, then either free up the oldest buffer for the next
758 read if that would leave enough characters, or else malloc a new
759 one. Some compaction mechanism is possible but probably not
761 last = last->next = tmp;
762 if (total_bytes - first->nbytes > n_bytes) {
764 total_bytes -= first->nbytes;
767 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
771 if (tmp->nbytes == -1) {
772 detailed_error(0, errno, "%s", filename);
780 /* Run through the list, printing characters. First, skip over unneeded
782 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
783 total_bytes -= tmp->nbytes;
785 /* Find the correct beginning, then print the rest of the file.
786 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
787 if (total_bytes > n_bytes)
788 i = total_bytes - n_bytes;
791 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
793 for (tmp = tmp->next; tmp; tmp = tmp->next)
794 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
799 free((char *) first);
805 /* Skip N_BYTES characters from the start of pipe FD, and print
806 any extra characters that were read beyond that.
807 Return 1 on error, 0 if ok. */
809 static int start_bytes(const char *filename, int fd, off_t n_bytes)
814 while (n_bytes > 0 && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0)
815 n_bytes -= bytes_read;
816 if (bytes_read == -1) {
817 detailed_error(0, errno, "%s", filename);
819 } else if (n_bytes < 0)
820 XWRITE(STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
824 /* Skip N_LINES lines at the start of file or pipe FD, and print
825 any extra characters that were read beyond that.
826 Return 1 on error, 0 if ok. */
828 static int start_lines(const char *filename, int fd, long int n_lines)
832 int bytes_to_skip = 0;
834 while (n_lines && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
836 while (bytes_to_skip < bytes_read)
837 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
840 if (bytes_read == -1) {
841 detailed_error(0, errno, "%s", filename);
843 } else if (bytes_to_skip < bytes_read) {
844 XWRITE(STDOUT_FILENO, &buffer[bytes_to_skip],
845 bytes_read - bytes_to_skip);
850 /* Display file FILENAME from the current position in FD to the end.
851 If `forever' is nonzero, keep reading from the end of the file
852 until killed. Return the number of bytes read from the file. */
854 static long dump_remainder(const char *filename, int fd)
862 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
863 XWRITE(STDOUT_FILENO, buffer, bytes_read);
866 if (bytes_read == -1)
867 detailed_error(EXIT_FAILURE, errno, "%s", filename);
873 if (forever_multiple)
880 /* Tail NFILES (>1) files forever until killed. The file names are in
881 NAMES. The open file descriptors are in `file_descs', and the size
882 at which we stopped tailing them is in `file_sizes'. We loop over
883 each of them, doing an fstat to see if they have changed size. If
884 none of them have changed size in one iteration, we sleep for a
885 second and try again. We do this until the user interrupts us. */
887 static void tail_forever(char **names, int nfiles)
898 for (i = 0; i < nfiles; i++) {
901 if (file_descs[i] < 0)
903 if (fstat(file_descs[i], &stats) < 0) {
904 detailed_error(0, errno, "%s", names[i]);
908 if (stats.st_size == file_sizes[i])
911 /* This file has changed size. Print out what we can, and
912 then keep looping. */
916 if (stats.st_size < file_sizes[i]) {
917 write_header(names[i], "file truncated");
919 lseek(file_descs[i], stats.st_size, SEEK_SET);
920 file_sizes[i] = stats.st_size;
926 write_header(names[i], NULL);
929 file_sizes[i] += dump_remainder(names[i], file_descs[i]);
932 /* If none of the files changed size, sleep. */
938 /* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
939 Return 0 if successful, 1 if an error occurred. */
941 static int tail_bytes(const char *filename, int fd, off_t n_bytes)
945 /* FIXME: resolve this like in dd.c. */
946 /* Use fstat instead of checking for errno == ESPIPE because
947 lseek doesn't work on some special files but doesn't return an
949 if (fstat(fd, &stats)) {
950 detailed_error(0, errno, "%s", filename);
955 if (S_ISREG(stats.st_mode))
956 lseek(fd, n_bytes, SEEK_CUR);
957 else if (start_bytes(filename, fd, n_bytes))
959 dump_remainder(filename, fd);
961 if (S_ISREG(stats.st_mode)) {
962 off_t current_pos, end_pos;
963 size_t bytes_remaining;
965 if ((current_pos = lseek(fd, (off_t) 0, SEEK_CUR)) != -1
966 && (end_pos = lseek(fd, (off_t) 0, SEEK_END)) != -1) {
969 /* Be careful here. The current position may actually be
970 beyond the end of the file. */
971 bytes_remaining = (diff =
972 end_pos - current_pos) < 0 ? 0 : diff;
974 detailed_error(0, errno, "%s", filename);
978 if (bytes_remaining <= n_bytes) {
979 /* From the current position to end of file, there are no
980 more bytes than have been requested. So reposition the
981 file pointer to the incoming current position and print
982 everything after that. */
983 lseek(fd, current_pos, SEEK_SET);
985 /* There are more bytes remaining than were requested.
987 lseek(fd, -n_bytes, SEEK_END);
989 dump_remainder(filename, fd);
991 return pipe_bytes(filename, fd, n_bytes);
996 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
997 Return 0 if successful, 1 if an error occurred. */
999 static int tail_lines(const char *filename, int fd, long int n_lines)
1004 if (fstat(fd, &stats)) {
1005 detailed_error(0, errno, "%s", filename);
1010 if (start_lines(filename, fd, n_lines))
1012 dump_remainder(filename, fd);
1014 /* Use file_lines only if FD refers to a regular file with
1015 its file pointer positioned at beginning of file. */
1016 /* FIXME: adding the lseek conjunct is a kludge.
1017 Once there's a reasonable test suite, fix the true culprit:
1018 file_lines. file_lines shouldn't presume that the input
1019 file pointer is initially positioned to beginning of file. */
1020 if (S_ISREG(stats.st_mode)
1021 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
1022 length = lseek(fd, (off_t) 0, SEEK_END);
1023 if (length != 0 && file_lines(filename, fd, n_lines, length))
1025 dump_remainder(filename, fd);
1027 return pipe_lines(filename, fd, n_lines);
1032 /* Display the last N_UNITS units of file FILENAME, open for reading
1034 Return 0 if successful, 1 if an error occurred. */
1036 static int tail(const char *filename, int fd, off_t n_units)
1039 return tail_lines(filename, fd, (long) n_units);
1041 return tail_bytes(filename, fd, n_units);
1044 /* Display the last N_UNITS units of file FILENAME.
1045 "-" for FILENAME means the standard input.
1046 FILENUM is this file's index in the list of files the user gave.
1047 Return 0 if successful, 1 if an error occurred. */
1049 static int tail_file(const char *filename, off_t n_units, int filenum)
1054 if (!strcmp(filename, "-")) {
1055 have_read_stdin = 1;
1056 filename = "standard input";
1058 write_header(filename, NULL);
1059 errors = tail(filename, 0, n_units);
1060 if (forever_multiple) {
1061 if (fstat(0, &stats) < 0) {
1062 detailed_error(0, errno, "standard input");
1064 } else if (!S_ISREG(stats.st_mode)) {
1065 detailed_error(0, 0,
1066 "standard input: cannot follow end of non-regular file");
1070 file_descs[filenum] = -1;
1072 file_descs[filenum] = 0;
1073 file_sizes[filenum] = stats.st_size;
1077 /* Not standard input. */
1078 fd = open(filename, O_RDONLY);
1080 if (forever_multiple)
1081 file_descs[filenum] = -1;
1082 detailed_error(0, errno, "%s", filename);
1086 write_header(filename, NULL);
1087 errors = tail(filename, fd, n_units);
1088 if (forever_multiple) {
1089 if (fstat(fd, &stats) < 0) {
1090 detailed_error(0, errno, "%s", filename);
1092 } else if (!S_ISREG(stats.st_mode)) {
1093 detailed_error(0, 0,
1094 "%s: cannot follow end of non-regular file",
1100 file_descs[filenum] = -1;
1102 file_descs[filenum] = fd;
1103 file_sizes[filenum] = stats.st_size;
1107 detailed_error(0, errno, "%s", filename);
1117 extern int tail_main(int argc, char **argv)
1120 enum header_mode header_mode = multiple_files;
1121 int exit_status = 0;
1123 /* If from_start, the number of items to skip before printing; otherwise,
1124 the number of items at the end of the file to print. Initially, -1
1125 means the value has not been set. */
1130 program_name = argv[0];
1131 have_read_stdin = 0;
1133 forever = forever_multiple = from_start = print_headers = 0;
1135 /* Parse any options */
1136 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1137 while (--argc > 0 && (**(++argv) == '-' || **argv == '+')) {
1138 if (**argv == '+') {
1142 while (stopit == 0 && *(++(*argv))) {
1150 n_units = getNum(*(++argv));
1164 n_units = atol(*(++argv));
1169 header_mode = never;
1173 header_mode = always;
1184 n_units = DEFAULT_N_LINES;
1186 /* To start printing with item N_UNITS from the start of the file, skip
1187 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
1188 compatibility it's treated the same as `tail +1'. */
1197 if (n_files > 1 && forever) {
1198 forever_multiple = 1;
1200 file_descs = (int *) xmalloc(n_files * sizeof(int));
1202 file_sizes = (off_t *) xmalloc(n_files * sizeof(off_t));
1205 if (header_mode == always
1206 || (header_mode == multiple_files && n_files > 1))
1210 exit_status |= tail_file("-", n_units, 0);
1214 for (i = 0; i < n_files; i++)
1215 exit_status |= tail_file(file[i], n_units, i);
1217 if (forever_multiple)
1218 tail_forever(file, n_files);
1221 if (have_read_stdin && close(0) < 0)
1222 detailed_error(EXIT_FAILURE, errno, "-");
1223 if (fclose(stdout) == EOF)
1224 detailed_error(EXIT_FAILURE, errno, "write error");
1225 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);