summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2016-11-09 17:23:04 +0000
committerPádraig Brady <P@draigBrady.com>2016-11-09 19:36:42 +0000
commit7fc7206b03a7f54b23904373ad397f693a5fae2a (patch)
treef82dde5b62877b33a07859dc4538fb95f4b31b50
parent2a809125299261db9db9b97e93b5885223c6e9d3 (diff)
downloadcoreutils-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--NEWS4
-rw-r--r--src/tail.c16
2 files changed, 17 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index 7780d5288..c223b562d 100644
--- a/NEWS
+++ b/NEWS
@@ -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;
}