|
|
dev_t dev; | dev_t dev; |
ino_t ino; | ino_t ino; |
| |
|
/* Whether this file is a FIFO */ |
|
int fifo; |
|
|
|
/* Whether this file is a FIFO and we received eof last time we read from it |
|
* */ |
|
int read_eof; |
|
|
/* The specified name initially referred to a directory or some other | /* The specified name initially referred to a directory or some other |
type for which tail isn't meaningful. Unlike for a permission problem | type for which tail isn't meaningful. Unlike for a permission problem |
(tailable, below) once this is set, the name is not checked ever again. */ | (tailable, below) once this is set, the name is not checked ever again. */ |
|
|
{ | { |
int last; | int last; |
int writer_is_dead = 0; | int writer_is_dead = 0; |
|
int fifo_read = 0; |
| |
last = nfiles - 1; | last = nfiles - 1; |
| |
|
|
{ | { |
int i; | int i; |
int any_changed; | int any_changed; |
|
int skip_fifo; |
| |
any_changed = 0; | any_changed = 0; |
|
|
|
skip_fifo = fifo_read; |
|
fifo_read = 0; |
|
|
for (i = 0; i < nfiles; i++) | for (i = 0; i < nfiles; i++) |
{ | { |
struct stat stats; | struct stat stats; |
|
int bytes_read; |
|
|
| |
if (f[i].ignore) | if (f[i].ignore) |
continue; | continue; |
|
|
continue; | continue; |
} | } |
| |
if (fstat (f[i].fd, &stats) < 0) |
if (f[i].fifo) |
{ |
{ |
f[i].fd = -1; |
if (f[i].read_eof == 1 || skip_fifo) |
f[i].errnum = errno; |
{ |
error (0, errno, "%s", pretty_name (&f[i])); |
f[i].read_eof = 0; |
continue; |
continue; |
} |
} |
|
} |
if (stats.st_size == f[i].size) |
else |
{ |
{ |
f[i].n_consecutive_size_changes = 0; |
if (fstat (f[i].fd, &stats) < 0) |
if ((max_n_unchanged_stats_between_opens |
{ |
<= f[i].n_unchanged_stats++) |
f[i].fd = -1; |
&& follow_mode == Follow_name) |
f[i].errnum = errno; |
{ |
error (0, errno, "%s", pretty_name (&f[i])); |
recheck (&f[i]); |
continue; |
f[i].n_unchanged_stats = 0; |
} |
} |
|
continue; |
if (stats.st_size == f[i].size) |
} |
{ |
|
f[i].n_consecutive_size_changes = 0; |
/* Ensure that a file that's unlinked or moved aside, yet always |
if ((max_n_unchanged_stats_between_opens |
growing will be recognized as having been renamed. */ |
<= f[i].n_unchanged_stats++) |
if ((max_n_consecutive_size_changes_between_opens |
&& follow_mode == Follow_name) |
<= f[i].n_consecutive_size_changes++) |
{ |
&& follow_mode == Follow_name) |
recheck (&f[i]); |
{ |
f[i].n_unchanged_stats = 0; |
f[i].n_consecutive_size_changes = 0; |
} |
recheck (&f[i]); |
continue; |
continue; |
} |
} |
|
|
/* Ensure that a file that's unlinked or moved aside, yet always |
|
growing will be recognized as having been renamed. */ |
|
if ((max_n_consecutive_size_changes_between_opens |
|
<= f[i].n_consecutive_size_changes++) |
|
&& follow_mode == Follow_name) |
|
{ |
|
f[i].n_consecutive_size_changes = 0; |
|
recheck (&f[i]); |
|
continue; |
|
} |
|
|
|
if (stats.st_size < f[i].size) |
|
{ |
|
error (0, 0, _("%s: file truncated"), pretty_name (&f[i])); |
|
last = i; |
|
xlseek (f[i].fd, (off_t) stats.st_size, SEEK_SET, |
|
pretty_name (&f[i])); |
|
f[i].size = stats.st_size; |
|
continue; |
|
} |
|
} |
| |
/* This file has changed size. Print out what we can, and | /* This file has changed size. Print out what we can, and |
then keep looping. */ | then keep looping. */ |
|
|
/* reset counter */ | /* reset counter */ |
f[i].n_unchanged_stats = 0; | f[i].n_unchanged_stats = 0; |
| |
if (stats.st_size < f[i].size) |
|
{ |
|
error (0, 0, _("%s: file truncated"), pretty_name (&f[i])); |
|
last = i; |
|
xlseek (f[i].fd, (off_t) stats.st_size, SEEK_SET, |
|
pretty_name (&f[i])); |
|
f[i].size = stats.st_size; |
|
continue; |
|
} |
|
| |
if (i != last) | if (i != last) |
{ | { |
|
|
write_header (pretty_name (&f[i])); | write_header (pretty_name (&f[i])); |
last = i; | last = i; |
} | } |
f[i].size += dump_remainder (pretty_name (&f[i]), f[i].fd, |
bytes_read = dump_remainder (pretty_name (&f[i]), f[i].fd, |
COPY_TO_EOF); | COPY_TO_EOF); |
|
if (f[i].fifo == 1) |
|
{ |
|
if (bytes_read == 0) |
|
{ |
|
f[i].read_eof = 1; |
|
} |
|
else |
|
{ |
|
fifo_read = 1; |
|
} |
|
} |
|
else |
|
{ |
|
f[i].size += bytes_read; |
|
} |
} | } |
| |
if (n_live_files (f, nfiles) == 0 && ! reopen_inaccessible_files) | if (n_live_files (f, nfiles) == 0 && ! reopen_inaccessible_files) |
|
|
} | } |
else | else |
{ | { |
fd = open (f->name, O_RDONLY); |
fd = open (f->name, O_RDONLY | O_NONBLOCK); |
} | } |
| |
f->tailable = !(reopen_inaccessible_files && fd == -1); | f->tailable = !(reopen_inaccessible_files && fd == -1); |
|
|
f->n_unchanged_stats = 0; | f->n_unchanged_stats = 0; |
f->n_consecutive_size_changes = 0; | f->n_consecutive_size_changes = 0; |
f->ignore = 0; | f->ignore = 0; |
|
if (S_ISFIFO (stats.st_mode)) |
|
{ |
|
f->fifo = 1; |
|
} |
|
else |
|
{ |
|
f->fifo = 0; |
|
} |
} | } |
} | } |
else | else |