summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS15
m---------gnulib0
-rw-r--r--src/tail.c85
3 files changed, 61 insertions, 39 deletions
diff --git a/NEWS b/NEWS
index 29bedac28..7057d8707 100644
--- a/NEWS
+++ b/NEWS
@@ -8,15 +8,22 @@ GNU coreutils NEWS -*- outline -*-
Even then, chcon may still be useful.
[bug introduced in coreutils-8.0]
- stat -f recognizes more file system types: afs, cifs, anon-inode FS,
- btrfs, cgroupfs, cramfs-wend, debugfs, futexfs, hfs, inotifyfs, minux3,
- nilfs, securityfs, selinux, xenfs
-
md5sum now prints checksums atomically so that concurrent
processes will not intersperse their output.
This also affected sum, sha1sum, sha224sum, sha384sum and sha512sum.
[the bug dates back to the initial implementation]
+ stat -f recognizes more file system types: afs, cifs, anon-inode FS,
+ btrfs, cgroupfs, cramfs-wend, debugfs, futexfs, hfs, inotifyfs, minux3,
+ nilfs, securityfs, selinux, xenfs
+
+ tail -f (inotify-enabled) now avoids a race condition.
+ Before, any data appended in the tiny interval between the initial
+ read-to-EOF and the inotify watch initialization would be ignored
+ initially (until more data was appended), or forever, if the file
+ were first renamed or unlinked or never modified.
+ [The race was introduced in coreutils-7.5]
+
** New features
md5sum --check now also accepts openssl-style checksums.
diff --git a/gnulib b/gnulib
-Subproject 447ce7436647899cfe03ee154bb2b2789d3a8ea
+Subproject f7f4cd99ff9ce8efee94aafdd5980cb4bb1d139
diff --git a/src/tail.c b/src/tail.c
index 97aa8d496..09afeec99 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -1168,6 +1168,47 @@ wd_comparator (const void *e1, const void *e2)
return spec1->wd == spec2->wd;
}
+/* Helper function used by `tail_forever_inotify'. */
+
+static void
+check_fspec (struct File_spec *fspec, int wd, int *prev_wd)
+{
+ struct stat stats;
+ char const *name = pretty_name (fspec);
+
+ if (fstat (fspec->fd, &stats) != 0)
+ {
+ close_fd (fspec->fd, name);
+ fspec->fd = -1;
+ fspec->errnum = errno;
+ return;
+ }
+
+ if (S_ISREG (fspec->mode) && stats.st_size < fspec->size)
+ {
+ error (0, 0, _("%s: file truncated"), name);
+ *prev_wd = wd;
+ xlseek (fspec->fd, stats.st_size, SEEK_SET, name);
+ fspec->size = stats.st_size;
+ }
+ else if (S_ISREG (fspec->mode) && stats.st_size == fspec->size
+ && timespec_cmp (fspec->mtime, get_stat_mtime (&stats)) == 0)
+ return;
+
+ if (wd != *prev_wd)
+ {
+ if (print_headers)
+ write_header (name);
+ *prev_wd = wd;
+ }
+
+ uintmax_t bytes_read = dump_remainder (name, fspec->fd, COPY_TO_EOF);
+ fspec->size += bytes_read;
+
+ if (fflush (stdout) != 0)
+ error (EXIT_FAILURE, errno, _("write error"));
+}
+
/* Tail N_FILES files forever, or until killed.
Check modifications using the inotify events system. */
@@ -1249,6 +1290,14 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files,
prev_wd = f[n_files - 1].wd;
+ /* Check files again. New data can be available since last time we checked
+ and before they are watched by inotify. */
+ for (i = 0; i < n_files; i++)
+ {
+ if (!f[i].ignore)
+ check_fspec (&f[i], f[i].wd, &prev_wd);
+ }
+
evlen += sizeof (struct inotify_event) + 1;
evbuf = xmalloc (evlen);
@@ -1257,11 +1306,7 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files,
This loop sleeps on the `safe_read' call until a new event is notified. */
while (1)
{
- char const *name;
struct File_spec *fspec;
- uintmax_t bytes_read;
- struct stat stats;
-
struct inotify_event *ev;
/* When watching a PID, ensure that a read from WD will not block
@@ -1369,37 +1414,7 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files,
continue;
}
-
- name = pretty_name (fspec);
-
- if (fstat (fspec->fd, &stats) != 0)
- {
- close_fd (fspec->fd, name);
- fspec->fd = -1;
- fspec->errnum = errno;
- continue;
- }
-
- if (S_ISREG (fspec->mode) && stats.st_size < fspec->size)
- {
- error (0, 0, _("%s: file truncated"), name);
- prev_wd = ev->wd;
- xlseek (fspec->fd, stats.st_size, SEEK_SET, name);
- fspec->size = stats.st_size;
- }
-
- if (ev->wd != prev_wd)
- {
- if (print_headers)
- write_header (name);
- prev_wd = ev->wd;
- }
-
- bytes_read = dump_remainder (name, fspec->fd, COPY_TO_EOF);
- fspec->size += bytes_read;
-
- if (fflush (stdout) != 0)
- error (EXIT_FAILURE, errno, _("write error"));
+ check_fspec (fspec, ev->wd, &prev_wd);
}
}
#endif