tail: implement -F
function old new delta tail_main 1190 1494 +304 Signed-off-by: Eric Lammerts <busybox@lists.lammerts.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
committed by
Denys Vlasenko
parent
997538ab58
commit
3b5a664440
@@ -635,7 +635,7 @@ config TAIL
|
|||||||
from files.
|
from files.
|
||||||
|
|
||||||
config FEATURE_FANCY_TAIL
|
config FEATURE_FANCY_TAIL
|
||||||
bool "Enable extra tail options (-q, -s, and -v)"
|
bool "Enable extra tail options (-q, -s, -v, and -F)"
|
||||||
default y
|
default y
|
||||||
depends on TAIL
|
depends on TAIL
|
||||||
help
|
help
|
||||||
|
@@ -85,18 +85,15 @@ int tail_main(int argc, char **argv)
|
|||||||
unsigned count = 10;
|
unsigned count = 10;
|
||||||
unsigned sleep_period = 1;
|
unsigned sleep_period = 1;
|
||||||
bool from_top;
|
bool from_top;
|
||||||
int header_threshhold = 1;
|
|
||||||
const char *str_c, *str_n;
|
const char *str_c, *str_n;
|
||||||
|
|
||||||
char *tailbuf;
|
char *tailbuf;
|
||||||
size_t tailbufsize;
|
size_t tailbufsize;
|
||||||
int taillen = 0;
|
unsigned header_threshhold = 1;
|
||||||
int newlines_seen = 0;
|
unsigned nfiles;
|
||||||
int nfiles, nread, nwrite, i, opt;
|
int i, opt;
|
||||||
unsigned seen;
|
|
||||||
|
|
||||||
int *fds;
|
int *fds;
|
||||||
char *s, *buf;
|
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
|
|
||||||
#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL
|
#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL
|
||||||
@@ -110,8 +107,9 @@ int tail_main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
IF_FEATURE_FANCY_TAIL(opt_complementary = "s+";) /* -s N */
|
/* -s NUM, -F imlies -f */
|
||||||
opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:v"),
|
IF_FEATURE_FANCY_TAIL(opt_complementary = "s+:Ff";)
|
||||||
|
opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:vF"),
|
||||||
&str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period));
|
&str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period));
|
||||||
#define FOLLOW (opt & 0x1)
|
#define FOLLOW (opt & 0x1)
|
||||||
#define COUNT_BYTES (opt & 0x2)
|
#define COUNT_BYTES (opt & 0x2)
|
||||||
@@ -119,8 +117,12 @@ int tail_main(int argc, char **argv)
|
|||||||
if (opt & 0x2) count = eat_num(str_c); // -c
|
if (opt & 0x2) count = eat_num(str_c); // -c
|
||||||
if (opt & 0x4) count = eat_num(str_n); // -n
|
if (opt & 0x4) count = eat_num(str_n); // -n
|
||||||
#if ENABLE_FEATURE_FANCY_TAIL
|
#if ENABLE_FEATURE_FANCY_TAIL
|
||||||
if (opt & 0x8) header_threshhold = INT_MAX; // -q
|
/* q: make it impossible for nfiles to be > header_threshhold */
|
||||||
|
if (opt & 0x8) header_threshhold = UINT_MAX; // -q
|
||||||
if (opt & 0x20) header_threshhold = 0; // -v
|
if (opt & 0x20) header_threshhold = 0; // -v
|
||||||
|
#define FOLLOW_RETRY (opt & 0x40)
|
||||||
|
#else
|
||||||
|
#define FOLLOW_RETRY 0
|
||||||
#endif
|
#endif
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
@@ -128,19 +130,21 @@ int tail_main(int argc, char **argv)
|
|||||||
G.status = EXIT_SUCCESS;
|
G.status = EXIT_SUCCESS;
|
||||||
|
|
||||||
/* open all the files */
|
/* open all the files */
|
||||||
fds = xmalloc(sizeof(int) * (argc + 1));
|
fds = xmalloc(sizeof(fds[0]) * (argc + 1));
|
||||||
if (!argv[0]) {
|
if (!argv[0]) {
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
if (!fstat(STDIN_FILENO, &statbuf) && S_ISFIFO(statbuf.st_mode)) {
|
if (fstat(STDIN_FILENO, &statbuf) == 0
|
||||||
|
&& S_ISFIFO(statbuf.st_mode)
|
||||||
|
) {
|
||||||
opt &= ~1; /* clear FOLLOW */
|
opt &= ~1; /* clear FOLLOW */
|
||||||
}
|
}
|
||||||
*argv = (char *) bb_msg_standard_input;
|
argv[0] = (char *) bb_msg_standard_input;
|
||||||
}
|
}
|
||||||
nfiles = i = 0;
|
nfiles = i = 0;
|
||||||
do {
|
do {
|
||||||
int fd = open_or_warn_stdin(argv[i]);
|
int fd = open_or_warn_stdin(argv[i]);
|
||||||
if (fd < 0) {
|
if (fd < 0 && !FOLLOW_RETRY) {
|
||||||
G.status = EXIT_FAILURE;
|
G.status = EXIT_FAILURE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -161,9 +165,18 @@ int tail_main(int argc, char **argv)
|
|||||||
tailbuf = xmalloc(tailbufsize);
|
tailbuf = xmalloc(tailbufsize);
|
||||||
|
|
||||||
/* tail the files */
|
/* tail the files */
|
||||||
fmt = header_fmt + 1; /* Skip header leading newline on first output. */
|
fmt = header_fmt + 1; /* skip header leading newline on first output */
|
||||||
i = 0;
|
i = 0;
|
||||||
do {
|
do {
|
||||||
|
char *buf;
|
||||||
|
int taillen;
|
||||||
|
int newlines_seen;
|
||||||
|
unsigned seen;
|
||||||
|
int nread;
|
||||||
|
|
||||||
|
if (ENABLE_FEATURE_FANCY_TAIL && fds[i] < 0)
|
||||||
|
continue; /* may happen with -E */
|
||||||
|
|
||||||
if (nfiles > header_threshhold) {
|
if (nfiles > header_threshhold) {
|
||||||
tail_xprint_header(fmt, argv[i]);
|
tail_xprint_header(fmt, argv[i]);
|
||||||
fmt = header_fmt;
|
fmt = header_fmt;
|
||||||
@@ -192,13 +205,13 @@ int tail_main(int argc, char **argv)
|
|||||||
newlines_seen = 0;
|
newlines_seen = 0;
|
||||||
while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
|
while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) {
|
||||||
if (from_top) {
|
if (from_top) {
|
||||||
nwrite = nread;
|
int nwrite = nread;
|
||||||
if (seen < count) {
|
if (seen < count) {
|
||||||
if (COUNT_BYTES) {
|
if (COUNT_BYTES) {
|
||||||
nwrite -= (count - seen);
|
nwrite -= (count - seen);
|
||||||
seen = count;
|
seen = count;
|
||||||
} else {
|
} else {
|
||||||
s = buf;
|
char *s = buf;
|
||||||
do {
|
do {
|
||||||
--nwrite;
|
--nwrite;
|
||||||
if (*s++ == '\n' && ++seen == count) {
|
if (*s++ == '\n' && ++seen == count) {
|
||||||
@@ -231,6 +244,7 @@ int tail_main(int argc, char **argv)
|
|||||||
taillen += nread;
|
taillen += nread;
|
||||||
} else {
|
} else {
|
||||||
int extra = (buf[nread-1] != '\n');
|
int extra = (buf[nread-1] != '\n');
|
||||||
|
char *s;
|
||||||
|
|
||||||
k = newlines_seen + newlines_in_buf + extra - count;
|
k = newlines_seen + newlines_in_buf + extra - count;
|
||||||
s = tailbuf;
|
s = tailbuf;
|
||||||
@@ -257,23 +271,54 @@ int tail_main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
} while (++i < nfiles);
|
} while (++i < nfiles);
|
||||||
|
|
||||||
buf = xrealloc(tailbuf, BUFSIZ);
|
tailbuf = xrealloc(tailbuf, BUFSIZ);
|
||||||
|
|
||||||
fmt = NULL;
|
fmt = NULL;
|
||||||
|
|
||||||
if (FOLLOW) while (1) {
|
if (FOLLOW) while (1) {
|
||||||
sleep(sleep_period);
|
sleep(sleep_period);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
do {
|
do {
|
||||||
|
int nread;
|
||||||
|
const char *filename = argv[i];
|
||||||
|
int fd = fds[i];
|
||||||
|
|
||||||
|
if (FOLLOW_RETRY) {
|
||||||
|
struct stat sbuf, fsbuf;
|
||||||
|
|
||||||
|
if (fd < 0
|
||||||
|
|| fstat(fd, &fsbuf) < 0
|
||||||
|
|| stat(filename, &sbuf) < 0
|
||||||
|
|| fsbuf.st_dev != sbuf.st_dev
|
||||||
|
|| fsbuf.st_ino != sbuf.st_ino
|
||||||
|
) {
|
||||||
|
int new_fd;
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
new_fd = open(filename, O_RDONLY);
|
||||||
|
if (new_fd >= 0) {
|
||||||
|
bb_error_msg("%s has %s; following end of new file",
|
||||||
|
filename, (fd < 0) ? "appeared" : "been replaced"
|
||||||
|
);
|
||||||
|
} else if (fd >= 0) {
|
||||||
|
bb_perror_msg("%s has become inaccessible", filename);
|
||||||
|
}
|
||||||
|
fds[i] = fd = new_fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ENABLE_FEATURE_FANCY_TAIL && fd < 0)
|
||||||
|
continue;
|
||||||
if (nfiles > header_threshhold) {
|
if (nfiles > header_threshhold) {
|
||||||
fmt = header_fmt;
|
fmt = header_fmt;
|
||||||
}
|
}
|
||||||
while ((nread = tail_read(fds[i], buf, BUFSIZ)) > 0) {
|
while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) {
|
||||||
if (fmt) {
|
if (fmt) {
|
||||||
tail_xprint_header(fmt, argv[i]);
|
tail_xprint_header(fmt, filename);
|
||||||
fmt = NULL;
|
fmt = NULL;
|
||||||
}
|
}
|
||||||
xwrite(STDOUT_FILENO, buf, nread);
|
xwrite(STDOUT_FILENO, tailbuf, nread);
|
||||||
}
|
}
|
||||||
} while (++i < nfiles);
|
} while (++i < nfiles);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user