Hello,
On my Linux system, I'm having problems getting 'tail -f' to
follow FIFOs. When tail starts, the last 10 lines present in the
FIFO are printed, but all subsequent writes to the FIFO go
unnoticed by tail.
Looking at the source code to tail, I found that the problem was
that tail looks at the size of the files it's following. The size
of a FIFO is always 0, resulting in tail not discovering the new
data available in the FIFO.
A small patch, which checks if the file is a FIFO and in that
case looks at the st_mtime stat struct field instead, has worked
well for me so far. The patch, which can be applied with the
'patch -p0' command, is attached to this mail, and I'd be happy
if you included it in any future releases of tail/textutils
(possibly adding some command line option to activate the patch,
if the functionality of it conflicts with other aspects of tail).
/Tomas
--- textutils-2.0.orig/src/tail.c Thu Aug 5 16:38:02 1999
+++ textutils-2.0/src/tail.c Thu Jul 5 13:56:23 2001
@@ -838,6 +838,7 @@
for (i = 0; i < nfiles; i++)
{
struct stat stats;
+ static time_t st_mtime = 0;
if (f[i].fd < 0)
{
@@ -853,6 +854,38 @@
continue;
}
+ /* FIFO patch; since the size of a FIFO doesn't change when it is written
+ * to, we have to look at something else. I suggest using the st_mtime
+ * stat entry. Of course, some of the code later in this function deals
+ * with size changes (thinks that the file has had its size changed)
+ * which is not true of FIFOs, but it works.
+ *
+ * TODO: I'm not 100% sure it works when two consecutive changes are done
+ * within one second, and there is a fstat() inbetween them. An fstat()
+ * call after the second change will see that st_mtime hasn't been
+ * changed since the previous fstat() call (since the two changes were
+ * done within the same second) and tail will thus not think that there
+ * are any changes to report. Then, if no further data is written to the
+ * FIFO in a long time, will that data be discovered by tail?
+ */
+ if (S_ISFIFO(stats.st_mode)) {
+ if (stats.st_mtime > st_mtime) {
+ st_mtime = stats.st_mtime;
+ } else {
+ /* This block copied from the if (stats.st_size ==
+f[i].size)
+ * block below
+ */
+ f[i].n_consecutive_size_changes = 0;
+ if (++f[i].n_unchanged_stats >
+max_n_unchanged_stats_between_opens
+ && follow_mode == Follow_name)
+ {
+ recheck (&f[i]);
+ f[i].n_unchanged_stats = 0;
+ }
+ continue;
+ }
+ } else
+
if (stats.st_size == f[i].size)
{
f[i].n_consecutive_size_changes = 0;
@@ -887,6 +920,7 @@
/* reset counter */
f[i].n_unchanged_stats = 0;
+ if (! S_ISFIFO(stats.st_mode))
if (stats.st_size < f[i].size)
{
write_header (pretty_name (&f[i]), _("file truncated"));
@@ -903,8 +937,12 @@
write_header (pretty_name (&f[i]), NULL);
last = i;
}
+ if (! S_ISFIFO(stats.st_mode)) {
f[i].size += dump_remainder (pretty_name (&f[i]), f[i].fd,
COPY_TO_EOF);
+ } else {
+ dump_remainder (pretty_name (&f[i]), f[i].fd, COPY_TO_EOF);
+ }
}
if (n_live_files (f, nfiles) == 0 && ! reopen_inaccessible_files)