blob: cea63e8400b924c63fa92a6ce7ab04fcd54a3906 [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
Erik Andersen3fe39dc2000-01-25 18:13:53 +000075static void write_header(const char *filename)
76{
Erik Andersene49d5ec2000-02-08 19:58:47 +000077 static int first_file = 1;
Erik Andersen3fe39dc2000-01-25 18:13:53 +000078
Erik Andersene49d5ec2000-02-08 19:58:47 +000079 printf("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
80 first_file = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +000081}
82
83/* Print the last N_LINES lines from the end of file FD.
84 Go backward through the file, reading `BUFSIZ' bytes at a time (except
85 probably the first), until we hit the start of the file or have
86 read NUMBER newlines.
87 POS starts out as the length of the file (the offset of the last
88 byte of the file + 1).
89 Return 0 if successful, 1 if an error occurred. */
90
91static int
Eric Andersenfad04fd2000-07-14 06:49:52 +000092file_lines(int fd, long int n_lines, off_t pos)
Erik Andersen3fe39dc2000-01-25 18:13:53 +000093{
Erik Andersene49d5ec2000-02-08 19:58:47 +000094 char buffer[BUFSIZ];
95 int bytes_read;
96 int i; /* Index into `buffer' for scanning. */
Erik Andersen3fe39dc2000-01-25 18:13:53 +000097
Erik Andersene49d5ec2000-02-08 19:58:47 +000098 if (n_lines == 0)
Erik Andersen3fe39dc2000-01-25 18:13:53 +000099 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000100
Erik Andersene49d5ec2000-02-08 19:58:47 +0000101 /* Set `bytes_read' to the size of the last, probably partial, buffer;
102 0 < `bytes_read' <= `BUFSIZ'. */
103 bytes_read = pos % BUFSIZ;
104 if (bytes_read == 0)
105 bytes_read = BUFSIZ;
106 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
107 reads will be on block boundaries, which might increase efficiency. */
108 pos -= bytes_read;
109 lseek(fd, pos, SEEK_SET);
110 bytes_read = fullRead(fd, buffer, bytes_read);
111 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000112 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000113
114 /* Count the incomplete line on files that don't end with a newline. */
115 if (bytes_read && buffer[bytes_read - 1] != '\n')
116 --n_lines;
117
118 do {
119 /* Scan backward, counting the newlines in this bufferfull. */
120 for (i = bytes_read - 1; i >= 0; i--) {
121 /* Have we counted the requested number of newlines yet? */
122 if (buffer[i] == '\n' && n_lines-- == 0) {
123 /* If this newline wasn't the last character in the buffer,
124 print the text after it. */
125 if (i != bytes_read - 1)
126 XWRITE(STDOUT_FILENO, &buffer[i + 1],
127 bytes_read - (i + 1));
128 return 0;
129 }
130 }
131 /* Not enough newlines in that bufferfull. */
132 if (pos == 0) {
133 /* Not enough lines in the file; print the entire file. */
134 lseek(fd, (off_t) 0, SEEK_SET);
135 return 0;
136 }
137 pos -= BUFSIZ;
138 lseek(fd, pos, SEEK_SET);
139 }
140 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
141 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000142 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000143
144 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000145}
146
147/* Print the last N_LINES lines from the end of the standard input,
148 open for reading as pipe FD.
149 Buffer the text as a linked list of LBUFFERs, adding them as needed.
150 Return 0 if successful, 1 if an error occured. */
151
Eric Andersenfad04fd2000-07-14 06:49:52 +0000152static int pipe_lines(int fd, long int n_lines)
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000153{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000154 struct linebuffer {
155 int nbytes, nlines;
156 char buffer[BUFSIZ];
157 struct linebuffer *next;
158 };
159 typedef struct linebuffer LBUFFER;
160 LBUFFER *first, *last, *tmp;
161 int i; /* Index into buffers. */
162 int total_lines = 0; /* Total number of newlines in all buffers. */
163 int errors = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000164
Erik Andersene49d5ec2000-02-08 19:58:47 +0000165 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
166 first->nbytes = first->nlines = 0;
167 first->next = NULL;
168 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000169
Erik Andersene49d5ec2000-02-08 19:58:47 +0000170 /* Input is always read into a fresh buffer. */
171 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
172 tmp->nlines = 0;
173 tmp->next = NULL;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000174
Erik Andersene49d5ec2000-02-08 19:58:47 +0000175 /* Count the number of newlines just read. */
176 for (i = 0; i < tmp->nbytes; i++)
177 if (tmp->buffer[i] == '\n')
178 ++tmp->nlines;
179 total_lines += tmp->nlines;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000180
Erik Andersene49d5ec2000-02-08 19:58:47 +0000181 /* If there is enough room in the last buffer read, just append the new
182 one to it. This is because when reading from a pipe, `nbytes' can
183 often be very small. */
184 if (tmp->nbytes + last->nbytes < BUFSIZ) {
185 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
186 last->nbytes += tmp->nbytes;
187 last->nlines += tmp->nlines;
188 } else {
189 /* If there's not enough room, link the new buffer onto the end of
190 the list, then either free up the oldest buffer for the next
191 read if that would leave enough lines, or else malloc a new one.
192 Some compaction mechanism is possible but probably not
193 worthwhile. */
194 last = last->next = tmp;
195 if (total_lines - first->nlines > n_lines) {
196 tmp = first;
197 total_lines -= first->nlines;
198 first = first->next;
199 } else
200 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
201 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000202 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000203 if (tmp->nbytes == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000204 errorMsg("read error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000205
Erik Andersene49d5ec2000-02-08 19:58:47 +0000206 free((char *) tmp);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000207
Erik Andersene49d5ec2000-02-08 19:58:47 +0000208 /* This prevents a core dump when the pipe contains no newlines. */
209 if (n_lines == 0)
210 goto free_lbuffers;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000211
Erik Andersene49d5ec2000-02-08 19:58:47 +0000212 /* Count the incomplete line on files that don't end with a newline. */
213 if (last->buffer[last->nbytes - 1] != '\n') {
214 ++last->nlines;
215 ++total_lines;
216 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000217
Erik Andersene49d5ec2000-02-08 19:58:47 +0000218 /* Run through the list, printing lines. First, skip over unneeded
219 buffers. */
220 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
221 total_lines -= tmp->nlines;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000222
Erik Andersene49d5ec2000-02-08 19:58:47 +0000223 /* Find the correct beginning, then print the rest of the file. */
224 if (total_lines > n_lines) {
225 char *cp;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000226
Erik Andersene49d5ec2000-02-08 19:58:47 +0000227 /* Skip `total_lines' - `n_lines' newlines. We made sure that
228 `total_lines' - `n_lines' <= `tmp->nlines'. */
229 cp = tmp->buffer;
230 for (i = total_lines - n_lines; i; --i)
231 while (*cp++ != '\n')
232 /* Do nothing. */ ;
233 i = cp - tmp->buffer;
234 } else
235 i = 0;
236 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000237
Erik Andersene49d5ec2000-02-08 19:58:47 +0000238 for (tmp = tmp->next; tmp; tmp = tmp->next)
239 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000240
241 free_lbuffers:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000242 while (first) {
243 tmp = first->next;
244 free((char *) first);
245 first = tmp;
246 }
247 return errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000248}
249
250/* Display file FILENAME from the current position in FD to the end.
251 If `forever' is nonzero, keep reading from the end of the file
252 until killed. Return the number of bytes read from the file. */
253
Eric Andersenfad04fd2000-07-14 06:49:52 +0000254static long dump_remainder(int fd)
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000255{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000256 char buffer[BUFSIZ];
257 int bytes_read;
258 long total;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000259
Erik Andersene49d5ec2000-02-08 19:58:47 +0000260 total = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000261 output:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000262 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
263 XWRITE(STDOUT_FILENO, buffer, bytes_read);
264 total += bytes_read;
265 }
266 if (bytes_read == -1)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000267 errorMsg("read error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000268 if (forever) {
269 fflush(stdout);
270 sleep(1);
271 goto output;
272 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000273
Erik Andersene49d5ec2000-02-08 19:58:47 +0000274 return total;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000275}
276
277/* Output the last N_LINES lines of file FILENAME open for reading in FD.
278 Return 0 if successful, 1 if an error occurred. */
279
280static int tail_lines(const char *filename, int fd, long int n_lines)
281{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000282 struct stat stats;
283 off_t length;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000284
Erik Andersene49d5ec2000-02-08 19:58:47 +0000285 if (print_headers)
286 write_header(filename);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000287
Erik Andersene49d5ec2000-02-08 19:58:47 +0000288 if (fstat(fd, &stats))
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000289 errorMsg("fstat error");
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000290
Erik Andersene49d5ec2000-02-08 19:58:47 +0000291 /* Use file_lines only if FD refers to a regular file with
292 its file pointer positioned at beginning of file. */
293 /* FIXME: adding the lseek conjunct is a kludge.
294 Once there's a reasonable test suite, fix the true culprit:
295 file_lines. file_lines shouldn't presume that the input
296 file pointer is initially positioned to beginning of file. */
297 if (S_ISREG(stats.st_mode)
298 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
299 length = lseek(fd, (off_t) 0, SEEK_END);
Eric Andersenfad04fd2000-07-14 06:49:52 +0000300 if (length != 0 && file_lines(fd, n_lines, length))
Erik Andersene49d5ec2000-02-08 19:58:47 +0000301 return 1;
Eric Andersenfad04fd2000-07-14 06:49:52 +0000302 dump_remainder(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000303 } else
Eric Andersenfad04fd2000-07-14 06:49:52 +0000304 return pipe_lines(fd, n_lines);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000305
Erik Andersene49d5ec2000-02-08 19:58:47 +0000306 return 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000307}
308
309/* Display the last N_UNITS lines of file FILENAME.
310 "-" for FILENAME means the standard input.
311 Return 0 if successful, 1 if an error occurred. */
312
313static int tail_file(const char *filename, off_t n_units)
314{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000315 int fd, errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000316
Erik Andersene49d5ec2000-02-08 19:58:47 +0000317 if (!strcmp(filename, "-")) {
318 filename = "standard input";
319 errors = tail_lines(filename, 0, (long) n_units);
320 } else {
321 /* Not standard input. */
322 fd = open(filename, O_RDONLY);
323 if (fd == -1)
Eric Andersen86ab8a32000-06-02 03:21:42 +0000324 perror(filename);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000325
Erik Andersene49d5ec2000-02-08 19:58:47 +0000326 errors = tail_lines(filename, fd, (long) n_units);
327 close(fd);
328 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000329
Erik Andersene49d5ec2000-02-08 19:58:47 +0000330 return errors;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000331}
332
333extern int tail_main(int argc, char **argv)
334{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000335 int exit_status = 0;
336 int n_units = DEFAULT_N_LINES;
337 int n_tmp, i;
338 char opt;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000339
Erik Andersene49d5ec2000-02-08 19:58:47 +0000340 forever = print_headers = 0;
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000341
Erik Andersene49d5ec2000-02-08 19:58:47 +0000342 /* parse argv[] */
343 for (i = 1; i < argc; i++) {
344 if (argv[i][0] == '-') {
345 opt = argv[i][1];
346 switch (opt) {
347 case 'f':
348 forever = 1;
349 break;
350 case 'n':
351 n_tmp = 0;
352 if (++i < argc)
353 n_tmp = atoi(argv[i]);
354 if (n_tmp < 1)
355 usage(tail_usage);
356 n_units = n_tmp;
357 break;
358 case '-':
359 case 'h':
360 usage(tail_usage);
361 default:
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000362 if ((n_units = atoi(&argv[i][1])) < 1) {
Matt Kraaid537a952000-07-14 01:51:25 +0000363 errorMsg("invalid option -- %c\n", opt);
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000364 usage(tail_usage);
365 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000366 }
367 } else {
368 break;
369 }
370 }
371
372 if (i + 1 < argc) {
373 if (forever) {
Matt Kraaid537a952000-07-14 01:51:25 +0000374 errorMsg("option -f is invalid with multiple files\n");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000375 usage(tail_usage);
376 }
377 print_headers = 1;
378 }
379
380 if (i >= argc) {
381 exit_status |= tail_file("-", n_units);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000382 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000383 for (; i < argc; i++)
384 exit_status |= tail_file(argv[i], n_units);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000385 }
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000386
Eric Andersenb6106152000-06-19 17:25:40 +0000387 return(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000388}
389
390
391#else
392// Here follows the code for the full featured tail code
393
394
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000395/* tail -- output the last part of file(s)
396 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
397
398 This program is free software; you can redistribute it and/or modify
399 it under the terms of the GNU General Public License as published by
400 the Free Software Foundation; either version 2, or (at your option)
401 any later version.
402
403 This program is distributed in the hope that it will be useful,
404 but WITHOUT ANY WARRANTY; without even the implied warranty of
405 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
406 GNU General Public License for more details.
407
408 You should have received a copy of the GNU General Public License
409 along with this program; if not, write to the Free Software
Eric Andersen1792f8c1999-12-09 06:11:36 +0000410 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000411
412 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
413 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
Eric Andersen1792f8c1999-12-09 06:11:36 +0000414 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
415
416 Rewrote the option parser, removed locales support,
417 and generally busyboxed, Erik Andersen <andersen@lineo.com>
418
419 */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000420
421#include "internal.h"
422
423#include <stdio.h>
Erik Andersen4d1d0111999-12-17 18:44:15 +0000424#include <stdarg.h>
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000425#include <assert.h>
426#include <errno.h>
427#include <sys/types.h>
Eric Andersen1792f8c1999-12-09 06:11:36 +0000428#include <sys/types.h>
429#include <sys/stat.h>
430#include <fcntl.h>
431#include <ctype.h>
432
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000433
434
435/* Disable assertions. Some systems have broken assert macros. */
436#define NDEBUG 1
437
438
Erik Andersene49d5ec2000-02-08 19:58:47 +0000439static void detailed_error(int i, int errnum, char *fmt, ...)
Erik Andersen93d65132000-04-06 08:06:36 +0000440 __attribute__ ((format (printf, 3, 4)));
441static void detailed_error(int i, int errnum, char *fmt, ...)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000442{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000443 va_list arguments;
Eric Andersen1792f8c1999-12-09 06:11:36 +0000444
Erik Andersene49d5ec2000-02-08 19:58:47 +0000445 va_start(arguments, fmt);
446 vfprintf(stderr, fmt, arguments);
447 fprintf(stderr, "\n%s\n", strerror(errnum));
448 va_end(arguments);
449 exit(i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000450}
451
452
453#define XWRITE(fd, buffer, n_bytes) \
454 do \
455 { \
456 assert ((fd) == 1); \
457 assert ((n_bytes) >= 0); \
458 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
Erik Andersen3fe39dc2000-01-25 18:13:53 +0000459 detailed_error (EXIT_FAILURE, errno, "write error"); \
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000460 } \
461 while (0)
462
463/* Number of items to tail. */
464#define DEFAULT_N_LINES 10
465
466/* Size of atomic reads. */
467#ifndef BUFSIZ
468#define BUFSIZ (512 * 8)
469#endif
470
471/* If nonzero, interpret the numeric argument as the number of lines.
472 Otherwise, interpret it as the number of bytes. */
473static int count_lines;
474
475/* If nonzero, read from the end of one file until killed. */
476static int forever;
477
478/* If nonzero, read from the end of multiple files until killed. */
479static int forever_multiple;
480
481/* Array of file descriptors if forever_multiple is 1. */
482static int *file_descs;
483
484/* Array of file sizes if forever_multiple is 1. */
485static off_t *file_sizes;
486
487/* If nonzero, count from start of file instead of end. */
488static int from_start;
489
490/* If nonzero, print filename headers. */
491static int print_headers;
492
493/* When to print the filename banners. */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000494enum header_mode {
495 multiple_files, always, never
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000496};
497
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000498/* The name this program was run with. */
499char *program_name;
500
501/* Nonzero if we have ever read standard input. */
502static int have_read_stdin;
503
Erik Andersene49d5ec2000-02-08 19:58:47 +0000504static void write_header(const char *filename, const char *comment)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000505{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000506 static int first_file = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000507
Erik Andersene49d5ec2000-02-08 19:58:47 +0000508 printf("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
509 (comment ? ": " : ""), (comment ? comment : ""));
510 first_file = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000511}
512
513/* Print the last N_LINES lines from the end of file FD.
514 Go backward through the file, reading `BUFSIZ' bytes at a time (except
515 probably the first), until we hit the start of the file or have
516 read NUMBER newlines.
517 POS starts out as the length of the file (the offset of the last
518 byte of the file + 1).
519 Return 0 if successful, 1 if an error occurred. */
520
521static int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000522file_lines(const char *filename, int fd, long int n_lines, off_t pos)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000523{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000524 char buffer[BUFSIZ];
525 int bytes_read;
526 int i; /* Index into `buffer' for scanning. */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000527
Erik Andersene49d5ec2000-02-08 19:58:47 +0000528 if (n_lines == 0)
529 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000530
Erik Andersene49d5ec2000-02-08 19:58:47 +0000531 /* Set `bytes_read' to the size of the last, probably partial, buffer;
532 0 < `bytes_read' <= `BUFSIZ'. */
533 bytes_read = pos % BUFSIZ;
534 if (bytes_read == 0)
535 bytes_read = BUFSIZ;
536 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
537 reads will be on block boundaries, which might increase efficiency. */
538 pos -= bytes_read;
539 lseek(fd, pos, SEEK_SET);
540 bytes_read = fullRead(fd, buffer, bytes_read);
541 if (bytes_read == -1) {
542 detailed_error(0, errno, "%s", filename);
543 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000544 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000545
546 /* Count the incomplete line on files that don't end with a newline. */
547 if (bytes_read && buffer[bytes_read - 1] != '\n')
548 --n_lines;
549
550 do {
551 /* Scan backward, counting the newlines in this bufferfull. */
552 for (i = bytes_read - 1; i >= 0; i--) {
553 /* Have we counted the requested number of newlines yet? */
554 if (buffer[i] == '\n' && n_lines-- == 0) {
555 /* If this newline wasn't the last character in the buffer,
556 print the text after it. */
557 if (i != bytes_read - 1)
558 XWRITE(STDOUT_FILENO, &buffer[i + 1],
559 bytes_read - (i + 1));
560 return 0;
561 }
562 }
563 /* Not enough newlines in that bufferfull. */
564 if (pos == 0) {
565 /* Not enough lines in the file; print the entire file. */
566 lseek(fd, (off_t) 0, SEEK_SET);
567 return 0;
568 }
569 pos -= BUFSIZ;
570 lseek(fd, pos, SEEK_SET);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000571 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000572 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0);
573 if (bytes_read == -1) {
574 detailed_error(0, errno, "%s", filename);
575 return 1;
576 }
577 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000578}
579
580/* Print the last N_LINES lines from the end of the standard input,
581 open for reading as pipe FD.
582 Buffer the text as a linked list of LBUFFERs, adding them as needed.
583 Return 0 if successful, 1 if an error occured. */
584
Eric Andersenfad04fd2000-07-14 06:49:52 +0000585static int pipe_lines(int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000586{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000587 struct linebuffer {
588 int nbytes, nlines;
589 char buffer[BUFSIZ];
590 struct linebuffer *next;
591 };
592 typedef struct linebuffer LBUFFER;
593 LBUFFER *first, *last, *tmp;
594 int i; /* Index into buffers. */
595 int total_lines = 0; /* Total number of newlines in all buffers. */
596 int errors = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000597
Erik Andersene49d5ec2000-02-08 19:58:47 +0000598 first = last = (LBUFFER *) xmalloc(sizeof(LBUFFER));
599 first->nbytes = first->nlines = 0;
600 first->next = NULL;
601 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000602
Erik Andersene49d5ec2000-02-08 19:58:47 +0000603 /* Input is always read into a fresh buffer. */
604 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
605 tmp->nlines = 0;
606 tmp->next = NULL;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000607
Erik Andersene49d5ec2000-02-08 19:58:47 +0000608 /* Count the number of newlines just read. */
609 for (i = 0; i < tmp->nbytes; i++)
610 if (tmp->buffer[i] == '\n')
611 ++tmp->nlines;
612 total_lines += tmp->nlines;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000613
Erik Andersene49d5ec2000-02-08 19:58:47 +0000614 /* If there is enough room in the last buffer read, just append the new
615 one to it. This is because when reading from a pipe, `nbytes' can
616 often be very small. */
617 if (tmp->nbytes + last->nbytes < BUFSIZ) {
618 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
619 last->nbytes += tmp->nbytes;
620 last->nlines += tmp->nlines;
621 } else {
622 /* If there's not enough room, link the new buffer onto the end of
623 the list, then either free up the oldest buffer for the next
624 read if that would leave enough lines, or else malloc a new one.
625 Some compaction mechanism is possible but probably not
626 worthwhile. */
627 last = last->next = tmp;
628 if (total_lines - first->nlines > n_lines) {
629 tmp = first;
630 total_lines -= first->nlines;
631 first = first->next;
632 } else
633 tmp = (LBUFFER *) xmalloc(sizeof(LBUFFER));
634 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000635 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000636 if (tmp->nbytes == -1) {
637 detailed_error(0, errno, "%s", filename);
638 errors = 1;
639 free((char *) tmp);
640 goto free_lbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000641 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000642
Erik Andersene49d5ec2000-02-08 19:58:47 +0000643 free((char *) tmp);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000644
Erik Andersene49d5ec2000-02-08 19:58:47 +0000645 /* This prevents a core dump when the pipe contains no newlines. */
646 if (n_lines == 0)
647 goto free_lbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000648
Erik Andersene49d5ec2000-02-08 19:58:47 +0000649 /* Count the incomplete line on files that don't end with a newline. */
650 if (last->buffer[last->nbytes - 1] != '\n') {
651 ++last->nlines;
652 ++total_lines;
653 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000654
Erik Andersene49d5ec2000-02-08 19:58:47 +0000655 /* Run through the list, printing lines. First, skip over unneeded
656 buffers. */
657 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
658 total_lines -= tmp->nlines;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000659
Erik Andersene49d5ec2000-02-08 19:58:47 +0000660 /* Find the correct beginning, then print the rest of the file. */
661 if (total_lines > n_lines) {
662 char *cp;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000663
Erik Andersene49d5ec2000-02-08 19:58:47 +0000664 /* Skip `total_lines' - `n_lines' newlines. We made sure that
665 `total_lines' - `n_lines' <= `tmp->nlines'. */
666 cp = tmp->buffer;
667 for (i = total_lines - n_lines; i; --i)
668 while (*cp++ != '\n')
669 /* Do nothing. */ ;
670 i = cp - tmp->buffer;
671 } else
672 i = 0;
673 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000674
Erik Andersene49d5ec2000-02-08 19:58:47 +0000675 for (tmp = tmp->next; tmp; tmp = tmp->next)
676 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000677
Erik Andersene49d5ec2000-02-08 19:58:47 +0000678 free_lbuffers:
679 while (first) {
680 tmp = first->next;
681 free((char *) first);
682 first = tmp;
683 }
684 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000685}
686
687/* Print the last N_BYTES characters from the end of pipe FD.
688 This is a stripped down version of pipe_lines.
689 Return 0 if successful, 1 if an error occurred. */
690
Erik Andersene49d5ec2000-02-08 19:58:47 +0000691static int pipe_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000692{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000693 struct charbuffer {
694 int nbytes;
695 char buffer[BUFSIZ];
696 struct charbuffer *next;
697 };
698 typedef struct charbuffer CBUFFER;
699 CBUFFER *first, *last, *tmp;
700 int i; /* Index into buffers. */
701 int total_bytes = 0; /* Total characters in all buffers. */
702 int errors = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000703
Erik Andersene49d5ec2000-02-08 19:58:47 +0000704 first = last = (CBUFFER *) xmalloc(sizeof(CBUFFER));
705 first->nbytes = 0;
706 first->next = NULL;
707 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000708
Erik Andersene49d5ec2000-02-08 19:58:47 +0000709 /* Input is always read into a fresh buffer. */
710 while ((tmp->nbytes = fullRead(fd, tmp->buffer, BUFSIZ)) > 0) {
711 tmp->next = NULL;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000712
Erik Andersene49d5ec2000-02-08 19:58:47 +0000713 total_bytes += tmp->nbytes;
714 /* If there is enough room in the last buffer read, just append the new
715 one to it. This is because when reading from a pipe, `nbytes' can
716 often be very small. */
717 if (tmp->nbytes + last->nbytes < BUFSIZ) {
718 memcpy(&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
719 last->nbytes += tmp->nbytes;
720 } else {
721 /* If there's not enough room, link the new buffer onto the end of
722 the list, then either free up the oldest buffer for the next
723 read if that would leave enough characters, or else malloc a new
724 one. Some compaction mechanism is possible but probably not
725 worthwhile. */
726 last = last->next = tmp;
727 if (total_bytes - first->nbytes > n_bytes) {
728 tmp = first;
729 total_bytes -= first->nbytes;
730 first = first->next;
731 } else {
732 tmp = (CBUFFER *) xmalloc(sizeof(CBUFFER));
733 }
734 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000735 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000736 if (tmp->nbytes == -1) {
737 detailed_error(0, errno, "%s", filename);
738 errors = 1;
739 free((char *) tmp);
740 goto free_cbuffers;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000741 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000742
Erik Andersene49d5ec2000-02-08 19:58:47 +0000743 free((char *) tmp);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000744
Erik Andersene49d5ec2000-02-08 19:58:47 +0000745 /* Run through the list, printing characters. First, skip over unneeded
746 buffers. */
747 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
748 total_bytes -= tmp->nbytes;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000749
Erik Andersene49d5ec2000-02-08 19:58:47 +0000750 /* Find the correct beginning, then print the rest of the file.
751 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
752 if (total_bytes > n_bytes)
753 i = total_bytes - n_bytes;
754 else
755 i = 0;
756 XWRITE(STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000757
Erik Andersene49d5ec2000-02-08 19:58:47 +0000758 for (tmp = tmp->next; tmp; tmp = tmp->next)
759 XWRITE(STDOUT_FILENO, tmp->buffer, tmp->nbytes);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000760
Erik Andersene49d5ec2000-02-08 19:58:47 +0000761 free_cbuffers:
762 while (first) {
763 tmp = first->next;
764 free((char *) first);
765 first = tmp;
766 }
767 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000768}
769
770/* Skip N_BYTES characters from the start of pipe FD, and print
771 any extra characters that were read beyond that.
772 Return 1 on error, 0 if ok. */
773
Erik Andersene49d5ec2000-02-08 19:58:47 +0000774static int start_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000775{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000776 char buffer[BUFSIZ];
777 int bytes_read = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000778
Erik Andersene49d5ec2000-02-08 19:58:47 +0000779 while (n_bytes > 0 && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0)
780 n_bytes -= bytes_read;
781 if (bytes_read == -1) {
782 detailed_error(0, errno, "%s", filename);
783 return 1;
784 } else if (n_bytes < 0)
785 XWRITE(STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
786 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000787}
788
789/* Skip N_LINES lines at the start of file or pipe FD, and print
790 any extra characters that were read beyond that.
791 Return 1 on error, 0 if ok. */
792
Erik Andersene49d5ec2000-02-08 19:58:47 +0000793static int start_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000794{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000795 char buffer[BUFSIZ];
796 int bytes_read = 0;
797 int bytes_to_skip = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000798
Erik Andersene49d5ec2000-02-08 19:58:47 +0000799 while (n_lines && (bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
800 bytes_to_skip = 0;
801 while (bytes_to_skip < bytes_read)
802 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
803 break;
804 }
805 if (bytes_read == -1) {
806 detailed_error(0, errno, "%s", filename);
807 return 1;
808 } else if (bytes_to_skip < bytes_read) {
809 XWRITE(STDOUT_FILENO, &buffer[bytes_to_skip],
810 bytes_read - bytes_to_skip);
811 }
812 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000813}
814
815/* Display file FILENAME from the current position in FD to the end.
816 If `forever' is nonzero, keep reading from the end of the file
817 until killed. Return the number of bytes read from the file. */
818
Eric Andersenfad04fd2000-07-14 06:49:52 +0000819static long dump_remainder(int fd)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000820{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000821 char buffer[BUFSIZ];
822 int bytes_read;
823 long total;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000824
Erik Andersene49d5ec2000-02-08 19:58:47 +0000825 total = 0;
826 output:
827 while ((bytes_read = fullRead(fd, buffer, BUFSIZ)) > 0) {
828 XWRITE(STDOUT_FILENO, buffer, bytes_read);
829 total += bytes_read;
830 }
831 if (bytes_read == -1)
832 detailed_error(EXIT_FAILURE, errno, "%s", filename);
833 if (forever) {
834 fflush(stdout);
835 sleep(1);
836 goto output;
837 } else {
838 if (forever_multiple)
839 fflush(stdout);
840 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000841
Erik Andersene49d5ec2000-02-08 19:58:47 +0000842 return total;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000843}
844
845/* Tail NFILES (>1) files forever until killed. The file names are in
846 NAMES. The open file descriptors are in `file_descs', and the size
847 at which we stopped tailing them is in `file_sizes'. We loop over
848 each of them, doing an fstat to see if they have changed size. If
849 none of them have changed size in one iteration, we sleep for a
850 second and try again. We do this until the user interrupts us. */
851
Erik Andersene49d5ec2000-02-08 19:58:47 +0000852static void tail_forever(char **names, int nfiles)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000853{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000854 int last;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000855
Erik Andersene49d5ec2000-02-08 19:58:47 +0000856 last = -1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000857
Erik Andersene49d5ec2000-02-08 19:58:47 +0000858 while (1) {
859 int i;
860 int changed;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000861
Erik Andersene49d5ec2000-02-08 19:58:47 +0000862 changed = 0;
863 for (i = 0; i < nfiles; i++) {
864 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000865
Erik Andersene49d5ec2000-02-08 19:58:47 +0000866 if (file_descs[i] < 0)
867 continue;
868 if (fstat(file_descs[i], &stats) < 0) {
869 detailed_error(0, errno, "%s", names[i]);
870 file_descs[i] = -1;
871 continue;
872 }
873 if (stats.st_size == file_sizes[i])
874 continue;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000875
Erik Andersene49d5ec2000-02-08 19:58:47 +0000876 /* This file has changed size. Print out what we can, and
877 then keep looping. */
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000878
Erik Andersene49d5ec2000-02-08 19:58:47 +0000879 changed = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000880
Erik Andersene49d5ec2000-02-08 19:58:47 +0000881 if (stats.st_size < file_sizes[i]) {
882 write_header(names[i], "file truncated");
883 last = i;
884 lseek(file_descs[i], stats.st_size, SEEK_SET);
885 file_sizes[i] = stats.st_size;
886 continue;
887 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000888
Erik Andersene49d5ec2000-02-08 19:58:47 +0000889 if (i != last) {
890 if (print_headers)
891 write_header(names[i], NULL);
892 last = i;
893 }
Eric Andersenfad04fd2000-07-14 06:49:52 +0000894 file_sizes[i] += dump_remainder(file_descs[i]);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000895 }
896
897 /* If none of the files changed size, sleep. */
898 if (!changed)
899 sleep(1);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000900 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000901}
902
903/* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
904 Return 0 if successful, 1 if an error occurred. */
905
Erik Andersene49d5ec2000-02-08 19:58:47 +0000906static int tail_bytes(const char *filename, int fd, off_t n_bytes)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000907{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000908 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000909
Erik Andersene49d5ec2000-02-08 19:58:47 +0000910 /* FIXME: resolve this like in dd.c. */
911 /* Use fstat instead of checking for errno == ESPIPE because
912 lseek doesn't work on some special files but doesn't return an
913 error, either. */
914 if (fstat(fd, &stats)) {
915 detailed_error(0, errno, "%s", filename);
916 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000917 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000918
919 if (from_start) {
920 if (S_ISREG(stats.st_mode))
921 lseek(fd, n_bytes, SEEK_CUR);
922 else if (start_bytes(filename, fd, n_bytes))
923 return 1;
Eric Andersenfad04fd2000-07-14 06:49:52 +0000924 dump_remainder(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000925 } else {
926 if (S_ISREG(stats.st_mode)) {
927 off_t current_pos, end_pos;
928 size_t bytes_remaining;
929
930 if ((current_pos = lseek(fd, (off_t) 0, SEEK_CUR)) != -1
931 && (end_pos = lseek(fd, (off_t) 0, SEEK_END)) != -1) {
932 off_t diff;
933
934 /* Be careful here. The current position may actually be
935 beyond the end of the file. */
936 bytes_remaining = (diff =
937 end_pos - current_pos) < 0 ? 0 : diff;
938 } else {
939 detailed_error(0, errno, "%s", filename);
940 return 1;
941 }
942
943 if (bytes_remaining <= n_bytes) {
944 /* From the current position to end of file, there are no
945 more bytes than have been requested. So reposition the
946 file pointer to the incoming current position and print
947 everything after that. */
948 lseek(fd, current_pos, SEEK_SET);
949 } else {
950 /* There are more bytes remaining than were requested.
951 Back up. */
952 lseek(fd, -n_bytes, SEEK_END);
953 }
954 dump_remainder(filename, fd);
955 } else
956 return pipe_bytes(filename, fd, n_bytes);
957 }
958 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000959}
960
961/* Output the last N_LINES lines of file FILENAME open for reading in FD.
962 Return 0 if successful, 1 if an error occurred. */
963
Erik Andersene49d5ec2000-02-08 19:58:47 +0000964static int tail_lines(const char *filename, int fd, long int n_lines)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000965{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000966 struct stat stats;
967 off_t length;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000968
Erik Andersene49d5ec2000-02-08 19:58:47 +0000969 if (fstat(fd, &stats)) {
970 detailed_error(0, errno, "%s", filename);
971 return 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000972 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000973
974 if (from_start) {
975 if (start_lines(filename, fd, n_lines))
976 return 1;
977 dump_remainder(filename, fd);
978 } else {
979 /* Use file_lines only if FD refers to a regular file with
980 its file pointer positioned at beginning of file. */
981 /* FIXME: adding the lseek conjunct is a kludge.
982 Once there's a reasonable test suite, fix the true culprit:
983 file_lines. file_lines shouldn't presume that the input
984 file pointer is initially positioned to beginning of file. */
985 if (S_ISREG(stats.st_mode)
986 && lseek(fd, (off_t) 0, SEEK_CUR) == (off_t) 0) {
987 length = lseek(fd, (off_t) 0, SEEK_END);
988 if (length != 0 && file_lines(filename, fd, n_lines, length))
989 return 1;
Eric Andersenfad04fd2000-07-14 06:49:52 +0000990 dump_remainder(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000991 } else
Eric Andersenfad04fd2000-07-14 06:49:52 +0000992 return pipe_lines(fd, n_lines);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000993 }
994 return 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000995}
996
997/* Display the last N_UNITS units of file FILENAME, open for reading
998 in FD.
999 Return 0 if successful, 1 if an error occurred. */
1000
Erik Andersene49d5ec2000-02-08 19:58:47 +00001001static int tail(const char *filename, int fd, off_t n_units)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001002{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001003 if (count_lines)
1004 return tail_lines(filename, fd, (long) n_units);
1005 else
1006 return tail_bytes(filename, fd, n_units);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001007}
1008
1009/* Display the last N_UNITS units of file FILENAME.
1010 "-" for FILENAME means the standard input.
1011 FILENUM is this file's index in the list of files the user gave.
1012 Return 0 if successful, 1 if an error occurred. */
1013
Erik Andersene49d5ec2000-02-08 19:58:47 +00001014static int tail_file(const char *filename, off_t n_units, int filenum)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001015{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001016 int fd, errors;
1017 struct stat stats;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001018
Erik Andersene49d5ec2000-02-08 19:58:47 +00001019 if (!strcmp(filename, "-")) {
1020 have_read_stdin = 1;
1021 filename = "standard input";
1022 if (print_headers)
1023 write_header(filename, NULL);
1024 errors = tail(filename, 0, n_units);
1025 if (forever_multiple) {
1026 if (fstat(0, &stats) < 0) {
1027 detailed_error(0, errno, "standard input");
1028 errors = 1;
1029 } else if (!S_ISREG(stats.st_mode)) {
1030 detailed_error(0, 0,
1031 "standard input: cannot follow end of non-regular file");
1032 errors = 1;
1033 }
1034 if (errors)
1035 file_descs[filenum] = -1;
1036 else {
1037 file_descs[filenum] = 0;
1038 file_sizes[filenum] = stats.st_size;
1039 }
1040 }
1041 } else {
1042 /* Not standard input. */
1043 fd = open(filename, O_RDONLY);
1044 if (fd == -1) {
1045 if (forever_multiple)
1046 file_descs[filenum] = -1;
1047 detailed_error(0, errno, "%s", filename);
1048 errors = 1;
1049 } else {
1050 if (print_headers)
1051 write_header(filename, NULL);
1052 errors = tail(filename, fd, n_units);
1053 if (forever_multiple) {
1054 if (fstat(fd, &stats) < 0) {
1055 detailed_error(0, errno, "%s", filename);
1056 errors = 1;
1057 } else if (!S_ISREG(stats.st_mode)) {
1058 detailed_error(0, 0,
1059 "%s: cannot follow end of non-regular file",
1060 filename);
1061 errors = 1;
1062 }
1063 if (errors) {
1064 close(fd);
1065 file_descs[filenum] = -1;
1066 } else {
1067 file_descs[filenum] = fd;
1068 file_sizes[filenum] = stats.st_size;
1069 }
1070 } else {
1071 if (close(fd)) {
1072 detailed_error(0, errno, "%s", filename);
1073 errors = 1;
1074 }
1075 }
1076 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001077 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001078
Erik Andersene49d5ec2000-02-08 19:58:47 +00001079 return errors;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001080}
1081
Erik Andersene49d5ec2000-02-08 19:58:47 +00001082extern int tail_main(int argc, char **argv)
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001083{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001084 int stopit = 0;
1085 enum header_mode header_mode = multiple_files;
1086 int exit_status = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001087
Erik Andersene49d5ec2000-02-08 19:58:47 +00001088 /* If from_start, the number of items to skip before printing; otherwise,
1089 the number of items at the end of the file to print. Initially, -1
1090 means the value has not been set. */
1091 off_t n_units = -1;
1092 int n_files;
1093 char **file;
1094
1095 program_name = argv[0];
1096 have_read_stdin = 0;
1097 count_lines = 1;
1098 forever = forever_multiple = from_start = print_headers = 0;
1099
1100 /* Parse any options */
1101 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
1102 while (--argc > 0 && (**(++argv) == '-' || **argv == '+')) {
1103 if (**argv == '+') {
1104 from_start = 1;
1105 }
1106 stopit = 0;
1107 while (stopit == 0 && *(++(*argv))) {
1108 switch (**argv) {
1109 case 'c':
1110 count_lines = 0;
1111
1112 if (--argc < 1) {
1113 usage(tail_usage);
1114 }
1115 n_units = getNum(*(++argv));
1116 stopit = 1;
1117 break;
1118
1119 case 'f':
1120 forever = 1;
1121 break;
1122
1123 case 'n':
1124 count_lines = 1;
1125
1126 if (--argc < 1) {
1127 usage(tail_usage);
1128 }
1129 n_units = atol(*(++argv));
1130 stopit = 1;
1131 break;
1132
1133 case 'q':
1134 header_mode = never;
1135 break;
1136
1137 case 'v':
1138 header_mode = always;
1139 break;
1140
1141 default:
1142 usage(tail_usage);
1143 }
1144 }
Eric Andersen1792f8c1999-12-09 06:11:36 +00001145 }
Eric Andersen1792f8c1999-12-09 06:11:36 +00001146
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001147
Erik Andersene49d5ec2000-02-08 19:58:47 +00001148 if (n_units == -1)
1149 n_units = DEFAULT_N_LINES;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001150
Erik Andersene49d5ec2000-02-08 19:58:47 +00001151 /* To start printing with item N_UNITS from the start of the file, skip
1152 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
1153 compatibility it's treated the same as `tail +1'. */
1154 if (from_start) {
1155 if (n_units)
1156 --n_units;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001157 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001158
Erik Andersene49d5ec2000-02-08 19:58:47 +00001159 n_files = argc;
1160 file = argv;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001161
Erik Andersene49d5ec2000-02-08 19:58:47 +00001162 if (n_files > 1 && forever) {
1163 forever_multiple = 1;
1164 forever = 0;
1165 file_descs = (int *) xmalloc(n_files * sizeof(int));
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001166
Erik Andersene49d5ec2000-02-08 19:58:47 +00001167 file_sizes = (off_t *) xmalloc(n_files * sizeof(off_t));
1168 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001169
Erik Andersene49d5ec2000-02-08 19:58:47 +00001170 if (header_mode == always
1171 || (header_mode == multiple_files && n_files > 1))
1172 print_headers = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001173
Erik Andersene49d5ec2000-02-08 19:58:47 +00001174 if (n_files == 0) {
1175 exit_status |= tail_file("-", n_units, 0);
1176 } else {
1177 int i;
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001178
Erik Andersene49d5ec2000-02-08 19:58:47 +00001179 for (i = 0; i < n_files; i++)
1180 exit_status |= tail_file(file[i], n_units, i);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001181
Erik Andersene49d5ec2000-02-08 19:58:47 +00001182 if (forever_multiple)
1183 tail_forever(file, n_files);
1184 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001185
Erik Andersene49d5ec2000-02-08 19:58:47 +00001186 if (have_read_stdin && close(0) < 0)
1187 detailed_error(EXIT_FAILURE, errno, "-");
1188 if (fclose(stdout) == EOF)
1189 detailed_error(EXIT_FAILURE, errno, "write error");
1190 exit(exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001191}
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001192
1193
1194#endif