From 15f8ecc505c041c3cc623c5e2e80e8151acfb0f4 Mon Sep 17 00:00:00 2001 From: Pierre Warnier Date: Wed, 10 Jun 2026 12:50:16 +0200 Subject: [PATCH] shadow-core: strip Rust's "(os error N)" suffix from strerror MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit io::Error::from_raw_os_error(e).to_string() renders as "Permission denied (os error 13)" — Rust appends its own suffix to the libc text. Strip it so the message is the bare OS string (matching GNU/coreutils output), and add a regression test that the suffix is absent. Addresses review feedback on #171. --- src/shadow-core/src/os_error.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/shadow-core/src/os_error.rs b/src/shadow-core/src/os_error.rs index bc70ae1..e1f922c 100644 --- a/src/shadow-core/src/os_error.rs +++ b/src/shadow-core/src/os_error.rs @@ -18,7 +18,16 @@ /// translate (musl), this is the untranslated English text. #[must_use] pub fn strerror(errno: i32) -> String { - std::io::Error::from_raw_os_error(errno).to_string() + // `io::Error::from_raw_os_error` carries libc's `strerror` text, but its + // `Display` appends Rust's own " (os error N)" suffix. Strip that so the + // result is the bare OS message (matching GNU/coreutils output). The + // suffix is emitted verbatim in English regardless of locale, so a + // localized message cannot contain it earlier in the string. + let rendered = std::io::Error::from_raw_os_error(errno).to_string(); + match rendered.rfind(" (os error ") { + Some(cut) => rendered[..cut].to_string(), + None => rendered, + } } /// The OS message for `EACCES` ("Permission denied"), sourced from libc. @@ -41,4 +50,13 @@ mod tests { // Same value libc would give for EACCES directly. assert_eq!(msg, strerror(libc::EACCES)); } + + #[test] + fn strerror_drops_the_rust_os_error_suffix() { + // Regression guard: the bare OS message must not carry Rust's + // " (os error N)" rendering (the bug that made permission_denied() + // return "Permission denied (os error 13)"). + let msg = strerror(libc::EACCES); + assert!(!msg.contains("(os error"), "got: {msg:?}"); + } }