blob: 3b3e2f56c10a7a311cb03a56492b802bd2ed5fdf [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Erik Andersen3fe39dc2000-01-25 18:13:53 +00002#include "internal.h"
Erik Andersen9ffdaa62000-02-11 21:55:04 +00003
Erik Andersen3fe39dc2000-01-25 18:13:53 +00004/* 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.
8 */
9
10
11#ifdef BB_FEATURE_SIMPLE_TAIL
12
13/* tail -- output the last part of file(s)
14 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
15
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)
19 any later version.
20
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.
25
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.
29
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>.
33
34 Rewrote the option parser, removed locales support,
35 and generally busyboxed, Erik Andersen <andersen@lineo.com>
36
37 Removed superfluous options and associated code ("-c", "-n", "-q").
Erik Andersenfac10d72000-02-07 05:29:42 +000038 Removed "tail -f" support for multiple files.
Erik Andersen3fe39dc2000-01-25 18:13:53 +000039 Both changes by Friedrich Vedder <fwv@myrtle.lahn.de>.
40
41 */
42
43
44#include <stdio.h>
45#include <stdarg.h>
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49#include <ctype.h>
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000050#define BB_DECLARE_EXTERN
51#define bb_need_help
52#include "messages.c"
Erik Andersen3fe39dc2000-01-25 18:13:53 +000053
54
55#define XWRITE(fd, buffer, n_bytes) \
56 do { \
57 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
Erik Andersen9ffdaa62000-02-11 21:55:04 +000058 errorMsg("write error"); \
Erik Andersen3fe39dc2000-01-25 18:13:53 +000059 } while (0)
60
61/* Number of items to tail. */
62#define DEFAULT_N_LINES 10
63
64/* Size of atomic reads. */
65#ifndef BUFSIZ
66#define BUFSIZ (512 * 8)
67#endif
68
69/* If nonzero, read from the end of one file until killed. */
70static int forever;
71
72/* If nonzero, print filename headers. */
73static int print_headers;
74
75const char tail_usage[] =
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000076 "tail [OPTION] [FILE]...\n"
77#ifndef BB_FEATURE_TRIVIAL_HELP
78 "\nPrint last 10 lines of each FILE to standard output.\n"
Erik Andersene49d5ec2000-02-08 19:58:47 +000079 "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"
81 "Options:\n"
82 "\t-n NUM\t\tPrint last NUM lines instead of first 10\n"
83
84 "\t-f\t\tOutput data as the file grows. This version\n"
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000085 "\t\t\tof 'tail -f' supports only one file at a time.\n"
86#endif
87 ;
Erik Andersen3fe39dc2000-01-25 18:13:53 +000088
89
90static void write_header(const char *filename)
91{
Erik Andersene49d5ec2000-02-08 19:58:47 +000092 static int first_file = 1;
Erik Andersen3fe39dc2000-01-25 18:13:53 +000093
Erik Andersene49d5ec2000-02-08 19:58:47 +000094 printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
95 first_file = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +000096}
97
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. */
105
106static int
107file_lines(const char *filename, int fd, long int n_lines, off_t pos)
108{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000109 char buffer[BUFSIZ];
110 int bytes_read;
111 int i; /* Index into `buffer' for scanning. */
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000112
Erik Andersene49d5ec2000-02-08 19:58:47 +0000113 if (n_lines == 0)
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000114 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000115
Erik Andersene49d5ec2000-02-08 19:58:47 +0000116 /* Set `bytes_read' to the size of the last, probably partial, buffer;
117 0 < `bytes_read' <= `BUFSIZ'. */
118 bytes_read = pos % BUFSIZ;
119 if (bytes_read == 0)
120 bytes_read = 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. */
123 pos -= bytes_read;
124 lseek(fd, pos, SEEK_SET);
125 bytes_read = fullRead(fd, buffer, bytes_read);
126 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000127 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128
129 /* Count the incomplete line on files that don't end with a newline. */
130 if (bytes_read && buffer[bytes_read - 1] != '\n')
131 --n_lines;
132
133 do {
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));
143 return 0;
144 }
145 }
146 /* Not enough newlines in that bufferfull. */
147 if (pos == 0) {
148 /* Not enough lines in the file; print the entire file. */
149 lseek(fd, (off_t) 0, SEEK_SET);
150 return 0;
151 }
152 pos -= BUFSIZ;
153 lseek(fd, pos, SEEK_SET);
154 }
155 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
156 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000157 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000158
159 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000160}
161
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. */
166
167static int pipe_lines(const char *filename, int fd, long int n_lines)
168{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000169 struct linebuffer {
170 int nbytes, nlines;
171 char buffer[BUFSIZ];
172 struct linebuffer *next;
173 };
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. */
178 int errors = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000179
Erik Andersene49d5ec2000-02-08 19:58:47 +0000180 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
181 first->nbytes = first->nlines = 0;
182 first->next = NULL;
183 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000184
Erik Andersene49d5ec2000-02-08 19:58:47 +0000185 /* Input is always read into a fresh buffer. */
186 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
187 tmp->nlines = 0;
188 tmp->next = NULL;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000189
Erik Andersene49d5ec2000-02-08 19:58:47 +0000190 /* Count the number of newlines just read. */
191 for (i = 0; i < tmp->nbytes; i++)
192 if (tmp->buffer[i] == '\n')
193 ++tmp->nlines;
194 total_lines += tmp->nlines;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000195
Erik Andersene49d5ec2000-02-08 19:58:47 +0000196 /* 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;
203 } else {
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
208 worthwhile. */
209 last = last->next = tmp;
210 if (total_lines - first->nlines > n_lines) {
211 tmp = first;
212 total_lines -= first->nlines;
213 first = first->next;
214 } else
215 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
216 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000217 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000218 if (tmp->nbytes == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000219 errorMsg("read error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000220
Erik Andersene49d5ec2000-02-08 19:58:47 +0000221 free((char *) tmp);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000222
Erik Andersene49d5ec2000-02-08 19:58:47 +0000223 /* This prevents a core dump when the pipe contains no newlines. */
224 if (n_lines == 0)
225 goto free_lbuffers;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000226
Erik Andersene49d5ec2000-02-08 19:58:47 +0000227 /* Count the incomplete line on files that don't end with a newline. */
228 if (last->buffer[last->nbytes - 1] != '\n') {
229 ++last->nlines;
230 ++total_lines;
231 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000232
Erik Andersene49d5ec2000-02-08 19:58:47 +0000233 /* Run through the list, printing lines. First, skip over unneeded
234 buffers. */
235 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
236 total_lines -= tmp->nlines;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000237
Erik Andersene49d5ec2000-02-08 19:58:47 +0000238 /* Find the correct beginning, then print the rest of the file. */
239 if (total_lines > n_lines) {
240 char *cp;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000241
Erik Andersene49d5ec2000-02-08 19:58:47 +0000242 /* Skip `total_lines' - `n_lines' newlines. We made sure that
243 `total_lines' - `n_lines' <= `tmp->nlines'. */
244 cp = tmp->buffer;
245 for (i = total_lines - n_lines; i; --i)
246 while (*cp++ != '\n')
247 /* Do nothing. */ ;
248 i = cp - tmp->buffer;
249 } else
250 i = 0;
251 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000252
Erik Andersene49d5ec2000-02-08 19:58:47 +0000253 for (tmp = tmp->next; tmp; tmp = tmp->next)
254 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000255
256 free_lbuffers:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000257 while (first) {
258 tmp = first->next;
259 free((char *) first);
260 first = tmp;
261 }
262 return errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000263}
264
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. */
268
269static long dump_remainder(const char *filename, int fd)
270{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000271 char buffer[BUFSIZ];
272 int bytes_read;
273 long total;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000274
Erik Andersene49d5ec2000-02-08 19:58:47 +0000275 total = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000276 output:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000277 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
278 XWRITE(STDOUT_FILENO, buffer, bytes_read);
279 total += bytes_read;
280 }
281 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000282 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000283 if (forever) {
284 fflush(stdout);
285 sleep(1);
286 goto output;
287 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000288
Erik Andersene49d5ec2000-02-08 19:58:47 +0000289 return total;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000290}
291
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. */
294
295static int tail_lines(const char *filename, int fd, long int n_lines)
296{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000297 struct stat stats;
298 off_t length;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000299
Erik Andersene49d5ec2000-02-08 19:58:47 +0000300 if (print_headers)
301 write_header(filename);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000302
Erik Andersene49d5ec2000-02-08 19:58:47 +0000303 if (fstat(fd, &stats))
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000304 errorMsg("fstat error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000305
Erik Andersene49d5ec2000-02-08 19:58:47 +0000306 /* 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))
316 return 1;
317 dump_remainder(filename, fd);
318 } else
319 return pipe_lines(filename, fd, n_lines);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000320
Erik Andersene49d5ec2000-02-08 19:58:47 +0000321 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000322}
323
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. */
327
328static int tail_file(const char *filename, off_t n_units)
329{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000330 int fd, errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000331
Erik Andersene49d5ec2000-02-08 19:58:47 +0000332 if (!strcmp(filename, "-")) {
333 filename = "standard input";
334 errors = tail_lines(filename, 0, (long) n_units);
335 } else {
336 /* Not standard input. */
337 fd = open(filename, O_RDONLY);
338 if (fd == -1)
Erik Andersene2729152000-02-18 21:34:17 +0000339 fatalError("open error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000340
Erik Andersene49d5ec2000-02-08 19:58:47 +0000341 errors = tail_lines(filename, fd, (long) n_units);
342 close(fd);
343 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000344
Erik Andersene49d5ec2000-02-08 19:58:47 +0000345 return errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000346}
347
348extern int tail_main(int argc, char **argv)
349{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000350 int exit_status = 0;
351 int n_units = DEFAULT_N_LINES;
352 int n_tmp, i;
353 char opt;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000354
Erik Andersene49d5ec2000-02-08 19:58:47 +0000355 forever = print_headers = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000356
Erik Andersene49d5ec2000-02-08 19:58:47 +0000357 /* parse argv[] */
358 for (i = 1; i < argc; i++) {
359 if (argv[i][0] == '-') {
360 opt = argv[i][1];
361 switch (opt) {
362 case 'f':
363 forever = 1;
364 break;
365 case 'n':
366 n_tmp = 0;
367 if (++i < argc)
368 n_tmp = atoi(argv[i]);
369 if (n_tmp < 1)
370 usage(tail_usage);
371 n_units = n_tmp;
372 break;
373 case '-':
374 case 'h':
375 usage(tail_usage);
376 default:
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000377 if ((n_units = atoi(&argv[i][1])) < 1) {
378 fprintf(stderr, "tail: invalid option -- %c\n", opt);
379 usage(tail_usage);
380 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000381 }
382 } else {
383 break;
384 }
385 }
386
387 if (i + 1 < argc) {
388 if (forever) {
389 fprintf(stderr,
390 "tail: option -f is invalid with multiple files\n");
391 usage(tail_usage);
392 }
393 print_headers = 1;
394 }
395
396 if (i >= argc) {
397 exit_status |= tail_file("-", n_units);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000398 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000399 for (; i < argc; i++)
400 exit_status |= tail_file(argv[i], n_units);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000401 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000402
Erik Andersene49d5ec2000-02-08 19:58:47 +0000403 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000404}
405
406
407#else
408// Here follows the code for the full featured tail code
409
410
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000411/* tail -- output the last part of file(s)
412 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
413
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)
417 any later version.
418
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.
423
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
Eric Andersen1792f8c1999-12-09 06:11:36 +0000426 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000427
428 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
429 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
Eric Andersen1792f8c1999-12-09 06:11:36 +0000430 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
431
432 Rewrote the option parser, removed locales support,
433 and generally busyboxed, Erik Andersen <andersen@lineo.com>
434
435 */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000436
437#include "internal.h"
438
439#include <stdio.h>
Erik Andersen4d1d0111999-12-17 18:44:15 +0000440#include <stdarg.h>
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000441#include <assert.h>
442#include <errno.h>
443#include <sys/types.h>
Eric Andersen1792f8c1999-12-09 06:11:36 +0000444#include <sys/types.h>
445#include <sys/stat.h>
446#include <fcntl.h>
447#include <ctype.h>
448
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000449
450
451/* Disable assertions. Some systems have broken assert macros. */
452#define NDEBUG 1
453
454
Erik Andersene49d5ec2000-02-08 19:58:47 +0000455static void detailed_error(int i, int errnum, char *fmt, ...)
Erik Andersen93d65132000-04-06 08:06:36 +0000456 __attribute__ ((format (printf, 3, 4)));
457static void detailed_error(int i, int errnum, char *fmt, ...)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000458{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000459 va_list arguments;
Eric Andersen1792f8c1999-12-09 06:11:36 +0000460
Erik Andersene49d5ec2000-02-08 19:58:47 +0000461 va_start(arguments, fmt);
462 vfprintf(stderr, fmt, arguments);
463 fprintf(stderr, "\n%s\n", strerror(errnum));
464 va_end(arguments);
465 exit(i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000466}
467
468
469#define XWRITE(fd, buffer, n_bytes) \
470 do \
471 { \
472 assert ((fd) == 1); \
473 assert ((n_bytes) >= 0); \
474 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000475 detailed_error (EXIT_FAILURE, errno, "write error"); \
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000476 } \
477 while (0)
478
479/* Number of items to tail. */
480#define DEFAULT_N_LINES 10
481
482/* Size of atomic reads. */
483#ifndef BUFSIZ
484#define BUFSIZ (512 * 8)
485#endif
486
487/* If nonzero, interpret the numeric argument as the number of lines.
488 Otherwise, interpret it as the number of bytes. */
489static int count_lines;
490
491/* If nonzero, read from the end of one file until killed. */
492static int forever;
493
494/* If nonzero, read from the end of multiple files until killed. */
495static int forever_multiple;
496
497/* Array of file descriptors if forever_multiple is 1. */
498static int *file_descs;
499
500/* Array of file sizes if forever_multiple is 1. */
501static off_t *file_sizes;
502
503/* If nonzero, count from start of file instead of end. */
504static int from_start;
505
506/* If nonzero, print filename headers. */
507static int print_headers;
508
509/* When to print the filename banners. */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000510enum header_mode {
511 multiple_files, always, never
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000512};
513
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000514/* The name this program was run with. */
515char *program_name;
516
517/* Nonzero if we have ever read standard input. */
518static int have_read_stdin;
519
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000520
Erik Andersen7ab9c7e2000-05-12 19:41:47 +0000521static 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\
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000524With more than one FILE, precede each with a header giving the file name.\n\
525With no FILE, or when FILE is -, read standard input.\n\
526\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000527 -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\
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000532\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000533If the first character of N (bytes or lines) is a `+', output begins with \n\
534the Nth item from the start of each file, otherwise, print the last N items\n\
Erik Andersen7ab9c7e2000-05-12 19:41:47 +0000535in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n"
536#endif
537;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000538
Erik Andersene49d5ec2000-02-08 19:58:47 +0000539static void write_header(const char *filename, const char *comment)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000540{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000541 static int first_file = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000542
Erik Andersene49d5ec2000-02-08 19:58:47 +0000543 printf("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
544 (comment ? ": " : ""), (comment ? comment : ""));
545 first_file = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000546}
547
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. */
555
556static int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000557file_lines(const char *filename, int fd, long int n_lines, off_t pos)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000558{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000559 char buffer[BUFSIZ];
560 int bytes_read;
561 int i; /* Index into `buffer' for scanning. */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000562
Erik Andersene49d5ec2000-02-08 19:58:47 +0000563 if (n_lines == 0)
564 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000565
Erik Andersene49d5ec2000-02-08 19:58:47 +0000566 /* Set `bytes_read' to the size of the last, probably partial, buffer;
567 0 < `bytes_read' <= `BUFSIZ'. */
568 bytes_read = pos % BUFSIZ;
569 if (bytes_read == 0)
570 bytes_read = 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. */
573 pos -= bytes_read;
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);
578 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000579 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000580
581 /* Count the incomplete line on files that don't end with a newline. */
582 if (bytes_read && buffer[bytes_read - 1] != '\n')
583 --n_lines;
584
585 do {
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));
595 return 0;
596 }
597 }
598 /* Not enough newlines in that bufferfull. */
599 if (pos == 0) {
600 /* Not enough lines in the file; print the entire file. */
601 lseek(fd, (off_t) 0, SEEK_SET);
602 return 0;
603 }
604 pos -= BUFSIZ;
605 lseek(fd, pos, SEEK_SET);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000606 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000607 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
608 if (bytes_read == -1) {
609 detailed_error(0, errno, "%s", filename);
610 return 1;
611 }
612 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000613}
614
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. */
619
Erik Andersene49d5ec2000-02-08 19:58:47 +0000620static int pipe_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000621{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000622 struct linebuffer {
623 int nbytes, nlines;
624 char buffer[BUFSIZ];
625 struct linebuffer *next;
626 };
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. */
631 int errors = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000632
Erik Andersene49d5ec2000-02-08 19:58:47 +0000633 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
634 first->nbytes = first->nlines = 0;
635 first->next = NULL;
636 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000637
Erik Andersene49d5ec2000-02-08 19:58:47 +0000638 /* Input is always read into a fresh buffer. */
639 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
640 tmp->nlines = 0;
641 tmp->next = NULL;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000642
Erik Andersene49d5ec2000-02-08 19:58:47 +0000643 /* Count the number of newlines just read. */
644 for (i = 0; i < tmp->nbytes; i++)
645 if (tmp->buffer[i] == '\n')
646 ++tmp->nlines;
647 total_lines += tmp->nlines;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000648
Erik Andersene49d5ec2000-02-08 19:58:47 +0000649 /* 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;
656 } else {
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
661 worthwhile. */
662 last = last->next = tmp;
663 if (total_lines - first->nlines > n_lines) {
664 tmp = first;
665 total_lines -= first->nlines;
666 first = first->next;
667 } else
668 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
669 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000670 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000671 if (tmp->nbytes == -1) {
672 detailed_error(0, errno, "%s", filename);
673 errors = 1;
674 free((char *) tmp);
675 goto free_lbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000676 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000677
Erik Andersene49d5ec2000-02-08 19:58:47 +0000678 free((char *) tmp);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000679
Erik Andersene49d5ec2000-02-08 19:58:47 +0000680 /* This prevents a core dump when the pipe contains no newlines. */
681 if (n_lines == 0)
682 goto free_lbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000683
Erik Andersene49d5ec2000-02-08 19:58:47 +0000684 /* Count the incomplete line on files that don't end with a newline. */
685 if (last->buffer[last->nbytes - 1] != '\n') {
686 ++last->nlines;
687 ++total_lines;
688 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000689
Erik Andersene49d5ec2000-02-08 19:58:47 +0000690 /* Run through the list, printing lines. First, skip over unneeded
691 buffers. */
692 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
693 total_lines -= tmp->nlines;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000694
Erik Andersene49d5ec2000-02-08 19:58:47 +0000695 /* Find the correct beginning, then print the rest of the file. */
696 if (total_lines > n_lines) {
697 char *cp;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000698
Erik Andersene49d5ec2000-02-08 19:58:47 +0000699 /* Skip `total_lines' - `n_lines' newlines. We made sure that
700 `total_lines' - `n_lines' <= `tmp->nlines'. */
701 cp = tmp->buffer;
702 for (i = total_lines - n_lines; i; --i)
703 while (*cp++ != '\n')
704 /* Do nothing. */ ;
705 i = cp - tmp->buffer;
706 } else
707 i = 0;
708 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000709
Erik Andersene49d5ec2000-02-08 19:58:47 +0000710 for (tmp = tmp->next; tmp; tmp = tmp->next)
711 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000712
Erik Andersene49d5ec2000-02-08 19:58:47 +0000713 free_lbuffers:
714 while (first) {
715 tmp = first->next;
716 free((char *) first);
717 first = tmp;
718 }
719 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000720}
721
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. */
725
Erik Andersene49d5ec2000-02-08 19:58:47 +0000726static int pipe_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000727{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000728 struct charbuffer {
729 int nbytes;
730 char buffer[BUFSIZ];
731 struct charbuffer *next;
732 };
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. */
737 int errors = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000738
Erik Andersene49d5ec2000-02-08 19:58:47 +0000739 first = last = (CBUFFER *) xmalloc(sizeof(CBUFFER));
740 first->nbytes = 0;
741 first->next = NULL;
742 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000743
Erik Andersene49d5ec2000-02-08 19:58:47 +0000744 /* Input is always read into a fresh buffer. */
745 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
746 tmp->next = NULL;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000747
Erik Andersene49d5ec2000-02-08 19:58:47 +0000748 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;
755 } else {
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
760 worthwhile. */
761 last = last->next = tmp;
762 if (total_bytes - first->nbytes > n_bytes) {
763 tmp = first;
764 total_bytes -= first->nbytes;
765 first = first->next;
766 } else {
767 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
768 }
769 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000770 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000771 if (tmp->nbytes == -1) {
772 detailed_error(0, errno, "%s", filename);
773 errors = 1;
774 free((char *) tmp);
775 goto free_cbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000776 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000777
Erik Andersene49d5ec2000-02-08 19:58:47 +0000778 free((char *) tmp);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000779
Erik Andersene49d5ec2000-02-08 19:58:47 +0000780 /* Run through the list, printing characters. First, skip over unneeded
781 buffers. */
782 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
783 total_bytes -= tmp->nbytes;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000784
Erik Andersene49d5ec2000-02-08 19:58:47 +0000785 /* 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;
789 else
790 i = 0;
791 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000792
Erik Andersene49d5ec2000-02-08 19:58:47 +0000793 for (tmp = tmp->next; tmp; tmp = tmp->next)
794 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000795
Erik Andersene49d5ec2000-02-08 19:58:47 +0000796 free_cbuffers:
797 while (first) {
798 tmp = first->next;
799 free((char *) first);
800 first = tmp;
801 }
802 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000803}
804
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. */
808
Erik Andersene49d5ec2000-02-08 19:58:47 +0000809static int start_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000810{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000811 char buffer[BUFSIZ];
812 int bytes_read = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000813
Erik Andersene49d5ec2000-02-08 19:58:47 +0000814 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);
818 return 1;
819 } else if (n_bytes < 0)
820 XWRITE(STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
821 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000822}
823
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. */
827
Erik Andersene49d5ec2000-02-08 19:58:47 +0000828static int start_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000829{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000830 char buffer[BUFSIZ];
831 int bytes_read = 0;
832 int bytes_to_skip = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000833
Erik Andersene49d5ec2000-02-08 19:58:47 +0000834 while (n_lines && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
835 bytes_to_skip = 0;
836 while (bytes_to_skip < bytes_read)
837 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
838 break;
839 }
840 if (bytes_read == -1) {
841 detailed_error(0, errno, "%s", filename);
842 return 1;
843 } else if (bytes_to_skip < bytes_read) {
844 XWRITE(STDOUT_FILENO, &buffer[bytes_to_skip],
845 bytes_read - bytes_to_skip);
846 }
847 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000848}
849
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. */
853
Erik Andersene49d5ec2000-02-08 19:58:47 +0000854static long dump_remainder(const char *filename, int fd)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000855{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000856 char buffer[BUFSIZ];
857 int bytes_read;
858 long total;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000859
Erik Andersene49d5ec2000-02-08 19:58:47 +0000860 total = 0;
861 output:
862 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
863 XWRITE(STDOUT_FILENO, buffer, bytes_read);
864 total += bytes_read;
865 }
866 if (bytes_read == -1)
867 detailed_error(EXIT_FAILURE, errno, "%s", filename);
868 if (forever) {
869 fflush(stdout);
870 sleep(1);
871 goto output;
872 } else {
873 if (forever_multiple)
874 fflush(stdout);
875 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000876
Erik Andersene49d5ec2000-02-08 19:58:47 +0000877 return total;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000878}
879
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. */
886
Erik Andersene49d5ec2000-02-08 19:58:47 +0000887static void tail_forever(char **names, int nfiles)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000888{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000889 int last;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000890
Erik Andersene49d5ec2000-02-08 19:58:47 +0000891 last = -1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000892
Erik Andersene49d5ec2000-02-08 19:58:47 +0000893 while (1) {
894 int i;
895 int changed;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000896
Erik Andersene49d5ec2000-02-08 19:58:47 +0000897 changed = 0;
898 for (i = 0; i < nfiles; i++) {
899 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000900
Erik Andersene49d5ec2000-02-08 19:58:47 +0000901 if (file_descs[i] < 0)
902 continue;
903 if (fstat(file_descs[i], &stats) < 0) {
904 detailed_error(0, errno, "%s", names[i]);
905 file_descs[i] = -1;
906 continue;
907 }
908 if (stats.st_size == file_sizes[i])
909 continue;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000910
Erik Andersene49d5ec2000-02-08 19:58:47 +0000911 /* This file has changed size. Print out what we can, and
912 then keep looping. */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000913
Erik Andersene49d5ec2000-02-08 19:58:47 +0000914 changed = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000915
Erik Andersene49d5ec2000-02-08 19:58:47 +0000916 if (stats.st_size < file_sizes[i]) {
917 write_header(names[i], "file truncated");
918 last = i;
919 lseek(file_descs[i], stats.st_size, SEEK_SET);
920 file_sizes[i] = stats.st_size;
921 continue;
922 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000923
Erik Andersene49d5ec2000-02-08 19:58:47 +0000924 if (i != last) {
925 if (print_headers)
926 write_header(names[i], NULL);
927 last = i;
928 }
929 file_sizes[i] += dump_remainder(names[i], file_descs[i]);
930 }
931
932 /* If none of the files changed size, sleep. */
933 if (!changed)
934 sleep(1);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000935 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000936}
937
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. */
940
Erik Andersene49d5ec2000-02-08 19:58:47 +0000941static int tail_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000942{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000943 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000944
Erik Andersene49d5ec2000-02-08 19:58:47 +0000945 /* 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
948 error, either. */
949 if (fstat(fd, &stats)) {
950 detailed_error(0, errno, "%s", filename);
951 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000952 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000953
954 if (from_start) {
955 if (S_ISREG(stats.st_mode))
956 lseek(fd, n_bytes, SEEK_CUR);
957 else if (start_bytes(filename, fd, n_bytes))
958 return 1;
959 dump_remainder(filename, fd);
960 } else {
961 if (S_ISREG(stats.st_mode)) {
962 off_t current_pos, end_pos;
963 size_t bytes_remaining;
964
965 if ((current_pos = lseek(fd, (off_t) 0, SEEK_CUR)) != -1
966 && (end_pos = lseek(fd, (off_t) 0, SEEK_END)) != -1) {
967 off_t diff;
968
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;
973 } else {
974 detailed_error(0, errno, "%s", filename);
975 return 1;
976 }
977
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);
984 } else {
985 /* There are more bytes remaining than were requested.
986 Back up. */
987 lseek(fd, -n_bytes, SEEK_END);
988 }
989 dump_remainder(filename, fd);
990 } else
991 return pipe_bytes(filename, fd, n_bytes);
992 }
993 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000994}
995
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. */
998
Erik Andersene49d5ec2000-02-08 19:58:47 +0000999static int tail_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001000{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001001 struct stat stats;
1002 off_t length;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001003
Erik Andersene49d5ec2000-02-08 19:58:47 +00001004 if (fstat(fd, &stats)) {
1005 detailed_error(0, errno, "%s", filename);
1006 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001007 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001008
1009 if (from_start) {
1010 if (start_lines(filename, fd, n_lines))
1011 return 1;
1012 dump_remainder(filename, fd);
1013 } else {
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))
1024 return 1;
1025 dump_remainder(filename, fd);
1026 } else
1027 return pipe_lines(filename, fd, n_lines);
1028 }
1029 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001030}
1031
1032/* Display the last N_UNITS units of file FILENAME, open for reading
1033 in FD.
1034 Return 0 if successful, 1 if an error occurred. */
1035
Erik Andersene49d5ec2000-02-08 19:58:47 +00001036static int tail(const char *filename, int fd, off_t n_units)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001037{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001038 if (count_lines)
1039 return tail_lines(filename, fd, (long) n_units);
1040 else
1041 return tail_bytes(filename, fd, n_units);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001042}
1043
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. */
1048
Erik Andersene49d5ec2000-02-08 19:58:47 +00001049static int tail_file(const char *filename, off_t n_units, int filenum)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001050{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001051 int fd, errors;
1052 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001053
Erik Andersene49d5ec2000-02-08 19:58:47 +00001054 if (!strcmp(filename, "-")) {
1055 have_read_stdin = 1;
1056 filename = "standard input";
1057 if (print_headers)
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");
1063 errors = 1;
1064 } else if (!S_ISREG(stats.st_mode)) {
1065 detailed_error(0, 0,
1066 "standard input: cannot follow end of non-regular file");
1067 errors = 1;
1068 }
1069 if (errors)
1070 file_descs[filenum] = -1;
1071 else {
1072 file_descs[filenum] = 0;
1073 file_sizes[filenum] = stats.st_size;
1074 }
1075 }
1076 } else {
1077 /* Not standard input. */
1078 fd = open(filename, O_RDONLY);
1079 if (fd == -1) {
1080 if (forever_multiple)
1081 file_descs[filenum] = -1;
1082 detailed_error(0, errno, "%s", filename);
1083 errors = 1;
1084 } else {
1085 if (print_headers)
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);
1091 errors = 1;
1092 } else if (!S_ISREG(stats.st_mode)) {
1093 detailed_error(0, 0,
1094 "%s: cannot follow end of non-regular file",
1095 filename);
1096 errors = 1;
1097 }
1098 if (errors) {
1099 close(fd);
1100 file_descs[filenum] = -1;
1101 } else {
1102 file_descs[filenum] = fd;
1103 file_sizes[filenum] = stats.st_size;
1104 }
1105 } else {
1106 if (close(fd)) {
1107 detailed_error(0, errno, "%s", filename);
1108 errors = 1;
1109 }
1110 }
1111 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001112 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001113
Erik Andersene49d5ec2000-02-08 19:58:47 +00001114 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001115}
1116
Erik Andersene49d5ec2000-02-08 19:58:47 +00001117extern int tail_main(int argc, char **argv)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001118{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001119 int stopit = 0;
1120 enum header_mode header_mode = multiple_files;
1121 int exit_status = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001122
Erik Andersene49d5ec2000-02-08 19:58:47 +00001123 /* 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. */
1126 off_t n_units = -1;
1127 int n_files;
1128 char **file;
1129
1130 program_name = argv[0];
1131 have_read_stdin = 0;
1132 count_lines = 1;
1133 forever = forever_multiple = from_start = print_headers = 0;
1134
1135 /* Parse any options */
1136 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1137 while (--argc > 0 && (**(++argv) == '-' || **argv == '+')) {
1138 if (**argv == '+') {
1139 from_start = 1;
1140 }
1141 stopit = 0;
1142 while (stopit == 0 && *(++(*argv))) {
1143 switch (**argv) {
1144 case 'c':
1145 count_lines = 0;
1146
1147 if (--argc < 1) {
1148 usage(tail_usage);
1149 }
1150 n_units = getNum(*(++argv));
1151 stopit = 1;
1152 break;
1153
1154 case 'f':
1155 forever = 1;
1156 break;
1157
1158 case 'n':
1159 count_lines = 1;
1160
1161 if (--argc < 1) {
1162 usage(tail_usage);
1163 }
1164 n_units = atol(*(++argv));
1165 stopit = 1;
1166 break;
1167
1168 case 'q':
1169 header_mode = never;
1170 break;
1171
1172 case 'v':
1173 header_mode = always;
1174 break;
1175
1176 default:
1177 usage(tail_usage);
1178 }
1179 }
Eric Andersen1792f8c1999-12-09 06:11:36 +00001180 }
Eric Andersen1792f8c1999-12-09 06:11:36 +00001181
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001182
Erik Andersene49d5ec2000-02-08 19:58:47 +00001183 if (n_units == -1)
1184 n_units = DEFAULT_N_LINES;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001185
Erik Andersene49d5ec2000-02-08 19:58:47 +00001186 /* 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'. */
1189 if (from_start) {
1190 if (n_units)
1191 --n_units;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001192 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001193
Erik Andersene49d5ec2000-02-08 19:58:47 +00001194 n_files = argc;
1195 file = argv;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001196
Erik Andersene49d5ec2000-02-08 19:58:47 +00001197 if (n_files > 1 && forever) {
1198 forever_multiple = 1;
1199 forever = 0;
1200 file_descs = (int *) xmalloc(n_files * sizeof(int));
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001201
Erik Andersene49d5ec2000-02-08 19:58:47 +00001202 file_sizes = (off_t *) xmalloc(n_files * sizeof(off_t));
1203 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001204
Erik Andersene49d5ec2000-02-08 19:58:47 +00001205 if (header_mode == always
1206 || (header_mode == multiple_files && n_files > 1))
1207 print_headers = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001208
Erik Andersene49d5ec2000-02-08 19:58:47 +00001209 if (n_files == 0) {
1210 exit_status |= tail_file("-", n_units, 0);
1211 } else {
1212 int i;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001213
Erik Andersene49d5ec2000-02-08 19:58:47 +00001214 for (i = 0; i < n_files; i++)
1215 exit_status |= tail_file(file[i], n_units, i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001216
Erik Andersene49d5ec2000-02-08 19:58:47 +00001217 if (forever_multiple)
1218 tail_forever(file, n_files);
1219 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001220
Erik Andersene49d5ec2000-02-08 19:58:47 +00001221 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);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001226}
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001227
1228
1229#endif