summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-09 22:06:06 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-09 22:06:06 -0500
commit819158c696c24b51f5881a8ea5e765fe21bb1b87 (patch)
tree0b521d71daec7036feed4d690447a5672e2b5b72
parent7f2a0f4f3f232763822734562e2f44892ed31d1c (diff)
downloadnbsh-819158c696c24b51f5881a8ea5e765fe21bb1b87.tar.gz
nbsh-819158c696c24b51f5881a8ea5e765fe21bb1b87.zip
block SIGTTOU when calling tcsetpgrp
otherwise it'll fail if the session leader is a background process
-rw-r--r--src/pipeline/mod.rs28
1 files changed, 27 insertions, 1 deletions
diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs
index 7748b0e..b47d0d6 100644
--- a/src/pipeline/mod.rs
+++ b/src/pipeline/mod.rs
@@ -449,8 +449,33 @@ fn set_foreground_pg(pg: nix::unistd::Pid) -> anyhow::Result<()> {
nix::fcntl::OFlag::empty(),
nix::sys::stat::Mode::empty(),
)?;
- nix::unistd::tcsetpgrp(pty, pg)?;
+
+ // if a background process calls tcsetpgrp, the kernel will send it
+ // SIGTTOU which suspends it. if that background process is the session
+ // leader and doesn't have SIGTTOU blocked, the kernel will instead just
+ // return ENOTTY from the tcsetpgrp call rather than sending a signal to
+ // avoid deadlocking the process. therefore, we need to ensure that
+ // SIGTTOU is blocked here.
+
+ // Safety: setting a signal handler to SigIgn is always safe
+ unsafe {
+ nix::sys::signal::signal(
+ nix::sys::signal::Signal::SIGTTOU,
+ nix::sys::signal::SigHandler::SigIgn,
+ )?;
+ }
+ let res = nix::unistd::tcsetpgrp(pty, pg);
+ // Safety: setting a signal handler to SigDfl is always safe
+ unsafe {
+ nix::sys::signal::signal(
+ nix::sys::signal::Signal::SIGTTOU,
+ nix::sys::signal::SigHandler::SigDfl,
+ )?;
+ }
+ res?;
+
nix::unistd::close(pty)?;
+
nix::sys::signal::kill(neg_pid(pg), nix::sys::signal::Signal::SIGCONT)
.or_else(|e| {
// the process group has already exited
@@ -460,6 +485,7 @@ fn set_foreground_pg(pg: nix::unistd::Pid) -> anyhow::Result<()> {
Err(e)
}
})?;
+
Ok(())
}