blob: 697177dc7b611203828f6fc44e91c2b1083d4b05 [file] [log] [blame]
Eric Andersenabc0f4f1999-12-08 23:19:36 +00001/* tail -- output the last part of file(s)
2 Copyright (C) 89, 90, 91, 95, 1996 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
Eric Andersen1792f8c1999-12-09 06:11:36 +000016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Eric Andersenabc0f4f1999-12-08 23:19:36 +000017
18 Original version by Paul Rubin <phr@ocf.berkeley.edu>.
19 Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
Eric Andersen1792f8c1999-12-09 06:11:36 +000020 tail -f for multiple files by Ian Lance Taylor <ian@airs.com>.
21
22 Rewrote the option parser, removed locales support,
23 and generally busyboxed, Erik Andersen <andersen@lineo.com>
24
25 */
Eric Andersenabc0f4f1999-12-08 23:19:36 +000026
27#include "internal.h"
28
29#include <stdio.h>
Erik Andersen4d1d0111999-12-17 18:44:15 +000030#include <stdarg.h>
Eric Andersenabc0f4f1999-12-08 23:19:36 +000031#include <assert.h>
32#include <errno.h>
33#include <sys/types.h>
Eric Andersen1792f8c1999-12-09 06:11:36 +000034#include <sys/types.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37#include <ctype.h>
38
Eric Andersenabc0f4f1999-12-08 23:19:36 +000039
40
41/* Disable assertions. Some systems have broken assert macros. */
42#define NDEBUG 1
43
44
Eric Andersen1792f8c1999-12-09 06:11:36 +000045static void error(int i, int errnum, char* fmt, ...)
Eric Andersenabc0f4f1999-12-08 23:19:36 +000046{
Eric Andersen1792f8c1999-12-09 06:11:36 +000047 va_list arguments;
48
49 va_start(arguments, fmt);
50 vfprintf(stderr, fmt, arguments);
51 fprintf(stderr, "\n%s\n", strerror( errnum));
52 va_end(arguments);
Eric Andersenabc0f4f1999-12-08 23:19:36 +000053 exit(i);
54}
55
56
57#define XWRITE(fd, buffer, n_bytes) \
58 do \
59 { \
60 assert ((fd) == 1); \
61 assert ((n_bytes) >= 0); \
62 if (n_bytes > 0 && fwrite ((buffer), 1, (n_bytes), stdout) == 0) \
Eric Andersen1792f8c1999-12-09 06:11:36 +000063 error (EXIT_FAILURE, errno, "write error"); \
Eric Andersenabc0f4f1999-12-08 23:19:36 +000064 } \
65 while (0)
66
67/* Number of items to tail. */
68#define DEFAULT_N_LINES 10
69
70/* Size of atomic reads. */
71#ifndef BUFSIZ
72#define BUFSIZ (512 * 8)
73#endif
74
75/* If nonzero, interpret the numeric argument as the number of lines.
76 Otherwise, interpret it as the number of bytes. */
77static int count_lines;
78
79/* If nonzero, read from the end of one file until killed. */
80static int forever;
81
82/* If nonzero, read from the end of multiple files until killed. */
83static int forever_multiple;
84
85/* Array of file descriptors if forever_multiple is 1. */
86static int *file_descs;
87
88/* Array of file sizes if forever_multiple is 1. */
89static off_t *file_sizes;
90
91/* If nonzero, count from start of file instead of end. */
92static int from_start;
93
94/* If nonzero, print filename headers. */
95static int print_headers;
96
97/* When to print the filename banners. */
98enum header_mode
99{
100 multiple_files, always, never
101};
102
103char *xmalloc ();
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000104
105/* The name this program was run with. */
106char *program_name;
107
108/* Nonzero if we have ever read standard input. */
109static int have_read_stdin;
110
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000111
112static const char tail_usage[] =
113"tail [OPTION]... [FILE]...\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000114\n\
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000115Print last 10 lines of each FILE to standard output.\n\
116With more than one FILE, precede each with a header giving the file name.\n\
117With no FILE, or when FILE is -, read standard input.\n\
118\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000119 -c=N[kbm] output the last N bytes\n\
120 -f output appended data as the file grows\n\
121 -n=N output the last N lines, instead of last 10\n\
122 -q never output headers giving file names\n\
123 -v always output headers giving file names\n\
124 --help display this help and exit\n\
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000125\n\
Eric Andersen1792f8c1999-12-09 06:11:36 +0000126If the first character of N (bytes or lines) is a `+', output begins with \n\
127the Nth item from the start of each file, otherwise, print the last N items\n\
128in 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 +0000129
130static void
131write_header (const char *filename, const char *comment)
132{
133 static int first_file = 1;
134
135 printf ("%s==> %s%s%s <==\n", (first_file ? "" : "\n"), filename,
136 (comment ? ": " : ""),
137 (comment ? comment : ""));
138 first_file = 0;
139}
140
141/* Print the last N_LINES lines from the end of file FD.
142 Go backward through the file, reading `BUFSIZ' bytes at a time (except
143 probably the first), until we hit the start of the file or have
144 read NUMBER newlines.
145 POS starts out as the length of the file (the offset of the last
146 byte of the file + 1).
147 Return 0 if successful, 1 if an error occurred. */
148
149static int
150file_lines (const char *filename, int fd, long int n_lines, off_t pos)
151{
152 char buffer[BUFSIZ];
153 int bytes_read;
154 int i; /* Index into `buffer' for scanning. */
155
156 if (n_lines == 0)
157 return 0;
158
159 /* Set `bytes_read' to the size of the last, probably partial, buffer;
160 0 < `bytes_read' <= `BUFSIZ'. */
161 bytes_read = pos % BUFSIZ;
162 if (bytes_read == 0)
163 bytes_read = BUFSIZ;
164 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
165 reads will be on block boundaries, which might increase efficiency. */
166 pos -= bytes_read;
167 lseek (fd, pos, SEEK_SET);
Eric Andersen1792f8c1999-12-09 06:11:36 +0000168 bytes_read = fullRead (fd, buffer, bytes_read);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000169 if (bytes_read == -1)
170 {
171 error (0, errno, "%s", filename);
172 return 1;
173 }
174
175 /* Count the incomplete line on files that don't end with a newline. */
176 if (bytes_read && buffer[bytes_read - 1] != '\n')
177 --n_lines;
178
179 do
180 {
181 /* Scan backward, counting the newlines in this bufferfull. */
182 for (i = bytes_read - 1; i >= 0; i--)
183 {
184 /* Have we counted the requested number of newlines yet? */
185 if (buffer[i] == '\n' && n_lines-- == 0)
186 {
187 /* If this newline wasn't the last character in the buffer,
188 print the text after it. */
189 if (i != bytes_read - 1)
190 XWRITE (STDOUT_FILENO, &buffer[i + 1], bytes_read - (i + 1));
191 return 0;
192 }
193 }
194 /* Not enough newlines in that bufferfull. */
195 if (pos == 0)
196 {
197 /* Not enough lines in the file; print the entire file. */
198 lseek (fd, (off_t) 0, SEEK_SET);
199 return 0;
200 }
201 pos -= BUFSIZ;
202 lseek (fd, pos, SEEK_SET);
203 }
Eric Andersen1792f8c1999-12-09 06:11:36 +0000204 while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000205 if (bytes_read == -1)
206 {
207 error (0, errno, "%s", filename);
208 return 1;
209 }
210 return 0;
211}
212
213/* Print the last N_LINES lines from the end of the standard input,
214 open for reading as pipe FD.
215 Buffer the text as a linked list of LBUFFERs, adding them as needed.
216 Return 0 if successful, 1 if an error occured. */
217
218static int
219pipe_lines (const char *filename, int fd, long int n_lines)
220{
221 struct linebuffer
222 {
223 int nbytes, nlines;
224 char buffer[BUFSIZ];
225 struct linebuffer *next;
226 };
227 typedef struct linebuffer LBUFFER;
228 LBUFFER *first, *last, *tmp;
229 int i; /* Index into buffers. */
230 int total_lines = 0; /* Total number of newlines in all buffers. */
231 int errors = 0;
232
233 first = last = (LBUFFER *) xmalloc (sizeof (LBUFFER));
234 first->nbytes = first->nlines = 0;
235 first->next = NULL;
236 tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
237
238 /* Input is always read into a fresh buffer. */
Eric Andersen1792f8c1999-12-09 06:11:36 +0000239 while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000240 {
241 tmp->nlines = 0;
242 tmp->next = NULL;
243
244 /* Count the number of newlines just read. */
245 for (i = 0; i < tmp->nbytes; i++)
246 if (tmp->buffer[i] == '\n')
247 ++tmp->nlines;
248 total_lines += tmp->nlines;
249
250 /* If there is enough room in the last buffer read, just append the new
251 one to it. This is because when reading from a pipe, `nbytes' can
252 often be very small. */
253 if (tmp->nbytes + last->nbytes < BUFSIZ)
254 {
255 memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
256 last->nbytes += tmp->nbytes;
257 last->nlines += tmp->nlines;
258 }
259 else
260 {
261 /* If there's not enough room, link the new buffer onto the end of
262 the list, then either free up the oldest buffer for the next
263 read if that would leave enough lines, or else malloc a new one.
264 Some compaction mechanism is possible but probably not
265 worthwhile. */
266 last = last->next = tmp;
267 if (total_lines - first->nlines > n_lines)
268 {
269 tmp = first;
270 total_lines -= first->nlines;
271 first = first->next;
272 }
273 else
274 tmp = (LBUFFER *) xmalloc (sizeof (LBUFFER));
275 }
276 }
277 if (tmp->nbytes == -1)
278 {
279 error (0, errno, "%s", filename);
280 errors = 1;
281 free ((char *) tmp);
282 goto free_lbuffers;
283 }
284
285 free ((char *) tmp);
286
287 /* This prevents a core dump when the pipe contains no newlines. */
288 if (n_lines == 0)
289 goto free_lbuffers;
290
291 /* Count the incomplete line on files that don't end with a newline. */
292 if (last->buffer[last->nbytes - 1] != '\n')
293 {
294 ++last->nlines;
295 ++total_lines;
296 }
297
298 /* Run through the list, printing lines. First, skip over unneeded
299 buffers. */
300 for (tmp = first; total_lines - tmp->nlines > n_lines; tmp = tmp->next)
301 total_lines -= tmp->nlines;
302
303 /* Find the correct beginning, then print the rest of the file. */
304 if (total_lines > n_lines)
305 {
306 char *cp;
307
308 /* Skip `total_lines' - `n_lines' newlines. We made sure that
309 `total_lines' - `n_lines' <= `tmp->nlines'. */
310 cp = tmp->buffer;
311 for (i = total_lines - n_lines; i; --i)
312 while (*cp++ != '\n')
313 /* Do nothing. */ ;
314 i = cp - tmp->buffer;
315 }
316 else
317 i = 0;
318 XWRITE (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
319
320 for (tmp = tmp->next; tmp; tmp = tmp->next)
321 XWRITE (STDOUT_FILENO, tmp->buffer, tmp->nbytes);
322
323free_lbuffers:
324 while (first)
325 {
326 tmp = first->next;
327 free ((char *) first);
328 first = tmp;
329 }
330 return errors;
331}
332
333/* Print the last N_BYTES characters from the end of pipe FD.
334 This is a stripped down version of pipe_lines.
335 Return 0 if successful, 1 if an error occurred. */
336
337static int
338pipe_bytes (const char *filename, int fd, off_t n_bytes)
339{
340 struct charbuffer
341 {
342 int nbytes;
343 char buffer[BUFSIZ];
344 struct charbuffer *next;
345 };
346 typedef struct charbuffer CBUFFER;
347 CBUFFER *first, *last, *tmp;
348 int i; /* Index into buffers. */
349 int total_bytes = 0; /* Total characters in all buffers. */
350 int errors = 0;
351
352 first = last = (CBUFFER *) xmalloc (sizeof (CBUFFER));
353 first->nbytes = 0;
354 first->next = NULL;
355 tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
356
357 /* Input is always read into a fresh buffer. */
Eric Andersen1792f8c1999-12-09 06:11:36 +0000358 while ((tmp->nbytes = fullRead (fd, tmp->buffer, BUFSIZ)) > 0)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000359 {
360 tmp->next = NULL;
361
362 total_bytes += tmp->nbytes;
363 /* If there is enough room in the last buffer read, just append the new
364 one to it. This is because when reading from a pipe, `nbytes' can
365 often be very small. */
366 if (tmp->nbytes + last->nbytes < BUFSIZ)
367 {
368 memcpy (&last->buffer[last->nbytes], tmp->buffer, tmp->nbytes);
369 last->nbytes += tmp->nbytes;
370 }
371 else
372 {
373 /* If there's not enough room, link the new buffer onto the end of
374 the list, then either free up the oldest buffer for the next
375 read if that would leave enough characters, or else malloc a new
376 one. Some compaction mechanism is possible but probably not
377 worthwhile. */
378 last = last->next = tmp;
379 if (total_bytes - first->nbytes > n_bytes)
380 {
381 tmp = first;
382 total_bytes -= first->nbytes;
383 first = first->next;
384 }
385 else
386 {
387 tmp = (CBUFFER *) xmalloc (sizeof (CBUFFER));
388 }
389 }
390 }
391 if (tmp->nbytes == -1)
392 {
393 error (0, errno, "%s", filename);
394 errors = 1;
395 free ((char *) tmp);
396 goto free_cbuffers;
397 }
398
399 free ((char *) tmp);
400
401 /* Run through the list, printing characters. First, skip over unneeded
402 buffers. */
403 for (tmp = first; total_bytes - tmp->nbytes > n_bytes; tmp = tmp->next)
404 total_bytes -= tmp->nbytes;
405
406 /* Find the correct beginning, then print the rest of the file.
407 We made sure that `total_bytes' - `n_bytes' <= `tmp->nbytes'. */
408 if (total_bytes > n_bytes)
409 i = total_bytes - n_bytes;
410 else
411 i = 0;
412 XWRITE (STDOUT_FILENO, &tmp->buffer[i], tmp->nbytes - i);
413
414 for (tmp = tmp->next; tmp; tmp = tmp->next)
415 XWRITE (STDOUT_FILENO, tmp->buffer, tmp->nbytes);
416
417free_cbuffers:
418 while (first)
419 {
420 tmp = first->next;
421 free ((char *) first);
422 first = tmp;
423 }
424 return errors;
425}
426
427/* Skip N_BYTES characters from the start of pipe FD, and print
428 any extra characters that were read beyond that.
429 Return 1 on error, 0 if ok. */
430
431static int
432start_bytes (const char *filename, int fd, off_t n_bytes)
433{
434 char buffer[BUFSIZ];
435 int bytes_read = 0;
436
Eric Andersen1792f8c1999-12-09 06:11:36 +0000437 while (n_bytes > 0 && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000438 n_bytes -= bytes_read;
439 if (bytes_read == -1)
440 {
441 error (0, errno, "%s", filename);
442 return 1;
443 }
444 else if (n_bytes < 0)
445 XWRITE (STDOUT_FILENO, &buffer[bytes_read + n_bytes], -n_bytes);
446 return 0;
447}
448
449/* Skip N_LINES lines at the start of file or pipe FD, and print
450 any extra characters that were read beyond that.
451 Return 1 on error, 0 if ok. */
452
453static int
454start_lines (const char *filename, int fd, long int n_lines)
455{
456 char buffer[BUFSIZ];
457 int bytes_read = 0;
458 int bytes_to_skip = 0;
459
Eric Andersen1792f8c1999-12-09 06:11:36 +0000460 while (n_lines && (bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000461 {
462 bytes_to_skip = 0;
463 while (bytes_to_skip < bytes_read)
464 if (buffer[bytes_to_skip++] == '\n' && --n_lines == 0)
465 break;
466 }
467 if (bytes_read == -1)
468 {
469 error (0, errno, "%s", filename);
470 return 1;
471 }
472 else if (bytes_to_skip < bytes_read)
473 {
474 XWRITE (STDOUT_FILENO, &buffer[bytes_to_skip],
475 bytes_read - bytes_to_skip);
476 }
477 return 0;
478}
479
480/* Display file FILENAME from the current position in FD to the end.
481 If `forever' is nonzero, keep reading from the end of the file
482 until killed. Return the number of bytes read from the file. */
483
484static long
485dump_remainder (const char *filename, int fd)
486{
487 char buffer[BUFSIZ];
488 int bytes_read;
489 long total;
490
491 total = 0;
492output:
Eric Andersen1792f8c1999-12-09 06:11:36 +0000493 while ((bytes_read = fullRead (fd, buffer, BUFSIZ)) > 0)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000494 {
495 XWRITE (STDOUT_FILENO, buffer, bytes_read);
496 total += bytes_read;
497 }
498 if (bytes_read == -1)
499 error (EXIT_FAILURE, errno, "%s", filename);
500 if (forever)
501 {
502 fflush (stdout);
503 sleep (1);
504 goto output;
505 }
506 else
507 {
508 if (forever_multiple)
509 fflush (stdout);
510 }
511
512 return total;
513}
514
515/* Tail NFILES (>1) files forever until killed. The file names are in
516 NAMES. The open file descriptors are in `file_descs', and the size
517 at which we stopped tailing them is in `file_sizes'. We loop over
518 each of them, doing an fstat to see if they have changed size. If
519 none of them have changed size in one iteration, we sleep for a
520 second and try again. We do this until the user interrupts us. */
521
522static void
523tail_forever (char **names, int nfiles)
524{
525 int last;
526
527 last = -1;
528
529 while (1)
530 {
531 int i;
532 int changed;
533
534 changed = 0;
535 for (i = 0; i < nfiles; i++)
536 {
537 struct stat stats;
538
539 if (file_descs[i] < 0)
540 continue;
541 if (fstat (file_descs[i], &stats) < 0)
542 {
543 error (0, errno, "%s", names[i]);
544 file_descs[i] = -1;
545 continue;
546 }
547 if (stats.st_size == file_sizes[i])
548 continue;
549
550 /* This file has changed size. Print out what we can, and
551 then keep looping. */
552
553 changed = 1;
554
555 if (stats.st_size < file_sizes[i])
556 {
557 write_header (names[i], "file truncated");
558 last = i;
559 lseek (file_descs[i], stats.st_size, SEEK_SET);
560 file_sizes[i] = stats.st_size;
561 continue;
562 }
563
564 if (i != last)
565 {
566 if (print_headers)
567 write_header (names[i], NULL);
568 last = i;
569 }
570 file_sizes[i] += dump_remainder (names[i], file_descs[i]);
571 }
572
573 /* If none of the files changed size, sleep. */
574 if (! changed)
575 sleep (1);
576 }
577}
578
579/* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
580 Return 0 if successful, 1 if an error occurred. */
581
582static int
583tail_bytes (const char *filename, int fd, off_t n_bytes)
584{
585 struct stat stats;
586
587 /* FIXME: resolve this like in dd.c. */
588 /* Use fstat instead of checking for errno == ESPIPE because
589 lseek doesn't work on some special files but doesn't return an
590 error, either. */
591 if (fstat (fd, &stats))
592 {
593 error (0, errno, "%s", filename);
594 return 1;
595 }
596
597 if (from_start)
598 {
599 if (S_ISREG (stats.st_mode))
600 lseek (fd, n_bytes, SEEK_CUR);
601 else if (start_bytes (filename, fd, n_bytes))
602 return 1;
603 dump_remainder (filename, fd);
604 }
605 else
606 {
607 if (S_ISREG (stats.st_mode))
608 {
609 off_t current_pos, end_pos;
610 size_t bytes_remaining;
611
612 if ((current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
613 && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
614 {
615 off_t diff;
616 /* Be careful here. The current position may actually be
617 beyond the end of the file. */
618 bytes_remaining = (diff = end_pos - current_pos) < 0 ? 0 : diff;
619 }
620 else
621 {
622 error (0, errno, "%s", filename);
623 return 1;
624 }
625
626 if (bytes_remaining <= n_bytes)
627 {
628 /* From the current position to end of file, there are no
629 more bytes than have been requested. So reposition the
630 file pointer to the incoming current position and print
631 everything after that. */
632 lseek (fd, current_pos, SEEK_SET);
633 }
634 else
635 {
636 /* There are more bytes remaining than were requested.
637 Back up. */
638 lseek (fd, -n_bytes, SEEK_END);
639 }
640 dump_remainder (filename, fd);
641 }
642 else
643 return pipe_bytes (filename, fd, n_bytes);
644 }
645 return 0;
646}
647
648/* Output the last N_LINES lines of file FILENAME open for reading in FD.
649 Return 0 if successful, 1 if an error occurred. */
650
651static int
652tail_lines (const char *filename, int fd, long int n_lines)
653{
654 struct stat stats;
655 off_t length;
656
657 if (fstat (fd, &stats))
658 {
659 error (0, errno, "%s", filename);
660 return 1;
661 }
662
663 if (from_start)
664 {
665 if (start_lines (filename, fd, n_lines))
666 return 1;
667 dump_remainder (filename, fd);
668 }
669 else
670 {
671 /* Use file_lines only if FD refers to a regular file with
672 its file pointer positioned at beginning of file. */
673 /* FIXME: adding the lseek conjunct is a kludge.
674 Once there's a reasonable test suite, fix the true culprit:
675 file_lines. file_lines shouldn't presume that the input
676 file pointer is initially positioned to beginning of file. */
677 if (S_ISREG (stats.st_mode)
678 && lseek (fd, (off_t) 0, SEEK_CUR) == (off_t) 0)
679 {
680 length = lseek (fd, (off_t) 0, SEEK_END);
681 if (length != 0 && file_lines (filename, fd, n_lines, length))
682 return 1;
683 dump_remainder (filename, fd);
684 }
685 else
686 return pipe_lines (filename, fd, n_lines);
687 }
688 return 0;
689}
690
691/* Display the last N_UNITS units of file FILENAME, open for reading
692 in FD.
693 Return 0 if successful, 1 if an error occurred. */
694
695static int
696tail (const char *filename, int fd, off_t n_units)
697{
698 if (count_lines)
699 return tail_lines (filename, fd, (long) n_units);
700 else
701 return tail_bytes (filename, fd, n_units);
702}
703
704/* Display the last N_UNITS units of file FILENAME.
705 "-" for FILENAME means the standard input.
706 FILENUM is this file's index in the list of files the user gave.
707 Return 0 if successful, 1 if an error occurred. */
708
709static int
710tail_file (const char *filename, off_t n_units, int filenum)
711{
712 int fd, errors;
713 struct stat stats;
714
Eric Andersen1792f8c1999-12-09 06:11:36 +0000715 if (!strcmp (filename, "-"))
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000716 {
717 have_read_stdin = 1;
718 filename = "standard input";
719 if (print_headers)
720 write_header (filename, NULL);
721 errors = tail (filename, 0, n_units);
722 if (forever_multiple)
723 {
724 if (fstat (0, &stats) < 0)
725 {
726 error (0, errno, "standard input");
727 errors = 1;
728 }
729 else if (!S_ISREG (stats.st_mode))
730 {
731 error (0, 0,
732 "standard input: cannot follow end of non-regular file");
733 errors = 1;
734 }
735 if (errors)
736 file_descs[filenum] = -1;
737 else
738 {
739 file_descs[filenum] = 0;
740 file_sizes[filenum] = stats.st_size;
741 }
742 }
743 }
744 else
745 {
746 /* Not standard input. */
747 fd = open (filename, O_RDONLY);
748 if (fd == -1)
749 {
750 if (forever_multiple)
751 file_descs[filenum] = -1;
752 error (0, errno, "%s", filename);
753 errors = 1;
754 }
755 else
756 {
757 if (print_headers)
758 write_header (filename, NULL);
759 errors = tail (filename, fd, n_units);
760 if (forever_multiple)
761 {
762 if (fstat (fd, &stats) < 0)
763 {
764 error (0, errno, "%s", filename);
765 errors = 1;
766 }
767 else if (!S_ISREG (stats.st_mode))
768 {
769 error (0, 0, "%s: cannot follow end of non-regular file",
770 filename);
771 errors = 1;
772 }
773 if (errors)
774 {
775 close (fd);
776 file_descs[filenum] = -1;
777 }
778 else
779 {
780 file_descs[filenum] = fd;
781 file_sizes[filenum] = stats.st_size;
782 }
783 }
784 else
785 {
786 if (close (fd))
787 {
788 error (0, errno, "%s", filename);
789 errors = 1;
790 }
791 }
792 }
793 }
794
795 return errors;
796}
797
798extern int
Eric Andersen1792f8c1999-12-09 06:11:36 +0000799tail_main (int argc, char **argv)
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000800{
Eric Andersen1792f8c1999-12-09 06:11:36 +0000801 int stopit = 0;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000802 enum header_mode header_mode = multiple_files;
803 int exit_status = 0;
804 /* If from_start, the number of items to skip before printing; otherwise,
805 the number of items at the end of the file to print. Initially, -1
806 means the value has not been set. */
807 off_t n_units = -1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000808 int n_files;
809 char **file;
810
811 program_name = argv[0];
812 have_read_stdin = 0;
813 count_lines = 1;
814 forever = forever_multiple = from_start = print_headers = 0;
Eric Andersen1792f8c1999-12-09 06:11:36 +0000815
816 /* Parse any options */
817 //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv);
818 while (--argc > 0 && ( **(++argv) == '-' || **argv == '+' )) {
819 if (**argv == '+') {
820 from_start = 1;
821 }
822 stopit = 0;
823 while (stopit == 0 && *(++(*argv))) {
824 switch (**argv) {
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000825 case 'c':
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000826 count_lines = 0;
Eric Andersen1792f8c1999-12-09 06:11:36 +0000827
828 if (--argc < 1) {
829 usage(tail_usage);
830 }
831 n_units = getNum(*(++argv));
832 stopit = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000833 break;
834
835 case 'f':
836 forever = 1;
837 break;
838
Eric Andersen1792f8c1999-12-09 06:11:36 +0000839 case 'n':
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000840 count_lines = 1;
Eric Andersen1792f8c1999-12-09 06:11:36 +0000841
842 if (--argc < 1) {
843 usage(tail_usage);
844 }
845 n_units = atol(*(++argv));
846 stopit = 1;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000847 break;
848
849 case 'q':
850 header_mode = never;
851 break;
852
853 case 'v':
854 header_mode = always;
855 break;
856
857 default:
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000858 usage (tail_usage);
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000859 }
860 }
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000861 }
862
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000863
864 if (n_units == -1)
865 n_units = DEFAULT_N_LINES;
866
867 /* To start printing with item N_UNITS from the start of the file, skip
868 N_UNITS - 1 items. `tail +0' is actually meaningless, but for Unix
869 compatibility it's treated the same as `tail +1'. */
870 if (from_start)
871 {
872 if (n_units)
873 --n_units;
874 }
875
Eric Andersen1792f8c1999-12-09 06:11:36 +0000876 n_files = argc;
877 file = argv;
Eric Andersenabc0f4f1999-12-08 23:19:36 +0000878
879 if (n_files > 1 && forever)
880 {
881 forever_multiple = 1;
882 forever = 0;
883 file_descs = (int *) xmalloc (n_files * sizeof (int));
884 file_sizes = (off_t *) xmalloc (n_files * sizeof (off_t));
885 }
886
887 if (header_mode == always
888 || (header_mode == multiple_files && n_files > 1))
889 print_headers = 1;
890
891 if (n_files == 0)
892 {
893 exit_status |= tail_file ("-", n_units, 0);
894 }
895 else
896 {
897 int i;
898 for (i = 0; i < n_files; i++)
899 exit_status |= tail_file (file[i], n_units, i);
900
901 if (forever_multiple)
902 tail_forever (file, n_files);
903 }
904
905 if (have_read_stdin && close (0) < 0)
906 error (EXIT_FAILURE, errno, "-");
907 if (fclose (stdout) == EOF)
908 error (EXIT_FAILURE, errno, "write error");
909 exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
910}