tail: "stdbuf -o 4k tail XXX"

Version:

coreutils-7.5 (fixed in 7.6)

How to reproduce?

1. You need to modify the source code. modify ‘tail’ source code, add a scanf at the entrance of main to halt the execution of ‘tail’.

2. Then use gdb ./tail PID to attach to the running tail!

Symptom:

Incomplete results. Squid does not print anything.

stdbuf -o 4K tail -f /etc/passwd

will not print anything on the screen, where it should print. Note that this bug affects tail -f only when its standard output is buffered, which is relatively unusual.

Root cause:

When executed the above command, here is the execution:

main

  -> tail_file

      ->  tail

           -> tail_lines

                  -> start_lines

                          -> xwrite_stdout

                                -> fwrite (in non-buffer mode, this is supposed to write the output to screen. However, in buffer mode, the output is buffered by ‘stdbuf’

                                     The error actually occurred within fwrite, that in the end it didn’t

                                     print anything onto the screen!

   -> tail_forever_inotify

       -> safe_read

       -> fflush (stdout)

           Here is the failure: it hanged without calling the fflush!

Fix: Before calling ‘tail_forever_inotify’, call ‘fflush’:

main (... …) {

 … …

 if (forever)  {

#if HAVE_INOTIFY

     int wd = inotify_init ();

     if (wd < 0)

       error (0, errno, _("inotify cannot be used, reverting to polling"));

     else {

+       if (fflush (stdout) != 0)

+           error (EXIT_FAILURE, errno, _("write error"));

       tail_forever_inotify (wd, F, n_files, sleep_interval);

         /* The only way the above returns is upon failure.  */

         exit (EXIT_FAILURE);

       }

#endif

     tail_forever (F, n_files, sleep_interval);

   }

}

/* This is where it hangs with ‘-f’ */

void tail_forever_inotify (... ...) {

  … …

  len = safe_read (wd, evbuf, evlen);

}

/* safe_read is a macro for safe_rw. */

safe_rw (int fd, void const *buf, size_t count) {

  … ...

 for (;;) {

     ssize_t result = read (fd, buf, count); // where it hangs!

     if (0 <= result)

        return result;

     else if (IS_EINTR (errno))

        continue;

     else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)

        count = BUGGY_READ_MAXIMUM;

     else

        return result;

   }

}

Is there Error Message?

No.

Can developers/Errlog anticipate error and print error message?

No. Otherwise you can simply fix the bug!