diff --git a/src/uu/chroot/src/chroot.rs b/src/uu/chroot/src/chroot.rs index b4926acd9..b4a0fc949 100644 --- a/src/uu/chroot/src/chroot.rs +++ b/src/uu/chroot/src/chroot.rs @@ -80,7 +80,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .status() { Ok(status) => status, - Err(e) => return Err(ChrootError::CommandFailed(command[0].to_string(), e).into()), + Err(e) => { + return Err(if e.kind() == std::io::ErrorKind::NotFound { + ChrootError::CommandNotFound(command[0].to_string(), e) + } else { + ChrootError::CommandFailed(command[0].to_string(), e) + } + .into()) + } }; let code = if pstatus.success() { diff --git a/src/uu/chroot/src/error.rs b/src/uu/chroot/src/error.rs index 69e8ac54b..059715de1 100644 --- a/src/uu/chroot/src/error.rs +++ b/src/uu/chroot/src/error.rs @@ -18,6 +18,9 @@ pub enum ChrootError { /// Failed to execute the specified command. CommandFailed(String, Error), + /// Failed to find the specified command. + CommandNotFound(String, Error), + /// The given user and group specification was invalid. InvalidUserspec(String), @@ -43,12 +46,15 @@ pub enum ChrootError { impl std::error::Error for ChrootError {} impl UError for ChrootError { - // TODO: Exit status: // 125 if chroot itself fails // 126 if command is found but cannot be invoked // 127 if command cannot be found fn code(&self) -> i32 { - 1 + match self { + Self::CommandFailed(_, _) => 126, + Self::CommandNotFound(_, _) => 127, + _ => 125, + } } } @@ -56,7 +62,7 @@ impl Display for ChrootError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::CannotEnter(s, e) => write!(f, "cannot chroot to {}: {}", s.quote(), e,), - Self::CommandFailed(s, e) => { + Self::CommandFailed(s, e) | Self::CommandNotFound(s, e) => { write!(f, "failed to run command {}: {}", s.to_string().quote(), e,) } Self::InvalidUserspec(s) => write!(f, "invalid userspec: {}", s.quote(),), diff --git a/tests/by-util/test_chroot.rs b/tests/by-util/test_chroot.rs index 93eb9fc6c..6d25f2906 100644 --- a/tests/by-util/test_chroot.rs +++ b/tests/by-util/test_chroot.rs @@ -9,7 +9,9 @@ fn test_invalid_arg() { #[test] fn test_missing_operand() { - let result = new_ucmd!().run(); + let result = new_ucmd!().fails(); + + result.code_is(125); assert!(result .stderr_str() @@ -27,7 +29,7 @@ fn test_enter_chroot_fails() { at.mkdir("jail"); let result = ucmd.arg("jail").fails(); - + result.code_is(125); assert!(result .stderr_str() .starts_with("chroot: cannot chroot to 'jail': Operation not permitted (os error 1)")); @@ -41,7 +43,8 @@ fn test_no_such_directory() { ucmd.arg("a") .fails() - .stderr_is("chroot: cannot change root directory to 'a': no such directory"); + .stderr_is("chroot: cannot change root directory to 'a': no such directory") + .code_is(125); } #[test] @@ -51,7 +54,7 @@ fn test_invalid_user_spec() { at.mkdir("a"); let result = ucmd.arg("a").arg("--userspec=ARABA:").fails(); - + result.code_is(125); assert!(result.stderr_str().starts_with("chroot: invalid userspec")); } @@ -91,7 +94,9 @@ fn test_preference_of_userspec() { .arg("-G") .arg("ABC,DEF") .arg(format!("--userspec={}:{}", username, group_name)) - .run(); + .fails(); + + result.code_is(125); println!("result.stdout = {}", result.stdout_str()); println!("result.stderr = {}", result.stderr_str());