blob: 315eee1885b5f5e4d2c92b975fc1417bcc65d641 [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>
50
51
52#define XWRITE(fd, buffer, n_bytes) \
53 do { \
54 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
Erik Andersen9ffdaa62000-02-11 21:55:04 +000055 errorMsg("write error"); \
Erik Andersen3fe39dc2000-01-25 18:13:53 +000056 } while (0)
57
58/* Number of items to tail. */
59#define DEFAULT_N_LINES 10
60
61/* Size of atomic reads. */
62#ifndef BUFSIZ
63#define BUFSIZ (512 * 8)
64#endif
65
66/* If nonzero, read from the end of one file until killed. */
67static int forever;
68
69/* If nonzero, print filename headers. */
70static int print_headers;
71
72const char tail_usage[] =
Erik Andersene49d5ec2000-02-08 19:58:47 +000073 "tail [OPTION] [FILE]...\n\n"
74 "Print last 10 lines of each FILE to standard output.\n"
75 "With more than one FILE, precede each with a header giving the\n"
76 "file name. With no FILE, or when FILE is -, read standard input.\n\n"
77 "Options:\n"
78 "\t-n NUM\t\tPrint last NUM lines instead of first 10\n"
79
80 "\t-f\t\tOutput data as the file grows. This version\n"
81 "\t\t\tof 'tail -f' supports only one file at a time.\n";
Erik Andersen3fe39dc2000-01-25 18:13:53 +000082
83
84static void write_header(const char *filename)
85{
Erik Andersene49d5ec2000-02-08 19:58:47 +000086 static int first_file = 1;
Erik Andersen3fe39dc2000-01-25 18:13:53 +000087
Erik Andersene49d5ec2000-02-08 19:58:47 +000088 printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
89 first_file = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +000090}
91
92/* Print the last N_LINES lines from the end of file FD.
93 Go backward through the file, reading `BUFSIZ' bytes at a time (except
94 probably the first), until we hit the start of the file or have
95 read NUMBER newlines.
96 POS starts out as the length of the file (the offset of the last
97 byte of the file + 1).
98 Return 0 if successful, 1 if an error occurred. */
99
100static int
101file_lines(const char *filename, int fd, long int n_lines, off_t pos)
102{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000103 char buffer[BUFSIZ];
104 int bytes_read;
105 int i; /* Index into `buffer' for scanning. */
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000106
Erik Andersene49d5ec2000-02-08 19:58:47 +0000107 if (n_lines == 0)
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000108 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000109
Erik Andersene49d5ec2000-02-08 19:58:47 +0000110 /* Set `bytes_read' to the size of the last, probably partial, buffer;
111 0 < `bytes_read' <= `BUFSIZ'. */
112 bytes_read = pos % BUFSIZ;
113 if (bytes_read == 0)
114 bytes_read = BUFSIZ;
115 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
116 reads will be on block boundaries, which might increase efficiency. */
117 pos -= bytes_read;
118 lseek(fd, pos, SEEK_SET);
119 bytes_read = fullRead(fd, buffer, bytes_read);
120 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000121 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000122
123 /* Count the incomplete line on files that don't end with a newline. */
124 if (bytes_read && buffer[bytes_read - 1] != '\n')
125 --n_lines;
126
127 do {
128 /* Scan backward, counting the newlines in this bufferfull. */
129 for (i = bytes_read - 1; i >= 0; i--) {
130 /* Have we counted the requested number of newlines yet? */
131 if (buffer[i] == '\n' && n_lines-- == 0) {
132 /* If this newline wasn't the last character in the buffer,
133 print the text after it. */
134 if (i != bytes_read - 1)
135 XWRITE(STDOUT_FILENO, &buffer[i + 1],
136 bytes_read - (i + 1));
137 return 0;
138 }
139 }
140 /* Not enough newlines in that bufferfull. */
141 if (pos == 0) {
142 /* Not enough lines in the file; print the entire file. */
143 lseek(fd, (off_t) 0, SEEK_SET);
144 return 0;
145 }
146 pos -= BUFSIZ;
147 lseek(fd, pos, SEEK_SET);
148 }
149 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
150 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000151 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000152
153 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000154}
155
156/* Print the last N_LINES lines from the end of the standard input,
157 open for reading as pipe FD.
158 Buffer the text as a linked list of LBUFFERs, adding them as needed.
159 Return 0 if successful, 1 if an error occured. */
160
161static int pipe_lines(const char *filename, int fd, long int n_lines)
162{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000163 struct linebuffer {
164 int nbytes, nlines;
165 char buffer[BUFSIZ];
166 struct linebuffer *next;
167 };
168 typedef struct linebuffer LBUFFER;
169 LBUFFER *first, *last, *tmp;
170 int i; /* Index into buffers. */
171 int total_lines = 0; /* Total number of newlines in all buffers. */
172 int errors = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000173
Erik Andersene49d5ec2000-02-08 19:58:47 +0000174 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
175 first->nbytes = first->nlines = 0;
176 first->next = NULL;
177 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000178
Erik Andersene49d5ec2000-02-08 19:58:47 +0000179 /* Input is always read into a fresh buffer. */
180 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
181 tmp->nlines = 0;
182 tmp->next = NULL;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000183
Erik Andersene49d5ec2000-02-08 19:58:47 +0000184 /* Count the number of newlines just read. */
185 for (i = 0; i < tmp->nbytes; i++)
186 if (tmp->buffer[i] == '\n')
187 ++tmp->nlines;
188 total_lines += tmp->nlines;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000189
Erik Andersene49d5ec2000-02-08 19:58:47 +0000190 /* If there is enough room in the last buffer read, just append the new
191 one to it. This is because when reading from a pipe, `nbytes' can
192 often be very small. */
193 if (tmp->nbytes + last->nbytes < BUFSIZ) {
194 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
195 last->nbytes += tmp->nbytes;
196 last->nlines += tmp->nlines;
197 } else {
198 /* If there's not enough room, link the new buffer onto the end of
199 the list, then either free up the oldest buffer for the next
200 read if that would leave enough lines, or else malloc a new one.
201 Some compaction mechanism is possible but probably not
202 worthwhile. */
203 last = last->next = tmp;
204 if (total_lines - first->nlines > n_lines) {
205 tmp = first;
206 total_lines -= first->nlines;
207 first = first->next;
208 } else
209 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
210 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000211 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000212 if (tmp->nbytes == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000213 errorMsg("read error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000214
Erik Andersene49d5ec2000-02-08 19:58:47 +0000215 free((char *) tmp);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000216
Erik Andersene49d5ec2000-02-08 19:58:47 +0000217 /* This prevents a core dump when the pipe contains no newlines. */
218 if (n_lines == 0)
219 goto free_lbuffers;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000220
Erik Andersene49d5ec2000-02-08 19:58:47 +0000221 /* Count the incomplete line on files that don't end with a newline. */
222 if (last->buffer[last->nbytes - 1] != '\n') {
223 ++last->nlines;
224 ++total_lines;
225 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000226
Erik Andersene49d5ec2000-02-08 19:58:47 +0000227 /* Run through the list, printing lines. First, skip over unneeded
228 buffers. */
229 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
230 total_lines -= tmp->nlines;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000231
Erik Andersene49d5ec2000-02-08 19:58:47 +0000232 /* Find the correct beginning, then print the rest of the file. */
233 if (total_lines > n_lines) {
234 char *cp;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000235
Erik Andersene49d5ec2000-02-08 19:58:47 +0000236 /* Skip `total_lines' - `n_lines' newlines. We made sure that
237 `total_lines' - `n_lines' <= `tmp->nlines'. */
238 cp = tmp->buffer;
239 for (i = total_lines - n_lines; i; --i)
240 while (*cp++ != '\n')
241 /* Do nothing. */ ;
242 i = cp - tmp->buffer;
243 } else
244 i = 0;
245 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000246
Erik Andersene49d5ec2000-02-08 19:58:47 +0000247 for (tmp = tmp->next; tmp; tmp = tmp->next)
248 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000249
250 free_lbuffers:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000251 while (first) {
252 tmp = first->next;
253 free((char *) first);
254 first = tmp;
255 }
256 return errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000257}
258
259/* Display file FILENAME from the current position in FD to the end.
260 If `forever' is nonzero, keep reading from the end of the file
261 until killed. Return the number of bytes read from the file. */
262
263static long dump_remainder(const char *filename, int fd)
264{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000265 char buffer[BUFSIZ];
266 int bytes_read;
267 long total;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000268
Erik Andersene49d5ec2000-02-08 19:58:47 +0000269 total = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000270 output:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000271 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
272 XWRITE(STDOUT_FILENO, buffer, bytes_read);
273 total += bytes_read;
274 }
275 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000276 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000277 if (forever) {
278 fflush(stdout);
279 sleep(1);
280 goto output;
281 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000282
Erik Andersene49d5ec2000-02-08 19:58:47 +0000283 return total;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000284}
285
286/* Output the last N_LINES lines of file FILENAME open for reading in FD.
287 Return 0 if successful, 1 if an error occurred. */
288
289static int tail_lines(const char *filename, int fd, long int n_lines)
290{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000291 struct stat stats;
292 off_t length;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000293
Erik Andersene49d5ec2000-02-08 19:58:47 +0000294 if (print_headers)
295 write_header(filename);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000296
Erik Andersene49d5ec2000-02-08 19:58:47 +0000297 if (fstat(fd, &stats))
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000298 errorMsg("fstat error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000299
Erik Andersene49d5ec2000-02-08 19:58:47 +0000300 /* Use file_lines only if FD refers to a regular file with
301 its file pointer positioned at beginning of file. */
302 /* FIXME: adding the lseek conjunct is a kludge.
303 Once there's a reasonable test suite, fix the true culprit:
304 file_lines. file_lines shouldn't presume that the input
305 file pointer is initially positioned to beginning of file. */
306 if (S_ISREG(stats.st_mode)
307 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
308 length = lseek(fd, (off_t) 0, SEEK_END);
309 if (length != 0 && file_lines(filename, fd, n_lines, length))
310 return 1;
311 dump_remainder(filename, fd);
312 } else
313 return pipe_lines(filename, fd, n_lines);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000314
Erik Andersene49d5ec2000-02-08 19:58:47 +0000315 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000316}
317
318/* Display the last N_UNITS lines of file FILENAME.
319 "-" for FILENAME means the standard input.
320 Return 0 if successful, 1 if an error occurred. */
321
322static int tail_file(const char *filename, off_t n_units)
323{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000324 int fd, errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000325
Erik Andersene49d5ec2000-02-08 19:58:47 +0000326 if (!strcmp(filename, "-")) {
327 filename = "standard input";
328 errors = tail_lines(filename, 0, (long) n_units);
329 } else {
330 /* Not standard input. */
331 fd = open(filename, O_RDONLY);
332 if (fd == -1)
Erik Andersene2729152000-02-18 21:34:17 +0000333 fatalError("open error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000334
Erik Andersene49d5ec2000-02-08 19:58:47 +0000335 errors = tail_lines(filename, fd, (long) n_units);
336 close(fd);
337 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000338
Erik Andersene49d5ec2000-02-08 19:58:47 +0000339 return errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000340}
341
342extern int tail_main(int argc, char **argv)
343{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000344 int exit_status = 0;
345 int n_units = DEFAULT_N_LINES;
346 int n_tmp, i;
347 char opt;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000348
Erik Andersene49d5ec2000-02-08 19:58:47 +0000349 forever = print_headers = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000350
Erik Andersene49d5ec2000-02-08 19:58:47 +0000351 /* parse argv[] */
352 for (i = 1; i < argc; i++) {
353 if (argv[i][0] == '-') {
354 opt = argv[i][1];
355 switch (opt) {
356 case 'f':
357 forever = 1;
358 break;
359 case 'n':
360 n_tmp = 0;
361 if (++i < argc)
362 n_tmp = atoi(argv[i]);
363 if (n_tmp < 1)
364 usage(tail_usage);
365 n_units = n_tmp;
366 break;
367 case '-':
368 case 'h':
369 usage(tail_usage);
370 default:
371 fprintf(stderr, "tail: invalid option -- %c\n", opt);
372 usage(tail_usage);
373 }
374 } else {
375 break;
376 }
377 }
378
379 if (i + 1 < argc) {
380 if (forever) {
381 fprintf(stderr,
382 "tail: option -f is invalid with multiple files\n");
383 usage(tail_usage);
384 }
385 print_headers = 1;
386 }
387
388 if (i >= argc) {
389 exit_status |= tail_file("-", n_units);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000390 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000391 for (; i < argc; i++)
392 exit_status |= tail_file(argv[i], n_units);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000393 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000394
Erik Andersene49d5ec2000-02-08 19:58:47 +0000395 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000396}
397
398
399#else
400// Here follows the code for the full featured tail code
401
402
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000403/* tail -- output the last part of file(s)
404 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
405
406 This program is free software; you can redistribute it and/or modify
407 it under the terms of the GNU General Public License as published by
408 the Free Software Foundation; either version 2, or (at your option)
409 any later version.
410
411 This program is distributed in the hope that it will be useful,
412 but WITHOUT ANY WARRANTY; without even the implied warranty of
413 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
414 GNU General Public License for more details.
415
416 You should have received a copy of the GNU General Public License
417 along with this program; if not, write to the Free Software
Eric Andersen1792f8c1999-12-09 06:11:36 +0000418 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000419
420 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
421 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
Eric Andersen1792f8c1999-12-09 06:11:36 +0000422 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
423
424 Rewrote the option parser, removed locales support,
425 and generally busyboxed, Erik Andersen <andersen@lineo.com>
426
427 */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000428
429#include "internal.h"
430
431#include <stdio.h>
Erik Andersen4d1d0111999-12-17 18:44:15 +0000432#include <stdarg.h>
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000433#include <assert.h>
434#include <errno.h>
435#include <sys/types.h>
Eric Andersen1792f8c1999-12-09 06:11:36 +0000436#include <sys/types.h>
437#include <sys/stat.h>
438#include <fcntl.h>
439#include <ctype.h>
440
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000441
442
443/* Disable assertions. Some systems have broken assert macros. */
444#define NDEBUG 1
445
446
Erik Andersene49d5ec2000-02-08 19:58:47 +0000447static void detailed_error(int i, int errnum, char *fmt, ...)
Erik Andersen93d65132000-04-06 08:06:36 +0000448 __attribute__ ((format (printf, 3, 4)));
449static void detailed_error(int i, int errnum, char *fmt, ...)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000450{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000451 va_list arguments;
Eric Andersen1792f8c1999-12-09 06:11:36 +0000452
Erik Andersene49d5ec2000-02-08 19:58:47 +0000453 va_start(arguments, fmt);
454 vfprintf(stderr, fmt, arguments);
455 fprintf(stderr, "\n%s\n", strerror(errnum));
456 va_end(arguments);
457 exit(i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000458}
459
460
461#define XWRITE(fd, buffer, n_bytes) \
462 do \
463 { \
464 assert ((fd) == 1); \
465 assert ((n_bytes) >= 0); \
466 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000467 detailed_error (EXIT_FAILURE, errno, "write error"); \
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000468 } \
469 while (0)
470
471/* Number of items to tail. */
472#define DEFAULT_N_LINES 10
473
474/* Size of atomic reads. */
475#ifndef BUFSIZ
476#define BUFSIZ (512 * 8)
477#endif
478
479/* If nonzero, interpret the numeric argument as the number of lines.
480 Otherwise, interpret it as the number of bytes. */
481static int count_lines;
482
483/* If nonzero, read from the end of one file until killed. */
484static int forever;
485
486/* If nonzero, read from the end of multiple files until killed. */
487static int forever_multiple;
488
489/* Array of file descriptors if forever_multiple is 1. */
490static int *file_descs;
491
492/* Array of file sizes if forever_multiple is 1. */
493static off_t *file_sizes;
494
495/* If nonzero, count from start of file instead of end. */
496static int from_start;
497
498/* If nonzero, print filename headers. */
499static int print_headers;
500
501/* When to print the filename banners. */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000502enum header_mode {
503 multiple_files, always, never
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000504};
505
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000506/* The name this program was run with. */
507char *program_name;
508
509/* Nonzero if we have ever read standard input. */
510static int have_read_stdin;
511
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000512
Erik Andersene49d5ec2000-02-08 19:58:47 +0000513static const char tail_usage[] = "tail [OPTION]... [FILE]...\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000514\n\
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000515Print last 10 lines of each FILE to standard output.\n\
516With more than one FILE, precede each with a header giving the file name.\n\
517With no FILE, or when FILE is -, read standard input.\n\
518\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000519 -c=N[kbm] output the last N bytes\n\
520 -f output appended data as the file grows\n\
521 -n=N output the last N lines, instead of last 10\n\
522 -q never output headers giving file names\n\
523 -v always output headers giving file names\n\
524 --help display this help and exit\n\
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000525\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000526If the first character of N (bytes or lines) is a `+', output begins with \n\
527the Nth item from the start of each file, otherwise, print the last N items\n\
528in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2).\n\n";
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000529
Erik Andersene49d5ec2000-02-08 19:58:47 +0000530static void write_header(const char *filename, const char *comment)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000531{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000532 static int first_file = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000533
Erik Andersene49d5ec2000-02-08 19:58:47 +0000534 printf("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
535 (comment ? ": " : ""), (comment ? comment : ""));
536 first_file = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000537}
538
539/* Print the last N_LINES lines from the end of file FD.
540 Go backward through the file, reading `BUFSIZ' bytes at a time (except
541 probably the first), until we hit the start of the file or have
542 read NUMBER newlines.
543 POS starts out as the length of the file (the offset of the last
544 byte of the file + 1).
545 Return 0 if successful, 1 if an error occurred. */
546
547static int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000548file_lines(const char *filename, int fd, long int n_lines, off_t pos)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000549{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000550 char buffer[BUFSIZ];
551 int bytes_read;
552 int i; /* Index into `buffer' for scanning. */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000553
Erik Andersene49d5ec2000-02-08 19:58:47 +0000554 if (n_lines == 0)
555 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000556
Erik Andersene49d5ec2000-02-08 19:58:47 +0000557 /* Set `bytes_read' to the size of the last, probably partial, buffer;
558 0 < `bytes_read' <= `BUFSIZ'. */
559 bytes_read = pos % BUFSIZ;
560 if (bytes_read == 0)
561 bytes_read = BUFSIZ;
562 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
563 reads will be on block boundaries, which might increase efficiency. */
564 pos -= bytes_read;
565 lseek(fd, pos, SEEK_SET);
566 bytes_read = fullRead(fd, buffer, bytes_read);
567 if (bytes_read == -1) {
568 detailed_error(0, errno, "%s", filename);
569 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000570 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000571
572 /* Count the incomplete line on files that don't end with a newline. */
573 if (bytes_read && buffer[bytes_read - 1] != '\n')
574 --n_lines;
575
576 do {
577 /* Scan backward, counting the newlines in this bufferfull. */
578 for (i = bytes_read - 1; i >= 0; i--) {
579 /* Have we counted the requested number of newlines yet? */
580 if (buffer[i] == '\n' && n_lines-- == 0) {
581 /* If this newline wasn't the last character in the buffer,
582 print the text after it. */
583 if (i != bytes_read - 1)
584 XWRITE(STDOUT_FILENO, &buffer[i + 1],
585 bytes_read - (i + 1));
586 return 0;
587 }
588 }
589 /* Not enough newlines in that bufferfull. */
590 if (pos == 0) {
591 /* Not enough lines in the file; print the entire file. */
592 lseek(fd, (off_t) 0, SEEK_SET);
593 return 0;
594 }
595 pos -= BUFSIZ;
596 lseek(fd, pos, SEEK_SET);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000597 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000598 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
599 if (bytes_read == -1) {
600 detailed_error(0, errno, "%s", filename);
601 return 1;
602 }
603 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000604}
605
606/* Print the last N_LINES lines from the end of the standard input,
607 open for reading as pipe FD.
608 Buffer the text as a linked list of LBUFFERs, adding them as needed.
609 Return 0 if successful, 1 if an error occured. */
610
Erik Andersene49d5ec2000-02-08 19:58:47 +0000611static int pipe_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000612{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000613 struct linebuffer {
614 int nbytes, nlines;
615 char buffer[BUFSIZ];
616 struct linebuffer *next;
617 };
618 typedef struct linebuffer LBUFFER;
619 LBUFFER *first, *last, *tmp;
620 int i; /* Index into buffers. */
621 int total_lines = 0; /* Total number of newlines in all buffers. */
622 int errors = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000623
Erik Andersene49d5ec2000-02-08 19:58:47 +0000624 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
625 first->nbytes = first->nlines = 0;
626 first->next = NULL;
627 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000628
Erik Andersene49d5ec2000-02-08 19:58:47 +0000629 /* Input is always read into a fresh buffer. */
630 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
631 tmp->nlines = 0;
632 tmp->next = NULL;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000633
Erik Andersene49d5ec2000-02-08 19:58:47 +0000634 /* Count the number of newlines just read. */
635 for (i = 0; i < tmp->nbytes; i++)
636 if (tmp->buffer[i] == '\n')
637 ++tmp->nlines;
638 total_lines += tmp->nlines;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000639
Erik Andersene49d5ec2000-02-08 19:58:47 +0000640 /* If there is enough room in the last buffer read, just append the new
641 one to it. This is because when reading from a pipe, `nbytes' can
642 often be very small. */
643 if (tmp->nbytes + last->nbytes < BUFSIZ) {
644 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
645 last->nbytes += tmp->nbytes;
646 last->nlines += tmp->nlines;
647 } else {
648 /* If there's not enough room, link the new buffer onto the end of
649 the list, then either free up the oldest buffer for the next
650 read if that would leave enough lines, or else malloc a new one.
651 Some compaction mechanism is possible but probably not
652 worthwhile. */
653 last = last->next = tmp;
654 if (total_lines - first->nlines > n_lines) {
655 tmp = first;
656 total_lines -= first->nlines;
657 first = first->next;
658 } else
659 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
660 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000661 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000662 if (tmp->nbytes == -1) {
663 detailed_error(0, errno, "%s", filename);
664 errors = 1;
665 free((char *) tmp);
666 goto free_lbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000667 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000668
Erik Andersene49d5ec2000-02-08 19:58:47 +0000669 free((char *) tmp);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000670
Erik Andersene49d5ec2000-02-08 19:58:47 +0000671 /* This prevents a core dump when the pipe contains no newlines. */
672 if (n_lines == 0)
673 goto free_lbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000674
Erik Andersene49d5ec2000-02-08 19:58:47 +0000675 /* Count the incomplete line on files that don't end with a newline. */
676 if (last->buffer[last->nbytes - 1] != '\n') {
677 ++last->nlines;
678 ++total_lines;
679 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000680
Erik Andersene49d5ec2000-02-08 19:58:47 +0000681 /* Run through the list, printing lines. First, skip over unneeded
682 buffers. */
683 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
684 total_lines -= tmp->nlines;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000685
Erik Andersene49d5ec2000-02-08 19:58:47 +0000686 /* Find the correct beginning, then print the rest of the file. */
687 if (total_lines > n_lines) {
688 char *cp;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000689
Erik Andersene49d5ec2000-02-08 19:58:47 +0000690 /* Skip `total_lines' - `n_lines' newlines. We made sure that
691 `total_lines' - `n_lines' <= `tmp->nlines'. */
692 cp = tmp->buffer;
693 for (i = total_lines - n_lines; i; --i)
694 while (*cp++ != '\n')
695 /* Do nothing. */ ;
696 i = cp - tmp->buffer;
697 } else
698 i = 0;
699 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000700
Erik Andersene49d5ec2000-02-08 19:58:47 +0000701 for (tmp = tmp->next; tmp; tmp = tmp->next)
702 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000703
Erik Andersene49d5ec2000-02-08 19:58:47 +0000704 free_lbuffers:
705 while (first) {
706 tmp = first->next;
707 free((char *) first);
708 first = tmp;
709 }
710 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000711}
712
713/* Print the last N_BYTES characters from the end of pipe FD.
714 This is a stripped down version of pipe_lines.
715 Return 0 if successful, 1 if an error occurred. */
716
Erik Andersene49d5ec2000-02-08 19:58:47 +0000717static int pipe_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000718{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000719 struct charbuffer {
720 int nbytes;
721 char buffer[BUFSIZ];
722 struct charbuffer *next;
723 };
724 typedef struct charbuffer CBUFFER;
725 CBUFFER *first, *last, *tmp;
726 int i; /* Index into buffers. */
727 int total_bytes = 0; /* Total characters in all buffers. */
728 int errors = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000729
Erik Andersene49d5ec2000-02-08 19:58:47 +0000730 first = last = (CBUFFER *) xmalloc(sizeof(CBUFFER));
731 first->nbytes = 0;
732 first->next = NULL;
733 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000734
Erik Andersene49d5ec2000-02-08 19:58:47 +0000735 /* Input is always read into a fresh buffer. */
736 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
737 tmp->next = NULL;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000738
Erik Andersene49d5ec2000-02-08 19:58:47 +0000739 total_bytes += tmp->nbytes;
740 /* If there is enough room in the last buffer read, just append the new
741 one to it. This is because when reading from a pipe, `nbytes' can
742 often be very small. */
743 if (tmp->nbytes + last->nbytes < BUFSIZ) {
744 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
745 last->nbytes += tmp->nbytes;
746 } else {
747 /* If there's not enough room, link the new buffer onto the end of
748 the list, then either free up the oldest buffer for the next
749 read if that would leave enough characters, or else malloc a new
750 one. Some compaction mechanism is possible but probably not
751 worthwhile. */
752 last = last->next = tmp;
753 if (total_bytes - first->nbytes > n_bytes) {
754 tmp = first;
755 total_bytes -= first->nbytes;
756 first = first->next;
757 } else {
758 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
759 }
760 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000761 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000762 if (tmp->nbytes == -1) {
763 detailed_error(0, errno, "%s", filename);
764 errors = 1;
765 free((char *) tmp);
766 goto free_cbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000767 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000768
Erik Andersene49d5ec2000-02-08 19:58:47 +0000769 free((char *) tmp);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000770
Erik Andersene49d5ec2000-02-08 19:58:47 +0000771 /* Run through the list, printing characters. First, skip over unneeded
772 buffers. */
773 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
774 total_bytes -= tmp->nbytes;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000775
Erik Andersene49d5ec2000-02-08 19:58:47 +0000776 /* Find the correct beginning, then print the rest of the file.
777 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
778 if (total_bytes > n_bytes)
779 i = total_bytes - n_bytes;
780 else
781 i = 0;
782 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000783
Erik Andersene49d5ec2000-02-08 19:58:47 +0000784 for (tmp = tmp->next; tmp; tmp = tmp->next)
785 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000786
Erik Andersene49d5ec2000-02-08 19:58:47 +0000787 free_cbuffers:
788 while (first) {
789 tmp = first->next;
790 free((char *) first);
791 first = tmp;
792 }
793 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000794}
795
796/* Skip N_BYTES characters from the start of pipe FD, and print
797 any extra characters that were read beyond that.
798 Return 1 on error, 0 if ok. */
799
Erik Andersene49d5ec2000-02-08 19:58:47 +0000800static int start_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000801{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000802 char buffer[BUFSIZ];
803 int bytes_read = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000804
Erik Andersene49d5ec2000-02-08 19:58:47 +0000805 while (n_bytes > 0 && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0)
806 n_bytes -= bytes_read;
807 if (bytes_read == -1) {
808 detailed_error(0, errno, "%s", filename);
809 return 1;
810 } else if (n_bytes < 0)
811 XWRITE(STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
812 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000813}
814
815/* Skip N_LINES lines at the start of file or pipe FD, and print
816 any extra characters that were read beyond that.
817 Return 1 on error, 0 if ok. */
818
Erik Andersene49d5ec2000-02-08 19:58:47 +0000819static int start_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000820{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000821 char buffer[BUFSIZ];
822 int bytes_read = 0;
823 int bytes_to_skip = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000824
Erik Andersene49d5ec2000-02-08 19:58:47 +0000825 while (n_lines && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
826 bytes_to_skip = 0;
827 while (bytes_to_skip < bytes_read)
828 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
829 break;
830 }
831 if (bytes_read == -1) {
832 detailed_error(0, errno, "%s", filename);
833 return 1;
834 } else if (bytes_to_skip < bytes_read) {
835 XWRITE(STDOUT_FILENO, &buffer[bytes_to_skip],
836 bytes_read - bytes_to_skip);
837 }
838 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000839}
840
841/* Display file FILENAME from the current position in FD to the end.
842 If `forever' is nonzero, keep reading from the end of the file
843 until killed. Return the number of bytes read from the file. */
844
Erik Andersene49d5ec2000-02-08 19:58:47 +0000845static long dump_remainder(const char *filename, int fd)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000846{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000847 char buffer[BUFSIZ];
848 int bytes_read;
849 long total;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000850
Erik Andersene49d5ec2000-02-08 19:58:47 +0000851 total = 0;
852 output:
853 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
854 XWRITE(STDOUT_FILENO, buffer, bytes_read);
855 total += bytes_read;
856 }
857 if (bytes_read == -1)
858 detailed_error(EXIT_FAILURE, errno, "%s", filename);
859 if (forever) {
860 fflush(stdout);
861 sleep(1);
862 goto output;
863 } else {
864 if (forever_multiple)
865 fflush(stdout);
866 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000867
Erik Andersene49d5ec2000-02-08 19:58:47 +0000868 return total;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000869}
870
871/* Tail NFILES (>1) files forever until killed. The file names are in
872 NAMES. The open file descriptors are in `file_descs', and the size
873 at which we stopped tailing them is in `file_sizes'. We loop over
874 each of them, doing an fstat to see if they have changed size. If
875 none of them have changed size in one iteration, we sleep for a
876 second and try again. We do this until the user interrupts us. */
877
Erik Andersene49d5ec2000-02-08 19:58:47 +0000878static void tail_forever(char **names, int nfiles)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000879{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000880 int last;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000881
Erik Andersene49d5ec2000-02-08 19:58:47 +0000882 last = -1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000883
Erik Andersene49d5ec2000-02-08 19:58:47 +0000884 while (1) {
885 int i;
886 int changed;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000887
Erik Andersene49d5ec2000-02-08 19:58:47 +0000888 changed = 0;
889 for (i = 0; i < nfiles; i++) {
890 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000891
Erik Andersene49d5ec2000-02-08 19:58:47 +0000892 if (file_descs[i] < 0)
893 continue;
894 if (fstat(file_descs[i], &stats) < 0) {
895 detailed_error(0, errno, "%s", names[i]);
896 file_descs[i] = -1;
897 continue;
898 }
899 if (stats.st_size == file_sizes[i])
900 continue;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000901
Erik Andersene49d5ec2000-02-08 19:58:47 +0000902 /* This file has changed size. Print out what we can, and
903 then keep looping. */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000904
Erik Andersene49d5ec2000-02-08 19:58:47 +0000905 changed = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000906
Erik Andersene49d5ec2000-02-08 19:58:47 +0000907 if (stats.st_size < file_sizes[i]) {
908 write_header(names[i], "file truncated");
909 last = i;
910 lseek(file_descs[i], stats.st_size, SEEK_SET);
911 file_sizes[i] = stats.st_size;
912 continue;
913 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000914
Erik Andersene49d5ec2000-02-08 19:58:47 +0000915 if (i != last) {
916 if (print_headers)
917 write_header(names[i], NULL);
918 last = i;
919 }
920 file_sizes[i] += dump_remainder(names[i], file_descs[i]);
921 }
922
923 /* If none of the files changed size, sleep. */
924 if (!changed)
925 sleep(1);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000926 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000927}
928
929/* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
930 Return 0 if successful, 1 if an error occurred. */
931
Erik Andersene49d5ec2000-02-08 19:58:47 +0000932static int tail_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000933{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000934 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000935
Erik Andersene49d5ec2000-02-08 19:58:47 +0000936 /* FIXME: resolve this like in dd.c. */
937 /* Use fstat instead of checking for errno == ESPIPE because
938 lseek doesn't work on some special files but doesn't return an
939 error, either. */
940 if (fstat(fd, &stats)) {
941 detailed_error(0, errno, "%s", filename);
942 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000943 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000944
945 if (from_start) {
946 if (S_ISREG(stats.st_mode))
947 lseek(fd, n_bytes, SEEK_CUR);
948 else if (start_bytes(filename, fd, n_bytes))
949 return 1;
950 dump_remainder(filename, fd);
951 } else {
952 if (S_ISREG(stats.st_mode)) {
953 off_t current_pos, end_pos;
954 size_t bytes_remaining;
955
956 if ((current_pos = lseek(fd, (off_t) 0, SEEK_CUR)) != -1
957 && (end_pos = lseek(fd, (off_t) 0, SEEK_END)) != -1) {
958 off_t diff;
959
960 /* Be careful here. The current position may actually be
961 beyond the end of the file. */
962 bytes_remaining = (diff =
963 end_pos - current_pos) < 0 ? 0 : diff;
964 } else {
965 detailed_error(0, errno, "%s", filename);
966 return 1;
967 }
968
969 if (bytes_remaining <= n_bytes) {
970 /* From the current position to end of file, there are no
971 more bytes than have been requested. So reposition the
972 file pointer to the incoming current position and print
973 everything after that. */
974 lseek(fd, current_pos, SEEK_SET);
975 } else {
976 /* There are more bytes remaining than were requested.
977 Back up. */
978 lseek(fd, -n_bytes, SEEK_END);
979 }
980 dump_remainder(filename, fd);
981 } else
982 return pipe_bytes(filename, fd, n_bytes);
983 }
984 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000985}
986
987/* Output the last N_LINES lines of file FILENAME open for reading in FD.
988 Return 0 if successful, 1 if an error occurred. */
989
Erik Andersene49d5ec2000-02-08 19:58:47 +0000990static int tail_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000991{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000992 struct stat stats;
993 off_t length;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000994
Erik Andersene49d5ec2000-02-08 19:58:47 +0000995 if (fstat(fd, &stats)) {
996 detailed_error(0, errno, "%s", filename);
997 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000998 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000999
1000 if (from_start) {
1001 if (start_lines(filename, fd, n_lines))
1002 return 1;
1003 dump_remainder(filename, fd);
1004 } else {
1005 /* Use file_lines only if FD refers to a regular file with
1006 its file pointer positioned at beginning of file. */
1007 /* FIXME: adding the lseek conjunct is a kludge.
1008 Once there's a reasonable test suite, fix the true culprit:
1009 file_lines. file_lines shouldn't presume that the input
1010 file pointer is initially positioned to beginning of file. */
1011 if (S_ISREG(stats.st_mode)
1012 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
1013 length = lseek(fd, (off_t) 0, SEEK_END);
1014 if (length != 0 && file_lines(filename, fd, n_lines, length))
1015 return 1;
1016 dump_remainder(filename, fd);
1017 } else
1018 return pipe_lines(filename, fd, n_lines);
1019 }
1020 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001021}
1022
1023/* Display the last N_UNITS units of file FILENAME, open for reading
1024 in FD.
1025 Return 0 if successful, 1 if an error occurred. */
1026
Erik Andersene49d5ec2000-02-08 19:58:47 +00001027static int tail(const char *filename, int fd, off_t n_units)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001028{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001029 if (count_lines)
1030 return tail_lines(filename, fd, (long) n_units);
1031 else
1032 return tail_bytes(filename, fd, n_units);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001033}
1034
1035/* Display the last N_UNITS units of file FILENAME.
1036 "-" for FILENAME means the standard input.
1037 FILENUM is this file's index in the list of files the user gave.
1038 Return 0 if successful, 1 if an error occurred. */
1039
Erik Andersene49d5ec2000-02-08 19:58:47 +00001040static int tail_file(const char *filename, off_t n_units, int filenum)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001041{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001042 int fd, errors;
1043 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001044
Erik Andersene49d5ec2000-02-08 19:58:47 +00001045 if (!strcmp(filename, "-")) {
1046 have_read_stdin = 1;
1047 filename = "standard input";
1048 if (print_headers)
1049 write_header(filename, NULL);
1050 errors = tail(filename, 0, n_units);
1051 if (forever_multiple) {
1052 if (fstat(0, &stats) < 0) {
1053 detailed_error(0, errno, "standard input");
1054 errors = 1;
1055 } else if (!S_ISREG(stats.st_mode)) {
1056 detailed_error(0, 0,
1057 "standard input: cannot follow end of non-regular file");
1058 errors = 1;
1059 }
1060 if (errors)
1061 file_descs[filenum] = -1;
1062 else {
1063 file_descs[filenum] = 0;
1064 file_sizes[filenum] = stats.st_size;
1065 }
1066 }
1067 } else {
1068 /* Not standard input. */
1069 fd = open(filename, O_RDONLY);
1070 if (fd == -1) {
1071 if (forever_multiple)
1072 file_descs[filenum] = -1;
1073 detailed_error(0, errno, "%s", filename);
1074 errors = 1;
1075 } else {
1076 if (print_headers)
1077 write_header(filename, NULL);
1078 errors = tail(filename, fd, n_units);
1079 if (forever_multiple) {
1080 if (fstat(fd, &stats) < 0) {
1081 detailed_error(0, errno, "%s", filename);
1082 errors = 1;
1083 } else if (!S_ISREG(stats.st_mode)) {
1084 detailed_error(0, 0,
1085 "%s: cannot follow end of non-regular file",
1086 filename);
1087 errors = 1;
1088 }
1089 if (errors) {
1090 close(fd);
1091 file_descs[filenum] = -1;
1092 } else {
1093 file_descs[filenum] = fd;
1094 file_sizes[filenum] = stats.st_size;
1095 }
1096 } else {
1097 if (close(fd)) {
1098 detailed_error(0, errno, "%s", filename);
1099 errors = 1;
1100 }
1101 }
1102 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001103 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001104
Erik Andersene49d5ec2000-02-08 19:58:47 +00001105 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001106}
1107
Erik Andersene49d5ec2000-02-08 19:58:47 +00001108extern int tail_main(int argc, char **argv)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001109{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001110 int stopit = 0;
1111 enum header_mode header_mode = multiple_files;
1112 int exit_status = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001113
Erik Andersene49d5ec2000-02-08 19:58:47 +00001114 /* If from_start, the number of items to skip before printing; otherwise,
1115 the number of items at the end of the file to print. Initially, -1
1116 means the value has not been set. */
1117 off_t n_units = -1;
1118 int n_files;
1119 char **file;
1120
1121 program_name = argv[0];
1122 have_read_stdin = 0;
1123 count_lines = 1;
1124 forever = forever_multiple = from_start = print_headers = 0;
1125
1126 /* Parse any options */
1127 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1128 while (--argc > 0 && (**(++argv) == '-' || **argv == '+')) {
1129 if (**argv == '+') {
1130 from_start = 1;
1131 }
1132 stopit = 0;
1133 while (stopit == 0 && *(++(*argv))) {
1134 switch (**argv) {
1135 case 'c':
1136 count_lines = 0;
1137
1138 if (--argc < 1) {
1139 usage(tail_usage);
1140 }
1141 n_units = getNum(*(++argv));
1142 stopit = 1;
1143 break;
1144
1145 case 'f':
1146 forever = 1;
1147 break;
1148
1149 case 'n':
1150 count_lines = 1;
1151
1152 if (--argc < 1) {
1153 usage(tail_usage);
1154 }
1155 n_units = atol(*(++argv));
1156 stopit = 1;
1157 break;
1158
1159 case 'q':
1160 header_mode = never;
1161 break;
1162
1163 case 'v':
1164 header_mode = always;
1165 break;
1166
1167 default:
1168 usage(tail_usage);
1169 }
1170 }
Eric Andersen1792f8c1999-12-09 06:11:36 +00001171 }
Eric Andersen1792f8c1999-12-09 06:11:36 +00001172
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001173
Erik Andersene49d5ec2000-02-08 19:58:47 +00001174 if (n_units == -1)
1175 n_units = DEFAULT_N_LINES;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001176
Erik Andersene49d5ec2000-02-08 19:58:47 +00001177 /* To start printing with item N_UNITS from the start of the file, skip
1178 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
1179 compatibility it's treated the same as `tail +1'. */
1180 if (from_start) {
1181 if (n_units)
1182 --n_units;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001183 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001184
Erik Andersene49d5ec2000-02-08 19:58:47 +00001185 n_files = argc;
1186 file = argv;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001187
Erik Andersene49d5ec2000-02-08 19:58:47 +00001188 if (n_files > 1 && forever) {
1189 forever_multiple = 1;
1190 forever = 0;
1191 file_descs = (int *) xmalloc(n_files * sizeof(int));
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001192
Erik Andersene49d5ec2000-02-08 19:58:47 +00001193 file_sizes = (off_t *) xmalloc(n_files * sizeof(off_t));
1194 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001195
Erik Andersene49d5ec2000-02-08 19:58:47 +00001196 if (header_mode == always
1197 || (header_mode == multiple_files && n_files > 1))
1198 print_headers = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001199
Erik Andersene49d5ec2000-02-08 19:58:47 +00001200 if (n_files == 0) {
1201 exit_status |= tail_file("-", n_units, 0);
1202 } else {
1203 int i;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001204
Erik Andersene49d5ec2000-02-08 19:58:47 +00001205 for (i = 0; i < n_files; i++)
1206 exit_status |= tail_file(file[i], n_units, i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001207
Erik Andersene49d5ec2000-02-08 19:58:47 +00001208 if (forever_multiple)
1209 tail_forever(file, n_files);
1210 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001211
Erik Andersene49d5ec2000-02-08 19:58:47 +00001212 if (have_read_stdin && close(0) < 0)
1213 detailed_error(EXIT_FAILURE, errno, "-");
1214 if (fclose(stdout) == EOF)
1215 detailed_error(EXIT_FAILURE, errno, "write error");
1216 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001217}
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001218
1219
1220#endif