git: a5ff4125cf08 - main - install: Fix two bugs in stdin code

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Wed, 26 Aug 2026 17:34:26 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=a5ff4125cf08a83f7e67f498e423f3e354144327

commit a5ff4125cf08a83f7e67f498e423f3e354144327
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-08-26 17:34:18 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-08-26 17:34:18 +0000

    install: Fix two bugs in stdin code
    
    * Fix case where the source is - and the target exists.
    
    * Only call chflags() (to remove flags that might prevent us from
      replacing an existing target) in the exists case; otherwise,
      to_sb.st_flags is uninitialized.
    
    * Rename the source file in the stdin test case.
    
    * Extend null and stdin test cases to cover the case where the
      target already exists.
    
    PR:             297681
    MFC after:      1 week
    Fixes:          d34870708db9 ("install: Allow installing stdin")
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D59144
---
 usr.bin/xinstall/tests/install_test.sh | 24 +++++++++++++++++-------
 usr.bin/xinstall/xinstall.c            |  6 +++---
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/usr.bin/xinstall/tests/install_test.sh b/usr.bin/xinstall/tests/install_test.sh
index 7acd02abbb80..1ea3dad7e31c 100755
--- a/usr.bin/xinstall/tests/install_test.sh
+++ b/usr.bin/xinstall/tests/install_test.sh
@@ -567,6 +567,11 @@ null_body() {
 	atf_check install /dev/null dst/file
 	atf_check test -f dst/file
 	atf_check test ! -s dst/file
+	# what if target already exists?
+	echo "The Magic Words are Squeamish Ossifrage" >dst/file
+	atf_check test -s dst/file
+	atf_check install /dev/null dst/file
+	atf_check test ! -s dst/file
 }
 
 atf_test_case stdin
@@ -575,16 +580,21 @@ stdin_head() {
 }
 stdin_body() {
 	atf_check mkdir dst
-	echo "The Magic Words are Squeamish Ossifrage" >file
-	atf_check -s exit:71 -e not-empty install - dst <file
+	echo "The Magic Words are Squeamish Ossifrage" >src
+	atf_check -s exit:71 -e not-empty install - dst <src
 	atf_check test ! -e dst/file
-	atf_check install - dst/file <file
-	atf_check cmp -s file dst/file
+	atf_check install - dst/file <src
+	atf_check cmp -s dst/file src
 	atf_check rm dst/file
-	atf_check -s exit:71 -e not-empty install /dev/stdin dst <file
+	atf_check -s exit:71 -e not-empty install /dev/stdin dst <src
 	atf_check test ! -e dst/file
-	atf_check install /dev/stdin dst/file <file
-	atf_check cmp -s file dst/file
+	atf_check install /dev/stdin dst/file <src
+	atf_check cmp -s dst/file src
+	# what if target already exists?
+	atf_check install - dst/file </dev/null
+	atf_check test ! -s dst/file
+	atf_check install /dev/stdin dst/file <src
+	atf_check cmp -s dst/file src
 }
 
 atf_init_test_cases() {
diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c
index 36af3528cae6..4e9bee857df2 100644
--- a/usr.bin/xinstall/xinstall.c
+++ b/usr.bin/xinstall/xinstall.c
@@ -409,7 +409,7 @@ main(int argc, char *argv[])
 		usage();
 	}
 
-	if (!no_target && linkmode == 0) {
+	if (!no_target && linkmode == 0 && strcmp(*argv, "-") != 0) {
 		if (stat(*argv, &from_sb))
 			err(EX_OSERR, "%s", *argv);
 		if (!S_ISREG(to_sb.st_mode))
@@ -882,7 +882,7 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags)
 		if ((to_fd = open(to_name, O_RDONLY)) < 0)
 			err(EX_OSERR, "%s", to_name);
 		if (devnull)
-			files_match = to_sb.st_size == 0;
+			files_match = (to_sb.st_size == 0);
 		else if (ispipe)
 			files_match = false;
 		else {
@@ -972,7 +972,7 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags)
 	if (!files_match) {
 #if HAVE_STRUCT_STAT_ST_FLAGS
 		/* Try to turn off the immutable bits. */
-		if (to_sb.st_flags & NOCHANGEBITS)
+		if (exists && (to_sb.st_flags & NOCHANGEBITS))
 			(void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS);
 #endif
 		if (exists && dobackup) {