Skip to content

Commit 3ddfaf5

Browse files
scubainit: Restore the default SIGPIPE action
Rust pre-main code may change the SIGPIPE disposition to ignore: * rust-lang/rust#62569 * rust-lang/rust#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
1 parent 325fb58 commit 3ddfaf5

File tree

3 files changed

+48
-0
lines changed

3 files changed

+48
-0
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [Unreleased]
6+
### Fixed
7+
- Fixed SIGPIPE disposition being set to ignore (#255)
8+
59
## [2.13.0] - 2024-03-25
610
### Added
711
- Added support for Python 3.12 (#244)

scubainit/src/main.rs

+33
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ fn run_scubainit() -> Result<()> {
4545
setup_logging()?;
4646
info!("Looking Rusty!");
4747

48+
restore_sigpipe_default()?;
49+
4850
let ctx = process_envvars()?;
4951

5052
if let Some(ref user_info) = ctx.user_info {
@@ -368,3 +370,34 @@ fn setup_logging() -> Result<()> {
368370
.verbosity(verbosity)
369371
.init()?)
370372
}
373+
374+
// Restore the default SIGPIPE action.
375+
//
376+
// Rust pre-main code may change the SIGPIPE disposition to ignore:
377+
// * https://github.com/rust-lang/rust/issues/62569
378+
// * https://github.com/rust-lang/rust/issues/97889
379+
//
380+
// While scubainit doesn't rely on any specific SIGPIPE behavior, the dispositions of ignored
381+
// signals are inherited through execve and Rust's pre-main code shouldn't influence the process
382+
// executed by scuba.
383+
//
384+
// From man signal(7):
385+
//
386+
// Signal dispositions ... A child created via fork(2) inherits a copy of its parent's signal
387+
// dispositions. During an execve(2), the dispositions of handled signals are reset to the
388+
// default; the dispositions of ignored signals are left unchanged.
389+
//
390+
// This code may be unnecessary in the future if Rust's execve library function is changed to
391+
// restore SIGPIPE.
392+
fn restore_sigpipe_default() -> Result<()> {
393+
// Set the SIGPIPE disposition to default (terminate).
394+
// SAFETY: No signal handler is provided, only the default action,
395+
// so no additional consideration is needed.
396+
unsafe {
397+
let result = libc::signal(libc::SIGPIPE, libc::SIG_DFL);
398+
if result == libc::SIG_ERR {
399+
return Err(std::io::Error::last_os_error().into());
400+
}
401+
}
402+
Ok(())
403+
}

tests/test_main.py

+11
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,17 @@ def test_redirect_stdin(self) -> None:
278278
assert_str_equalish(out, test_str)
279279

280280

281+
class TestMainSignals(MainTest):
282+
def test_sigpipe(self) -> None:
283+
"""Verify SIGPIPE is handled correctly"""
284+
# See https://github.com/JonathonReinhart/scuba/issues/254
285+
SCUBA_YML.write_text(f"image: {DOCKER_IMAGE}")
286+
287+
out, err = run_scuba(["sh", "-c", "yes | echo abcd"])
288+
assert_str_equalish(out, "abcd")
289+
assert_str_equalish(err, "")
290+
291+
281292
class TestMainUser(MainTest):
282293
def _test_user(
283294
self,

0 commit comments

Comments
 (0)