diff --git a/src/uu/stdbuf/src/stdbuf.rs b/src/uu/stdbuf/src/stdbuf.rs index 52824ad5e..fae2942f0 100644 --- a/src/uu/stdbuf/src/stdbuf.rs +++ b/src/uu/stdbuf/src/stdbuf.rs @@ -7,7 +7,6 @@ use clap::{Arg, ArgAction, ArgMatches, Command}; use std::ffi::OsString; -use std::os::unix::process::ExitStatusExt; use std::path::PathBuf; use std::process; use tempfile::TempDir; @@ -188,11 +187,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let options = ProgramOptions::try_from(&matches).map_err(|e| UUsageError::new(125, e.to_string()))?; - let mut command_values = matches.get_many::(options::COMMAND).unwrap(); - let mut command = process::Command::new(command_values.next().unwrap()); + let mut command_values = matches + .get_many::(options::COMMAND) + .ok_or_else(|| UUsageError::new(125, "no command specified".to_string()))?; + let Some(first_command) = command_values.next() else { + return Err(UUsageError::new(125, "no command specified".to_string())); + }; + let mut command = process::Command::new(first_command); let command_params: Vec<&OsString> = command_values.collect(); - let tmp_dir = tempdir().unwrap(); + let tmp_dir = tempdir() + .map_err(|e| UUsageError::new(125, format!("failed to create temp directory: {e}")))?; let (preload_env, libstdbuf) = get_preload_env(&tmp_dir)?; command.env(preload_env, libstdbuf); set_command_env(&mut command, "_STDBUF_I", &options.stdin); @@ -229,10 +234,27 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Err(i.into()) } } - None => Err(USimpleError::new( - 1, - translate!("stdbuf-error-killed-by-signal", "signal" => status.signal().unwrap()), - )), + None => { + #[cfg(unix)] + { + use std::os::unix::process::ExitStatusExt; + let signal_msg = status + .signal() + .map(|s| s.to_string()) + .unwrap_or_else(|| "unknown".to_string()); + Err(USimpleError::new( + 1, + translate!("stdbuf-error-killed-by-signal", "signal" => signal_msg), + )) + } + #[cfg(not(unix))] + { + Err(USimpleError::new( + 1, + "process terminated abnormally".to_string(), + )) + } + } } } diff --git a/tests/by-util/test_stdbuf.rs b/tests/by-util/test_stdbuf.rs index 8c3fef587..a19900db3 100644 --- a/tests/by-util/test_stdbuf.rs +++ b/tests/by-util/test_stdbuf.rs @@ -87,6 +87,17 @@ fn test_stdbuf_no_buffer_option_fails() { .stderr_contains("the following required arguments were not provided:"); } +#[cfg(not(target_os = "windows"))] +#[test] +fn test_stdbuf_no_command_fails_with_125() { + // Test that missing command fails with exit code 125 (stdbuf error) + // This verifies proper error handling without unwrap panic + new_ucmd!() + .args(&["-o1"]) + .fails_with_code(125) + .stderr_contains("the following required arguments were not provided:"); +} + // Disabled on x86_64-unknown-linux-musl because the cross-rs Docker image for this target // does not provide musl-compiled system utilities (like tail), leading to dynamic linker errors // when preloading musl-compiled libstdbuf.so into glibc-compiled binaries. Same thing for FreeBSD.