On 09/04/2022 15:16, Pádraig Brady wrote:
0 new test failures on Solaris 10 on SPARC-Enterprise-T5220
I read these results wrong actually.
I now notice a hang on Solaris 10,
due to the new use of open(..., O_DIRECTORY) in 9.x
The attached uses an extra stat() to avoid this hang,
but only on these older systems without O_DIRECTORY.
cheers,
Pádraig
From 8709188accaaad4d230afe0b6467482f9ef03802 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Sat, 9 Apr 2022 15:46:52 +0100
Subject: [PATCH] cp,mv,install: avoid opening destination non directories
v9.0-66-ge2daa8f79 introduced an issue, for example
where cp could hang when overwriting a destination fifo,
when it would try to open() the fifo on systems
like Solaris 10 that didn't support the O_DIRECTORY flag.
This is still racy on such systems, but only in the
case where a directory is replaced by a fifo in
the small window between stat() and open().
* src/system.h (target_directory_operand): On systems without
O_DIRECTORY, ensure the file is a directory before attempting to open().
* tests/cp/special-f.sh: Protect cp with timeout(1),
as cp was seen to hang when trying to overwrite an existing fifo.
---
src/system.h | 26 +++++++++++++++++++++++---
tests/cp/special-f.sh | 12 +++++-------
2 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/src/system.h b/src/system.h
index 09498a172..9ccfe9f18 100644
--- a/src/system.h
+++ b/src/system.h
@@ -136,12 +136,32 @@ target_directory_operand (char const *file)
if (must_be_working_directory (file))
return AT_FDCWD;
- int fd = open (file, O_PATHSEARCH | O_DIRECTORY);
+ int fd;
+ bool is_a_dir = false;
+
+ /* On old systems like Solaris 10, check with stat first
+ lest we try an open a fifo for example and hang. */
+ if (!O_DIRECTORY)
+ {
+ struct stat st;
+ int err;
+ if (stat (file, &st) != 0 ? (err = errno, true)
+ : !S_ISDIR (st.st_mode) && (err = ENOTDIR, true))
+ {
+ errno = err;
+ fd = -1;
+ }
+ else
+ is_a_dir = true;
+ }
+
+ if (O_DIRECTORY || is_a_dir)
+ fd = open (file, O_PATHSEARCH | O_DIRECTORY);
if (!O_DIRECTORY && 0 <= fd)
{
- /* On old systems like Solaris 10 that do not support O_DIRECTORY,
- check by hand whether FILE is a directory. */
+ /* On old systems like Solaris 10 double check type,
+ to ensure we've opened a directory. */
struct stat st;
int err;
if (fstat (fd, &st) != 0 ? (err = errno, true)
diff --git a/tests/cp/special-f.sh b/tests/cp/special-f.sh
index a3e7842fa..2c7bf5ea7 100755
--- a/tests/cp/special-f.sh
+++ b/tests/cp/special-f.sh
@@ -24,12 +24,10 @@ mkfifo_or_skip_ fifo
touch e || framework-failure
-
-# Without -f, expect it to fail.
-cp -R fifo e || fail=1
-
-# With -f, it must succeed.
-cp -Rf fifo e || fail=1
-test -p fifo || fail=1
+for force in '' '-f'; do
+ # Second time through will need to unlink fifo e
+ timeout 10 cp -R $force fifo e || fail=1
+ test -p fifo || fail=1
+done
Exit $fail
--
2.26.2