diff options
| author | Paul Eggert <eggert@cs.ucla.edu> | 2025-08-03 08:19:53 -0700 |
|---|---|---|
| committer | Paul Eggert <eggert@cs.ucla.edu> | 2025-08-03 19:48:06 -0700 |
| commit | e0100ac746e6ddefeef09e17716c148edc1f995b (patch) | |
| tree | 6017ca72fd3ec4f48bb5cf8bd58874c51e930556 | |
| parent | tail: track errno more accurately (diff) | |
| download | coreutils-e0100ac746e6ddefeef09e17716c148edc1f995b.tar.gz coreutils-e0100ac746e6ddefeef09e17716c148edc1f995b.zip | |
tail: fix race between read and fstat
* src/tail.c (get_file_status): Remove, since after the changes
described below it would be called in just one place and it’s a
bit clearer to inline by hand.
(tail_file): Don’t call fstat after reading the file, as that
misses changes arriving between read and fstat. Instead, reuse
the fstat done before reading the file.
| -rw-r--r-- | src/tail.c | 34 |
1 files changed, 10 insertions, 24 deletions
diff --git a/src/tail.c b/src/tail.c index f23e949b1..6a769181a 100644 --- a/src/tail.c +++ b/src/tail.c @@ -1824,22 +1824,6 @@ tail_forever_inotify (int wd, struct File_spec *f, int n_files, } #endif -/* Get the status for file F, which has descriptor FD, into *ST. - Return true on success, false (diagnosing the failure) otherwise. */ - -static bool -get_file_status (struct File_spec *f, int fd, struct stat *st) -{ - if (fstat (fd, st) < 0) - { - f->errnum = errno; - error (0, f->errnum, _("cannot fstat %s"), quoteaf (f->prettyname)); - return false; - } - f->errnum = 0; - return true; -} - /* Output the last bytes of the file PRETTYNAME open for reading in FD and with status ST. Output the last N_BYTES bytes. Return (-1 - errno) on failure, otherwise the resulting file offset @@ -2023,16 +2007,21 @@ tail_file (struct File_spec *f, count_t n_files, count_t n_units) if (print_headers) write_header (f->prettyname); + off_t read_pos; struct stat stats; - bool stat_ok = get_file_status (f, fd, &stats); - off_t read_pos = stat_ok ? tail (f->prettyname, fd, &stats, n_units) : -1; - if (read_pos < -1) + bool stat_ok = 0 <= fstat (fd, &stats); + if (!stat_ok) { - f->errnum = -1 - read_pos; + f->errnum = errno; + error (0, f->errnum, _("cannot fstat %s"), quoteaf (f->prettyname)); ok = false; } else - ok = stat_ok; + { + read_pos = tail (f->prettyname, fd, &stats, n_units); + ok = -1 <= read_pos; + f->errnum = ok ? 0 : -1 - read_pos; + } if (forever) { @@ -2047,9 +2036,6 @@ tail_file (struct File_spec *f, count_t n_files, count_t n_units) f->ignore ? _("; giving up on this name") : ""); } - if (ok && !get_file_status (f, fd, &stats)) - ok = false; - if (!ok) { f->ignore = ! reopen_inaccessible_files; |
