diff options
author | Pádraig Brady <P@draigBrady.com> | 2016-11-09 17:23:04 +0000 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2016-11-09 19:36:42 +0000 |
commit | 7fc7206b03a7f54b23904373ad397f693a5fae2a (patch) | |
tree | f82dde5b62877b33a07859dc4538fb95f4b31b50 | |
parent | 2a809125299261db9db9b97e93b5885223c6e9d3 (diff) | |
download | coreutils-7fc7206b03a7f54b23904373ad397f693a5fae2a.tar.xz |
tail: avoid outputting repeated data with remote files
* src/tail.c (tail_forever): Only read up to st_size on network
file systems to avoid the issue with a stale attribute cache
returning a smaller st_size than we have already read().
The was seen with glusterfs at least and caused the complete
file to be repeatedly output due to assuming the file was
truncated in this case.
* NEWS: Mention the fix.
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | src/tail.c | 16 |
2 files changed, 17 insertions, 3 deletions
@@ -55,6 +55,10 @@ GNU coreutils NEWS -*- outline -*- to read from stdin. Previously it behaved as if --retry was specified. [This bug was present in "the beginning".] + tail -f 'remote file' will now avoid outputting repeated data on network + file systems that misreport file sizes through stale metadata. + [This bug was present in "the beginning" but exacerbated in coreutils-8.24] + yes now handles short writes, rather than assuming all writes complete. [bug introduced in coreutils-8.24] diff --git a/src/tail.c b/src/tail.c index 96982ed5b..b3018d526 100644 --- a/src/tail.c +++ b/src/tail.c @@ -1220,9 +1220,19 @@ tail_forever (struct File_spec *f, size_t n_files, double sleep_interval) } } - bytes_read = dump_remainder (name, fd, - (f[i].blocking - ? COPY_A_BUFFER : COPY_TO_EOF)); + /* Don't read more than st_size on networked file systems + because it was seen on glusterfs at least, that st_size + may be smaller than the data read on a _subsequent_ stat call. */ + uintmax_t bytes_to_read; + if (f[i].blocking) + bytes_to_read = COPY_A_BUFFER; + else if (S_ISREG (mode) && f[i].remote) + bytes_to_read = stats.st_size - f[i].size; + else + bytes_to_read = COPY_TO_EOF; + + bytes_read = dump_remainder (name, fd, bytes_to_read); + any_input |= (bytes_read != 0); f[i].size += bytes_read; } |