*
* Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
/* BB_AUDIT SUSv3 compliant (need fancy for -c) */
{ "b", 512 },
{ "k", 1024 },
{ "m", 1024*1024 },
- { }
+ { "", 0 }
};
struct globals {
bool status;
-};
+} FIX_ALIASING;
#define G (*(struct globals*)&bb_common_bufsiz1)
static void tail_xprint_header(const char *fmt, const char *filename)
off_t current;
struct stat sbuf;
- /* (A good comment is missing here) */
- current = lseek(fd, 0, SEEK_CUR);
/* /proc files report zero st_size, don't lseek them. */
- if (fstat(fd, &sbuf) == 0 && sbuf.st_size)
+ if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) {
+ current = lseek(fd, 0, SEEK_CUR);
if (sbuf.st_size < current)
- lseek(fd, 0, SEEK_SET);
+ xlseek(fd, 0, SEEK_SET);
+ }
r = full_read(fd, buf, count);
if (r < 0) {
return r;
}
-static const char header_fmt[] ALIGN1 = "\n==> %s <==\n";
+#define header_fmt_str "\n==> %s <==\n"
static unsigned eat_num(const char *p)
{
#if ENABLE_FEATURE_FANCY_TAIL
/* q: make it impossible for nfiles to be > header_threshhold */
if (opt & 0x8) header_threshhold = UINT_MAX; // -q
+ //if (opt & 0x10) // -s
if (opt & 0x20) header_threshhold = 0; // -v
-#define FOLLOW_RETRY (opt & 0x40)
+# define FOLLOW_RETRY (opt & 0x40)
#else
-#define FOLLOW_RETRY 0
+# define FOLLOW_RETRY 0
#endif
argc -= optind;
argv += optind;
tailbuf = xmalloc(tailbufsize);
/* tail the files */
- fmt = header_fmt + 1; /* skip header leading newline on first output */
+ fmt = header_fmt_str + 1; /* skip header leading newline on first output */
i = 0;
do {
char *buf;
int newlines_seen;
unsigned seen;
int nread;
+ int fd = fds[i];
- if (ENABLE_FEATURE_FANCY_TAIL && fds[i] < 0)
+ if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)
continue; /* may happen with -E */
if (nfiles > header_threshhold) {
tail_xprint_header(fmt, argv[i]);
- fmt = header_fmt;
+ fmt = header_fmt_str;
}
- /* Optimizing count-bytes case if the file is seekable.
- * Beware of backing up too far.
- * Also we exclude files with size 0 (because of /proc/xxx) */
- if (COUNT_BYTES && !from_top) {
- off_t current = lseek(fds[i], 0, SEEK_END);
+ if (!from_top) {
+ off_t current = lseek(fd, 0, SEEK_END);
if (current > 0) {
- if (count == 0)
- continue; /* showing zero lines is easy :) */
- current -= count;
+ unsigned off;
+ if (COUNT_BYTES) {
+ /* Optimizing count-bytes case if the file is seekable.
+ * Beware of backing up too far.
+ * Also we exclude files with size 0 (because of /proc/xxx) */
+ if (count == 0)
+ continue; /* showing zero bytes is easy :) */
+ current -= count;
+ if (current < 0)
+ current = 0;
+ xlseek(fd, current, SEEK_SET);
+ bb_copyfd_size(fd, STDOUT_FILENO, count);
+ continue;
+ }
+#if 1 /* This is technically incorrect for *LONG* strings, but very useful */
+ /* Optimizing count-lines case if the file is seekable.
+ * We assume the lines are <64k.
+ * (Users complain that tail takes too long
+ * on multi-gigabyte files) */
+ off = (count | 0xf); /* for small counts, be more paranoid */
+ if (off > (INT_MAX / (64*1024)))
+ off = (INT_MAX / (64*1024));
+ current -= off * (64*1024);
if (current < 0)
current = 0;
- xlseek(fds[i], current, SEEK_SET);
- bb_copyfd_size(fds[i], STDOUT_FILENO, count);
- continue;
+ xlseek(fd, current, SEEK_SET);
+#endif
}
}
buf = tailbuf;
taillen = 0;
+ /* "We saw 1st line/byte".
+ * Used only by +N code ("start from Nth", 1-based): */
seen = 1;
newlines_seen = 0;
- while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
+ while ((nread = tail_read(fd, buf, tailbufsize-taillen)) > 0) {
if (from_top) {
int nwrite = nread;
if (seen < count) {
+ /* We need to skip a few more bytes/lines */
if (COUNT_BYTES) {
nwrite -= (count - seen);
seen = count;
} while (nwrite);
}
}
- xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite);
+ if (nwrite > 0)
+ xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite);
} else if (count) {
if (COUNT_BYTES) {
taillen += nread;
if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)
continue;
if (nfiles > header_threshhold) {
- fmt = header_fmt;
+ fmt = header_fmt_str;
}
while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) {
if (fmt) {