mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-09-10 07:59:52 +02:00
tail: avoid infloop with -c on /dev/zero
Problem reported by Ionut Nicula in: https://bugs.gnu.org/70477 * src/tail.c (tail_bytes): Do not loop forever on commands like 'tail -c 4096 /dev/zero'. * tests/tail/tail-c.sh: Test this fix.
This commit is contained in:
3
NEWS
3
NEWS
@@ -12,6 +12,9 @@ GNU coreutils NEWS -*- outline -*-
|
||||
have exited with a "Function not implemented" error.
|
||||
[bug introduced in coreutils-8.28]
|
||||
|
||||
'tail -c 4096 /dev/zero' no longer loops forever.
|
||||
[This bug was present in "the beginning".]
|
||||
|
||||
** Changes in behavior
|
||||
|
||||
ls's -f option now simply acts like -aU, instead of also ignoring
|
||||
|
||||
24
src/tail.c
24
src/tail.c
@@ -760,7 +760,8 @@ free_lbuffers:
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* Print the last N_BYTES characters from the end of pipe FD.
|
||||
/* Print the last N_BYTES characters from the end of FD.
|
||||
Work even if the input is a pipe.
|
||||
This is a stripped down version of pipe_lines.
|
||||
Return true if successful. */
|
||||
|
||||
@@ -1875,15 +1876,28 @@ tail_bytes (char const *pretty_filename, int fd, uintmax_t n_bytes,
|
||||
{
|
||||
off_t end_pos = -1;
|
||||
off_t current_pos = -1;
|
||||
bool copy_from_current_pos = false;
|
||||
|
||||
if (! presume_input_pipe && n_bytes <= OFF_T_MAX)
|
||||
{
|
||||
if (usable_st_size (&stats))
|
||||
end_pos = stats.st_size;
|
||||
else if ((current_pos = lseek (fd, -n_bytes, SEEK_END)) != -1)
|
||||
end_pos = current_pos + n_bytes;
|
||||
{
|
||||
/* Use st_size only if it's so large that this is
|
||||
probably not a /proc or similar file, where st_size
|
||||
is notional. */
|
||||
end_pos = stats.st_size;
|
||||
off_t smallish_size = STP_BLKSIZE (&stats);
|
||||
copy_from_current_pos = smallish_size < end_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_pos = lseek (fd, -n_bytes, SEEK_END);
|
||||
copy_from_current_pos = current_pos != -1;
|
||||
if (copy_from_current_pos)
|
||||
end_pos = current_pos + n_bytes;
|
||||
}
|
||||
}
|
||||
if (end_pos <= (off_t) STP_BLKSIZE (&stats))
|
||||
if (! copy_from_current_pos)
|
||||
return pipe_bytes (pretty_filename, fd, n_bytes, read_pos);
|
||||
if (current_pos == -1)
|
||||
current_pos = xlseek (fd, 0, SEEK_CUR, pretty_filename);
|
||||
|
||||
@@ -35,4 +35,14 @@ printf '123456' | tail -c3 > out || fail=1
|
||||
printf '456' > exp || framework_failure_
|
||||
compare exp out || fail=1
|
||||
|
||||
# Any part of /dev/zero should be valid for tail -c.
|
||||
head -c 4096 /dev/zero >exp || fail=1
|
||||
tail -c 4096 /dev/zero >out || fail=1
|
||||
compare exp out || fail=1
|
||||
|
||||
# Any part of /dev/urandom, if it exists, should be valid for tail -c.
|
||||
if test -r /dev/urandom; then
|
||||
timeout --verbose 1 tail -c 4096 /dev/urandom >/dev/null || fail=1
|
||||
fi
|
||||
|
||||
Exit $fail
|
||||
|
||||
Reference in New Issue
Block a user