From bbd1ede58e7b15bee41f5b0cf11bf3fc7ebf8da0 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Sun, 19 May 2024 22:40:39 -0400 Subject: [PATCH] scubainit: Restore the default SIGPIPE action Rust pre-main code may change the SIGPIPE disposition to ignore: * https://github.com/rust-lang/rust/issues/62569 * https://github.com/rust-lang/rust/issues/97889 We could use the nightly compiler flag -Zon-broken-pipe=inherit to disable this behavior. Instead, we take the simpler route and restore the default disposition ourselves. Fixes #254 --- scubainit/src/main.rs | 19 +++++++++++++++++++ tests/test_main.py | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/scubainit/src/main.rs b/scubainit/src/main.rs index e10c2e5..b1bacab 100644 --- a/scubainit/src/main.rs +++ b/scubainit/src/main.rs @@ -45,6 +45,8 @@ fn run_scubainit() -> Result<()> { setup_logging()?; info!("Looking Rusty!"); + restore_sigpipe_default()?; + let ctx = process_envvars()?; if let Some(ref user_info) = ctx.user_info { @@ -368,3 +370,20 @@ fn setup_logging() -> Result<()> { .verbosity(verbosity) .init()?) } + +// Restore the default SIGPIPE action. +// Rust pre-main code may change the SIGPIPE disposition to ignore: +// https://github.com/rust-lang/rust/issues/62569 +// https://github.com/rust-lang/rust/issues/97889 +fn restore_sigpipe_default() -> Result<()> { + // Set the SIGPIPE disposition to default (terminate). + // SAFETY: No signal handler is provided, only the default action, + // so no additional consideration is needed. + unsafe { + let result = libc::signal(libc::SIGPIPE, libc::SIG_DFL); + if result == libc::SIG_ERR { + return Err(std::io::Error::last_os_error().into()) + } + } + Ok(()) +} diff --git a/tests/test_main.py b/tests/test_main.py index 455c52a..bf3485f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -278,6 +278,17 @@ def test_redirect_stdin(self) -> None: assert_str_equalish(out, test_str) +class TestMainSignals(MainTest): + def test_sigpipe(self) -> None: + """Verify SIGPIPE is handled correctly""" + # See https://github.com/JonathonReinhart/scuba/issues/254 + SCUBA_YML.write_text(f"image: {DOCKER_IMAGE}") + + out, err = run_scuba(["sh", "-c", "yes | echo abcd"]) + assert_str_equalish(out, "abcd") + assert_str_equalish(err, "") + + class TestMainUser(MainTest): def _test_user( self,