File tree Expand file tree Collapse file tree 3 files changed +29
-13
lines changed
Expand file tree Collapse file tree 3 files changed +29
-13
lines changed Original file line number Diff line number Diff line change @@ -19,18 +19,21 @@ use uucore::error::UError;
1919/// assert_eq!(i32::from(ExitStatus::CommandTimedOut), 124);
2020/// ```
2121pub ( crate ) enum ExitStatus {
22- /// When the child process times out and `--preserve-status` is not specified .
22+ /// When the child process times out.
2323 CommandTimedOut ,
2424
2525 /// When `timeout` itself fails.
2626 TimeoutFailed ,
2727
28+ /// When command is found but cannot be invoked (permission denied, etc.).
29+ CannotInvoke ,
30+
31+ /// When command cannot be found.
32+ CommandNotFound ,
33+
2834 /// When a signal is sent to the child process or `timeout` itself.
2935 SignalSent ( usize ) ,
3036
31- /// When there is a failure while waiting for the child process to terminate.
32- WaitingFailed ,
33-
3437 /// When `SIGTERM` signal received.
3538 Terminated ,
3639}
@@ -40,8 +43,9 @@ impl From<ExitStatus> for i32 {
4043 match exit_status {
4144 ExitStatus :: CommandTimedOut => 124 ,
4245 ExitStatus :: TimeoutFailed => 125 ,
46+ ExitStatus :: CannotInvoke => 126 ,
47+ ExitStatus :: CommandNotFound => 127 ,
4348 ExitStatus :: SignalSent ( s) => 128 + s as Self ,
44- ExitStatus :: WaitingFailed => 124 ,
4549 ExitStatus :: Terminated => 143 ,
4650 }
4751 }
Original file line number Diff line number Diff line change @@ -275,7 +275,7 @@ fn wait_or_kill_process(
275275 process. wait ( ) ?;
276276 Ok ( ExitStatus :: SignalSent ( signal) . into ( ) )
277277 }
278- Err ( _) => Ok ( ExitStatus :: WaitingFailed . into ( ) ) ,
278+ Err ( _) => Ok ( ExitStatus :: CommandTimedOut . into ( ) ) ,
279279 }
280280}
281281
@@ -305,7 +305,6 @@ fn preserve_signal_info(signal: libc::c_int) -> libc::c_int {
305305 signal
306306}
307307
308- /// TODO: Improve exit codes, and make them consistent with the GNU Coreutils exit codes.
309308fn timeout (
310309 cmd : & [ String ] ,
311310 duration : Duration ,
@@ -328,12 +327,10 @@ fn timeout(
328327 . stderr ( Stdio :: inherit ( ) )
329328 . spawn ( )
330329 . map_err ( |err| {
331- let status_code = if err. kind ( ) == ErrorKind :: NotFound {
332- // FIXME: not sure which to use
333- 127
334- } else {
335- // FIXME: this may not be 100% correct...
336- 126
330+ let status_code = match err. kind ( ) {
331+ ErrorKind :: NotFound => ExitStatus :: CommandNotFound . into ( ) ,
332+ ErrorKind :: PermissionDenied => ExitStatus :: CannotInvoke . into ( ) ,
333+ _ => ExitStatus :: CannotInvoke . into ( ) ,
337334 } ;
338335 USimpleError :: new (
339336 status_code,
Original file line number Diff line number Diff line change @@ -223,3 +223,18 @@ fn test_terminate_child_on_receiving_terminate() {
223223 . code_is ( 143 )
224224 . stdout_contains ( "child received TERM" ) ;
225225}
226+
227+ #[ test]
228+ fn test_command_not_found ( ) {
229+ // Test exit code 127 when command doesn't exist
230+ new_ucmd ! ( )
231+ . args ( & [ "1" , "/this/command/definitely/does/not/exist" ] )
232+ . fails_with_code ( 127 ) ;
233+ }
234+
235+ #[ test]
236+ fn test_command_cannot_invoke ( ) {
237+ // Test exit code 126 when command exists but cannot be invoked
238+ // Try to execute a directory (should give permission denied or similar)
239+ new_ucmd ! ( ) . args ( & [ "1" , "/" ] ) . fails_with_code ( 126 ) ;
240+ }
You can’t perform that action at this time.
0 commit comments