2 /* This file contains _two_ implementations of tail. One is
3 * a bit more full featured, but costs 6k. The other (i.e. the
4 * SIMPLE_TAIL one) is less capable, but is good enough for about
5 * 99% of the things folks want to use tail for, and only costs 2k.
9 #ifdef BB_FEATURE_SIMPLE_TAIL
11 /* tail -- output the last part of file(s)
12 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2, or (at your option)
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
29 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
30 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
32 Rewrote the option parser, removed locales support,
33 and generally busyboxed, Erik Andersen <andersen@lineo.com>
35 Removed superfluous options and associated code ("-c", "-n", "-q").
36 Removed "tail -f" support for multiple files.
37 Both changes by Friedrich Vedder <fwv@myrtle.lahn.de>.
44 #include <sys/types.h>
50 #define XWRITE(fd, buffer, n_bytes) \
52 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
53 error("write error"); \
56 /* Number of items to tail. */
57 #define DEFAULT_N_LINES 10
59 /* Size of atomic reads. */
61 #define BUFSIZ (512 * 8)
64 /* If nonzero, read from the end of one file until killed. */
67 /* If nonzero, print filename headers. */
68 static int print_headers;
70 const char tail_usage[] =
71 "tail [OPTION] [FILE]...\n\n"
72 "Print last 10 lines of each FILE to standard output.\n"
73 "With more than one FILE, precede each with a header giving the\n"
74 "file name. With no FILE, or when FILE is -, read standard input.\n\n"
76 "\t-n NUM\t\tPrint last NUM lines instead of first 10\n"
77 "\t-f\t\tOutput data as the file grows. This version\n"
78 "\t\t\tof 'tail -f' supports only one file at a time.\n";
81 static void write_header(const char *filename)
83 static int first_file = 1;
85 printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
89 /* Print the last N_LINES lines from the end of file FD.
90 Go backward through the file, reading `BUFSIZ' bytes at a time (except
91 probably the first), until we hit the start of the file or have
93 POS starts out as the length of the file (the offset of the last
94 byte of the file + 1).
95 Return 0 if successful, 1 if an error occurred. */
98 file_lines(const char *filename, int fd, long int n_lines, off_t pos)
102 int i; /* Index into `buffer' for scanning. */
107 /* Set `bytes_read' to the size of the last, probably partial, buffer;
108 0 < `bytes_read' <= `BUFSIZ'. */
109 bytes_read = pos % BUFSIZ;
112 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
113 reads will be on block boundaries, which might increase efficiency. */
115 lseek(fd, pos, SEEK_SET);
116 bytes_read = fullRead(fd, buffer, bytes_read);
117 if (bytes_read == -1)
120 /* Count the incomplete line on files that don't end with a newline. */
121 if (bytes_read && buffer[bytes_read - 1] != '\n')
125 /* Scan backward, counting the newlines in this bufferfull. */
126 for (i = bytes_read - 1; i >= 0; i--) {
127 /* Have we counted the requested number of newlines yet? */
128 if (buffer[i] == '\n' && n_lines-- == 0) {
129 /* If this newline wasn't the last character in the buffer,
130 print the text after it. */
131 if (i != bytes_read - 1)
132 XWRITE(STDOUT_FILENO, &buffer[i + 1],
133 bytes_read - (i + 1));
137 /* Not enough newlines in that bufferfull. */
139 /* Not enough lines in the file; print the entire file. */
140 lseek(fd, (off_t) 0, SEEK_SET);
144 lseek(fd, pos, SEEK_SET);
146 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
147 if (bytes_read == -1)
153 /* Print the last N_LINES lines from the end of the standard input,
154 open for reading as pipe FD.
155 Buffer the text as a linked list of LBUFFERs, adding them as needed.
156 Return 0 if successful, 1 if an error occured. */
158 static int pipe_lines(const char *filename, int fd, long int n_lines)
163 struct linebuffer *next;
165 typedef struct linebuffer LBUFFER;
166 LBUFFER *first, *last, *tmp;
167 int i; /* Index into buffers. */
168 int total_lines = 0; /* Total number of newlines in all buffers. */
171 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
172 first->nbytes = first->nlines = 0;
174 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
176 /* Input is always read into a fresh buffer. */
177 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
181 /* Count the number of newlines just read. */
182 for (i = 0; i < tmp->nbytes; i++)
183 if (tmp->buffer[i] == '\n')
185 total_lines += tmp->nlines;
187 /* If there is enough room in the last buffer read, just append the new
188 one to it. This is because when reading from a pipe, `nbytes' can
189 often be very small. */
190 if (tmp->nbytes + last->nbytes < BUFSIZ) {
191 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
192 last->nbytes += tmp->nbytes;
193 last->nlines += tmp->nlines;
195 /* If there's not enough room, link the new buffer onto the end of
196 the list, then either free up the oldest buffer for the next
197 read if that would leave enough lines, or else malloc a new one.
198 Some compaction mechanism is possible but probably not
200 last = last->next = tmp;
201 if (total_lines - first->nlines > n_lines) {
203 total_lines -= first->nlines;
206 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
209 if (tmp->nbytes == -1)
214 /* This prevents a core dump when the pipe contains no newlines. */
218 /* Count the incomplete line on files that don't end with a newline. */
219 if (last->buffer[last->nbytes - 1] != '\n') {
224 /* Run through the list, printing lines. First, skip over unneeded
226 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
227 total_lines -= tmp->nlines;
229 /* Find the correct beginning, then print the rest of the file. */
230 if (total_lines > n_lines) {
233 /* Skip `total_lines' - `n_lines' newlines. We made sure that
234 `total_lines' - `n_lines' <= `tmp->nlines'. */
236 for (i = total_lines - n_lines; i; --i)
237 while (*cp++ != '\n')
239 i = cp - tmp->buffer;
242 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
244 for (tmp = tmp->next; tmp; tmp = tmp->next)
245 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
250 free((char *) first);
256 /* Display file FILENAME from the current position in FD to the end.
257 If `forever' is nonzero, keep reading from the end of the file
258 until killed. Return the number of bytes read from the file. */
260 static long dump_remainder(const char *filename, int fd)
268 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
269 XWRITE(STDOUT_FILENO, buffer, bytes_read);
272 if (bytes_read == -1)
283 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
284 Return 0 if successful, 1 if an error occurred. */
286 static int tail_lines(const char *filename, int fd, long int n_lines)
292 write_header(filename);
294 if (fstat(fd, &stats))
295 error("fstat error");
297 /* Use file_lines only if FD refers to a regular file with
298 its file pointer positioned at beginning of file. */
299 /* FIXME: adding the lseek conjunct is a kludge.
300 Once there's a reasonable test suite, fix the true culprit:
301 file_lines. file_lines shouldn't presume that the input
302 file pointer is initially positioned to beginning of file. */
303 if (S_ISREG(stats.st_mode)
304 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
305 length = lseek(fd, (off_t) 0, SEEK_END);
306 if (length != 0 && file_lines(filename, fd, n_lines, length))
308 dump_remainder(filename, fd);
310 return pipe_lines(filename, fd, n_lines);
315 /* Display the last N_UNITS lines of file FILENAME.
316 "-" for FILENAME means the standard input.
317 Return 0 if successful, 1 if an error occurred. */
319 static int tail_file(const char *filename, off_t n_units)
323 if (!strcmp(filename, "-")) {
324 filename = "standard input";
325 errors = tail_lines(filename, 0, (long) n_units);
327 /* Not standard input. */
328 fd = open(filename, O_RDONLY);
332 errors = tail_lines(filename, fd, (long) n_units);
339 extern int tail_main(int argc, char **argv)
342 int n_units = DEFAULT_N_LINES;
346 forever = print_headers = 0;
349 for (i = 1; i < argc; i++) {
350 if (argv[i][0] == '-') {
359 n_tmp = atoi(argv[i]);
368 fprintf(stderr, "tail: invalid option -- %c\n", opt);
379 "tail: option -f is invalid with multiple files\n");
386 exit_status |= tail_file("-", n_units);
388 for (; i < argc; i++)
389 exit_status |= tail_file(argv[i], n_units);
392 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
397 // Here follows the code for the full featured tail code
400 /* tail -- output the last part of file(s)
401 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
403 This program is free software; you can redistribute it and/or modify
404 it under the terms of the GNU General Public License as published by
405 the Free Software Foundation; either version 2, or (at your option)
408 This program is distributed in the hope that it will be useful,
409 but WITHOUT ANY WARRANTY; without even the implied warranty of
410 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
411 GNU General Public License for more details.
413 You should have received a copy of the GNU General Public License
414 along with this program; if not, write to the Free Software
415 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
417 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
418 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
419 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
421 Rewrote the option parser, removed locales support,
422 and generally busyboxed, Erik Andersen <andersen@lineo.com>
426 #include "internal.h"
432 #include <sys/types.h>
433 #include <sys/types.h>
434 #include <sys/stat.h>
440 /* Disable assertions. Some systems have broken assert macros. */
444 static void detailed_error(int i, int errnum, char* fmt, ...)
448 va_start(arguments, fmt);
449 vfprintf(stderr, fmt, arguments);
450 fprintf(stderr, "\n%s\n", strerror( errnum));
456 #define XWRITE(fd, buffer, n_bytes) \
459 assert ((fd) == 1); \
460 assert ((n_bytes) >= 0); \
461 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
462 detailed_error (EXIT_FAILURE, errno, "write error"); \
466 /* Number of items to tail. */
467 #define DEFAULT_N_LINES 10
469 /* Size of atomic reads. */
471 #define BUFSIZ (512 * 8)
474 /* If nonzero, interpret the numeric argument as the number of lines.
475 Otherwise, interpret it as the number of bytes. */
476 static int count_lines;
478 /* If nonzero, read from the end of one file until killed. */
481 /* If nonzero, read from the end of multiple files until killed. */
482 static int forever_multiple;
484 /* Array of file descriptors if forever_multiple is 1. */
485 static int *file_descs;
487 /* Array of file sizes if forever_multiple is 1. */
488 static off_t *file_sizes;
490 /* If nonzero, count from start of file instead of end. */
491 static int from_start;
493 /* If nonzero, print filename headers. */
494 static int print_headers;
496 /* When to print the filename banners. */
499 multiple_files, always, never
502 /* The name this program was run with. */
505 /* Nonzero if we have ever read standard input. */
506 static int have_read_stdin;
509 static const char tail_usage[] =
510 "tail [OPTION]... [FILE]...\n\
512 Print last 10 lines of each FILE to standard output.\n\
513 With more than one FILE, precede each with a header giving the file name.\n\
514 With no FILE, or when FILE is -, read standard input.\n\
516 -c=N[kbm] output the last N bytes\n\
517 -f output appended data as the file grows\n\
518 -n=N output the last N lines, instead of last 10\n\
519 -q never output headers giving file names\n\
520 -v always output headers giving file names\n\
521 --help display this help and exit\n\
523 If the first character of N (bytes or lines) is a `+', output begins with \n\
524 the Nth item from the start of each file, otherwise, print the last N items\n\
525 in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n";
528 write_header (const char *filename, const char *comment)
530 static int first_file = 1;
532 printf ("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
533 (comment ? ": " : ""),
534 (comment ? comment : ""));
538 /* Print the last N_LINES lines from the end of file FD.
539 Go backward through the file, reading `BUFSIZ' bytes at a time (except
540 probably the first), until we hit the start of the file or have
541 read NUMBER newlines.
542 POS starts out as the length of the file (the offset of the last
543 byte of the file + 1).
544 Return 0 if successful, 1 if an error occurred. */
547 file_lines (const char *filename, int fd, long int n_lines, off_t pos)
551 int i; /* Index into `buffer' for scanning. */
556 /* Set `bytes_read' to the size of the last, probably partial, buffer;
557 0 < `bytes_read' <= `BUFSIZ'. */
558 bytes_read = pos % BUFSIZ;
561 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
562 reads will be on block boundaries, which might increase efficiency. */
564 lseek (fd, pos, SEEK_SET);
565 bytes_read = fullRead (fd, buffer, bytes_read);
566 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')
578 /* Scan backward, counting the newlines in this bufferfull. */
579 for (i = bytes_read - 1; i >= 0; i--)
581 /* Have we counted the requested number of newlines yet? */
582 if (buffer[i] == '\n' && n_lines-- == 0)
584 /* If this newline wasn't the last character in the buffer,
585 print the text after it. */
586 if (i != bytes_read - 1)
587 XWRITE (STDOUT_FILENO, &buffer[i + 1], bytes_read - (i + 1));
591 /* Not enough newlines in that bufferfull. */
594 /* Not enough lines in the file; print the entire file. */
595 lseek (fd, (off_t) 0, SEEK_SET);
599 lseek (fd, pos, SEEK_SET);
601 while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0);
602 if (bytes_read == -1)
604 detailed_error (0, errno, "%s", filename);
610 /* Print the last N_LINES lines from the end of the standard input,
611 open for reading as pipe FD.
612 Buffer the text as a linked list of LBUFFERs, adding them as needed.
613 Return 0 if successful, 1 if an error occured. */
616 pipe_lines (const char *filename, int fd, long int n_lines)
622 struct linebuffer *next;
624 typedef struct linebuffer LBUFFER;
625 LBUFFER *first, *last, *tmp;
626 int i; /* Index into buffers. */
627 int total_lines = 0; /* Total number of newlines in all buffers. */
630 first = last = (LBUFFER *) xmalloc (sizeof (LBUFFER));
631 first->nbytes = first->nlines = 0;
633 tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
635 /* Input is always read into a fresh buffer. */
636 while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
641 /* Count the number of newlines just read. */
642 for (i = 0; i < tmp->nbytes; i++)
643 if (tmp->buffer[i] == '\n')
645 total_lines += tmp->nlines;
647 /* If there is enough room in the last buffer read, just append the new
648 one to it. This is because when reading from a pipe, `nbytes' can
649 often be very small. */
650 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;
658 /* If there's not enough room, link the new buffer onto the end of
659 the list, then either free up the oldest buffer for the next
660 read if that would leave enough lines, or else malloc a new one.
661 Some compaction mechanism is possible but probably not
663 last = last->next = tmp;
664 if (total_lines - first->nlines > n_lines)
667 total_lines -= first->nlines;
671 tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
674 if (tmp->nbytes == -1)
676 detailed_error (0, errno, "%s", filename);
684 /* This prevents a core dump when the pipe contains no newlines. */
688 /* Count the incomplete line on files that don't end with a newline. */
689 if (last->buffer[last->nbytes - 1] != '\n')
695 /* Run through the list, printing lines. First, skip over unneeded
697 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
698 total_lines -= tmp->nlines;
700 /* Find the correct beginning, then print the rest of the file. */
701 if (total_lines > n_lines)
705 /* Skip `total_lines' - `n_lines' newlines. We made sure that
706 `total_lines' - `n_lines' <= `tmp->nlines'. */
708 for (i = total_lines - n_lines; i; --i)
709 while (*cp++ != '\n')
711 i = cp - tmp->buffer;
715 XWRITE (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
717 for (tmp = tmp->next; tmp; tmp = tmp->next)
718 XWRITE (STDOUT_FILENO, tmp->buffer, tmp->nbytes);
724 free ((char *) first);
730 /* Print the last N_BYTES characters from the end of pipe FD.
731 This is a stripped down version of pipe_lines.
732 Return 0 if successful, 1 if an error occurred. */
735 pipe_bytes (const char *filename, int fd, off_t n_bytes)
741 struct charbuffer *next;
743 typedef struct charbuffer CBUFFER;
744 CBUFFER *first, *last, *tmp;
745 int i; /* Index into buffers. */
746 int total_bytes = 0; /* Total characters in all buffers. */
749 first = last = (CBUFFER *) xmalloc (sizeof (CBUFFER));
752 tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
754 /* Input is always read into a fresh buffer. */
755 while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
759 total_bytes += tmp->nbytes;
760 /* If there is enough room in the last buffer read, just append the new
761 one to it. This is because when reading from a pipe, `nbytes' can
762 often be very small. */
763 if (tmp->nbytes + last->nbytes < BUFSIZ)
765 memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
766 last->nbytes += tmp->nbytes;
770 /* If there's not enough room, link the new buffer onto the end of
771 the list, then either free up the oldest buffer for the next
772 read if that would leave enough characters, or else malloc a new
773 one. Some compaction mechanism is possible but probably not
775 last = last->next = tmp;
776 if (total_bytes - first->nbytes > n_bytes)
779 total_bytes -= first->nbytes;
784 tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
788 if (tmp->nbytes == -1)
790 detailed_error (0, errno, "%s", filename);
798 /* Run through the list, printing characters. First, skip over unneeded
800 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
801 total_bytes -= tmp->nbytes;
803 /* Find the correct beginning, then print the rest of the file.
804 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
805 if (total_bytes > n_bytes)
806 i = total_bytes - n_bytes;
809 XWRITE (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
811 for (tmp = tmp->next; tmp; tmp = tmp->next)
812 XWRITE (STDOUT_FILENO, tmp->buffer, tmp->nbytes);
818 free ((char *) first);
824 /* Skip N_BYTES characters from the start of pipe FD, and print
825 any extra characters that were read beyond that.
826 Return 1 on error, 0 if ok. */
829 start_bytes (const char *filename, int fd, off_t n_bytes)
834 while (n_bytes > 0 && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
835 n_bytes -= bytes_read;
836 if (bytes_read == -1)
838 detailed_error (0, errno, "%s", filename);
841 else if (n_bytes < 0)
842 XWRITE (STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
846 /* Skip N_LINES lines at the start of file or pipe FD, and print
847 any extra characters that were read beyond that.
848 Return 1 on error, 0 if ok. */
851 start_lines (const char *filename, int fd, long int n_lines)
855 int bytes_to_skip = 0;
857 while (n_lines && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
860 while (bytes_to_skip < bytes_read)
861 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
864 if (bytes_read == -1)
866 detailed_error (0, errno, "%s", filename);
869 else if (bytes_to_skip < bytes_read)
871 XWRITE (STDOUT_FILENO, &buffer[bytes_to_skip],
872 bytes_read - bytes_to_skip);
877 /* Display file FILENAME from the current position in FD to the end.
878 If `forever' is nonzero, keep reading from the end of the file
879 until killed. Return the number of bytes read from the file. */
882 dump_remainder (const char *filename, int fd)
890 while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
892 XWRITE (STDOUT_FILENO, buffer, bytes_read);
895 if (bytes_read == -1)
896 detailed_error (EXIT_FAILURE, errno, "%s", filename);
905 if (forever_multiple)
912 /* Tail NFILES (>1) files forever until killed. The file names are in
913 NAMES. The open file descriptors are in `file_descs', and the size
914 at which we stopped tailing them is in `file_sizes'. We loop over
915 each of them, doing an fstat to see if they have changed size. If
916 none of them have changed size in one iteration, we sleep for a
917 second and try again. We do this until the user interrupts us. */
920 tail_forever (char **names, int nfiles)
932 for (i = 0; i < nfiles; i++)
936 if (file_descs[i] < 0)
938 if (fstat (file_descs[i], &stats) < 0)
940 detailed_error (0, errno, "%s", names[i]);
944 if (stats.st_size == file_sizes[i])
947 /* This file has changed size. Print out what we can, and
948 then keep looping. */
952 if (stats.st_size < file_sizes[i])
954 write_header (names[i], "file truncated");
956 lseek (file_descs[i], stats.st_size, SEEK_SET);
957 file_sizes[i] = stats.st_size;
964 write_header (names[i], NULL);
967 file_sizes[i] += dump_remainder (names[i], file_descs[i]);
970 /* If none of the files changed size, sleep. */
976 /* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
977 Return 0 if successful, 1 if an error occurred. */
980 tail_bytes (const char *filename, int fd, off_t n_bytes)
984 /* FIXME: resolve this like in dd.c. */
985 /* Use fstat instead of checking for errno == ESPIPE because
986 lseek doesn't work on some special files but doesn't return an
988 if (fstat (fd, &stats))
990 detailed_error (0, errno, "%s", filename);
996 if (S_ISREG (stats.st_mode))
997 lseek (fd, n_bytes, SEEK_CUR);
998 else if (start_bytes (filename, fd, n_bytes))
1000 dump_remainder (filename, fd);
1004 if (S_ISREG (stats.st_mode))
1006 off_t current_pos, end_pos;
1007 size_t bytes_remaining;
1009 if ((current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
1010 && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
1013 /* Be careful here. The current position may actually be
1014 beyond the end of the file. */
1015 bytes_remaining = (diff = end_pos - current_pos) < 0 ? 0 : diff;
1019 detailed_error (0, errno, "%s", filename);
1023 if (bytes_remaining <= n_bytes)
1025 /* From the current position to end of file, there are no
1026 more bytes than have been requested. So reposition the
1027 file pointer to the incoming current position and print
1028 everything after that. */
1029 lseek (fd, current_pos, SEEK_SET);
1033 /* There are more bytes remaining than were requested.
1035 lseek (fd, -n_bytes, SEEK_END);
1037 dump_remainder (filename, fd);
1040 return pipe_bytes (filename, fd, n_bytes);
1045 /* Output the last N_LINES lines of file FILENAME open for reading in FD.
1046 Return 0 if successful, 1 if an error occurred. */
1049 tail_lines (const char *filename, int fd, long int n_lines)
1054 if (fstat (fd, &stats))
1056 detailed_error (0, errno, "%s", filename);
1062 if (start_lines (filename, fd, n_lines))
1064 dump_remainder (filename, fd);
1068 /* Use file_lines only if FD refers to a regular file with
1069 its file pointer positioned at beginning of file. */
1070 /* FIXME: adding the lseek conjunct is a kludge.
1071 Once there's a reasonable test suite, fix the true culprit:
1072 file_lines. file_lines shouldn't presume that the input
1073 file pointer is initially positioned to beginning of file. */
1074 if (S_ISREG (stats.st_mode)
1075 && lseek (fd, (off_t) 0, SEEK_CUR) == (off_t) 0)
1077 length = lseek (fd, (off_t) 0, SEEK_END);
1078 if (length != 0 && file_lines (filename, fd, n_lines, length))
1080 dump_remainder (filename, fd);
1083 return pipe_lines (filename, fd, n_lines);
1088 /* Display the last N_UNITS units of file FILENAME, open for reading
1090 Return 0 if successful, 1 if an error occurred. */
1093 tail (const char *filename, int fd, off_t n_units)
1096 return tail_lines (filename, fd, (long) n_units);
1098 return tail_bytes (filename, fd, n_units);
1101 /* Display the last N_UNITS units of file FILENAME.
1102 "-" for FILENAME means the standard input.
1103 FILENUM is this file's index in the list of files the user gave.
1104 Return 0 if successful, 1 if an error occurred. */
1107 tail_file (const char *filename, off_t n_units, int filenum)
1112 if (!strcmp (filename, "-"))
1114 have_read_stdin = 1;
1115 filename = "standard input";
1117 write_header (filename, NULL);
1118 errors = tail (filename, 0, n_units);
1119 if (forever_multiple)
1121 if (fstat (0, &stats) < 0)
1123 detailed_error (0, errno, "standard input");
1126 else if (!S_ISREG (stats.st_mode))
1128 detailed_error (0, 0,
1129 "standard input: cannot follow end of non-regular file");
1133 file_descs[filenum] = -1;
1136 file_descs[filenum] = 0;
1137 file_sizes[filenum] = stats.st_size;
1143 /* Not standard input. */
1144 fd = open (filename, O_RDONLY);
1147 if (forever_multiple)
1148 file_descs[filenum] = -1;
1149 detailed_error (0, errno, "%s", filename);
1155 write_header (filename, NULL);
1156 errors = tail (filename, fd, n_units);
1157 if (forever_multiple)
1159 if (fstat (fd, &stats) < 0)
1161 detailed_error (0, errno, "%s", filename);
1164 else if (!S_ISREG (stats.st_mode))
1166 detailed_error (0, 0, "%s: cannot follow end of non-regular file",
1173 file_descs[filenum] = -1;
1177 file_descs[filenum] = fd;
1178 file_sizes[filenum] = stats.st_size;
1185 detailed_error (0, errno, "%s", filename);
1196 tail_main (int argc, char **argv)
1199 enum header_mode header_mode = multiple_files;
1200 int exit_status = 0;
1201 /* If from_start, the number of items to skip before printing; otherwise,
1202 the number of items at the end of the file to print. Initially, -1
1203 means the value has not been set. */
1208 program_name = argv[0];
1209 have_read_stdin = 0;
1211 forever = forever_multiple = from_start = print_headers = 0;
1213 /* Parse any options */
1214 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1215 while (--argc > 0 && ( **(++argv) == '-' || **argv == '+' )) {
1216 if (**argv == '+') {
1220 while (stopit == 0 && *(++(*argv))) {
1228 n_units = getNum(*(++argv));
1242 n_units = atol(*(++argv));
1247 header_mode = never;
1251 header_mode = always;
1262 n_units = DEFAULT_N_LINES;
1264 /* To start printing with item N_UNITS from the start of the file, skip
1265 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
1266 compatibility it's treated the same as `tail +1'. */
1276 if (n_files > 1 && forever)
1278 forever_multiple = 1;
1280 file_descs = (int *) xmalloc (n_files * sizeof (int));
1281 file_sizes = (off_t *) xmalloc (n_files * sizeof (off_t));
1284 if (header_mode == always
1285 || (header_mode == multiple_files && n_files > 1))
1290 exit_status |= tail_file ("-", n_units, 0);
1295 for (i = 0; i < n_files; i++)
1296 exit_status |= tail_file (file[i], n_units, i);
1298 if (forever_multiple)
1299 tail_forever (file, n_files);
1302 if (have_read_stdin && close (0) < 0)
1303 detailed_error (EXIT_FAILURE, errno, "-");
1304 if (fclose (stdout) == EOF)
1305 detailed_error (EXIT_FAILURE, errno, "write error");
1306 exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);