From: Pádraig Brady Date: Fri, 18 Oct 2024 12:40:13 +0000 (+0100) Subject: tail: honor --pid with fifos X-Git-Tag: v9.6~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=177fcec66d50b7e7ee351aad417a0bd9e0eb4673;p=thirdparty%2Fcoreutils.git tail: honor --pid with fifos * src/tail.c (tail_file): Open files with O_NONBLOCK if we might need async processing. (pipe_bytes): Ignore EAGAIN read() errors. (pipe_lines): Likewise. * tests/tail/pid-pipe.sh: Add a new test. * tests/local.mk: Reference the new test. * NEWS: Mention the bug fix. Reported by Berhard Voelker. --- diff --git a/NEWS b/NEWS index 3e01536102..31093fb4fb 100644 --- a/NEWS +++ b/NEWS @@ -47,6 +47,10 @@ GNU coreutils NEWS -*- outline -*- where inotify is not used, when all followed files become inaccessible. [This bug was present in "the beginning".] + `tail --follow --pid=PID` will now exit when the PID dies, + even in the presence of blocking inputs like unopened fifos. + [This bug was present in "the beginning".] + 'tail -c 4096 /dev/zero' no longer loops forever. [This bug was present in "the beginning".] diff --git a/src/tail.c b/src/tail.c index aa53d2519c..30207e288f 100644 --- a/src/tail.c +++ b/src/tail.c @@ -698,7 +698,7 @@ pipe_lines (char const *pretty_filename, int fd, uintmax_t n_lines, free (tmp); - if (n_read < 0) + if (n_read < 0 && errno != EAGAIN) { error (0, errno, _("error reading %s"), quoteaf (pretty_filename)); ok = false; @@ -826,7 +826,7 @@ pipe_bytes (char const *pretty_filename, int fd, uintmax_t n_bytes, free (tmp); - if (n_read < 0) + if (n_read < 0 && errno != EAGAIN) { error (0, errno, _("error reading %s"), quoteaf (pretty_filename)); ok = false; @@ -2003,11 +2003,14 @@ tail (char const *filename, int fd, uintmax_t n_units, Return true if successful. */ static bool -tail_file (struct File_spec *f, uintmax_t n_units) +tail_file (struct File_spec *f, uintmax_t n_files, uintmax_t n_units) { int fd; bool ok; + /* Avoid blocking if we may need to process asynchronously. */ + bool nonblocking = forever && (nbpids || n_files > 1); + bool is_stdin = (STREQ (f->name, "-")); if (is_stdin) @@ -2017,7 +2020,8 @@ tail_file (struct File_spec *f, uintmax_t n_units) xset_binary_mode (STDIN_FILENO, O_BINARY); } else - fd = open (f->name, O_RDONLY | O_BINARY); + fd = open (f->name, O_RDONLY | O_BINARY + | nonblocking ? O_NONBLOCK : 0); f->tailable = !(reopen_inaccessible_files && fd == -1); @@ -2456,7 +2460,7 @@ main (int argc, char **argv) xset_binary_mode (STDOUT_FILENO, O_BINARY); for (i = 0; i < n_files; i++) - ok &= tail_file (&F[i], n_units); + ok &= tail_file (&F[i], n_files, n_units); if (forever && ignore_fifo_and_pipe (F, n_files)) { diff --git a/tests/local.mk b/tests/local.mk index bd8f2c8766..12e30b449b 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -268,6 +268,7 @@ all_tests = \ tests/misc/xstrtol.pl \ tests/tail/overlay-headers.sh \ tests/tail/pid.sh \ + tests/tail/pid-pipe.sh \ tests/od/od.pl \ tests/od/od-endian.sh \ tests/od/od-float.sh \ diff --git a/tests/tail/pid-pipe.sh b/tests/tail/pid-pipe.sh new file mode 100755 index 0000000000..61df3be8cd --- /dev/null +++ b/tests/tail/pid-pipe.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# Ensure that "tail --pid=PID fifo" exits responsively + +# Copyright (C) 2025 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src +print_ver_ tail + +mkfifo_or_skip_ fifo + +# Terminate any background process +cleanup_() { kill $pid 2>/dev/null && wait $pid; } + +# Speedup the non inotify case +fastpoll='-s.1 --max-unchanged-stats=1' + +sleep 1 & pid=$! + +returns_ 124 timeout 10 tail -f $fastpoll --pid=$! fifo && fail=1 + +cleanup_ + +Exit $fail