From df2d27286abd2a91b8df3f281b222b56ccdbd98b Mon Sep 17 00:00:00 2001 From: cerdelen Date: Tue, 23 Dec 2025 14:07:24 +0100 Subject: [PATCH 1/2] chmod: fix error handling if multiple files are handled --- src/uu/chmod/src/chmod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/chmod/src/chmod.rs b/src/uu/chmod/src/chmod.rs index 15b608af6b2..c5dcb07fca9 100644 --- a/src/uu/chmod/src/chmod.rs +++ b/src/uu/chmod/src/chmod.rs @@ -415,7 +415,7 @@ impl Chmoder { return Err(ChmodError::PreserveRoot("/".to_string()).into()); } if self.recursive { - r = self.walk_dir_with_context(file, true); + r = self.walk_dir_with_context(file, true).and(r); } else { r = self.chmod_file(file).and(r); } From 748949f471b992bb6d32a2363a6fd6ef15678aa3 Mon Sep 17 00:00:00 2001 From: cerdelen Date: Tue, 23 Dec 2025 23:22:38 +0100 Subject: [PATCH 2/2] chmod: add regression test for correct exit codes --- tests/by-util/test_chmod.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/by-util/test_chmod.rs b/tests/by-util/test_chmod.rs index e4d4b028474..ff3e309b5d8 100644 --- a/tests/by-util/test_chmod.rs +++ b/tests/by-util/test_chmod.rs @@ -375,6 +375,38 @@ fn test_permission_denied() { .stderr_is("chmod: 'd/no-x/y': Permission denied\n"); } +#[test] +#[allow(clippy::unreadable_literal)] +fn test_chmod_recursive_correct_exit_code() { + let (at, mut ucmd) = at_and_ucmd!(); + + // create 3 folders to test on + at.mkdir("a"); + at.mkdir("a/b"); + at.mkdir("z"); + + // remove read permissions for folder a so the chmod command for a/b fails + let mut perms = at.metadata("a").permissions(); + perms.set_mode(0o000); + set_permissions(at.plus_as_string("a"), perms).unwrap(); + + #[cfg(not(target_os = "linux"))] + let err_msg = "chmod: Permission denied\n"; + #[cfg(target_os = "linux")] + let err_msg = "chmod: 'a': Permission denied\n"; + + // order of command is a, a/b then c + // command is expected to fail and not just take the last exit code + ucmd.arg("-R") + .arg("--verbose") + .arg("a+w") + .arg("a") + .arg("z") + .umask(0) + .fails() + .stderr_is(err_msg); +} + #[test] #[allow(clippy::unreadable_literal)] fn test_chmod_recursive() {