aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2021-12-30 16:15:14 -0500
committerJesse Luehrs <doy@tozt.net>2021-12-30 16:15:14 -0500
commit43e517cea6704f0d8424a88b13a1d40550c7e9ca (patch)
treed19bf1e3b3fa8b1e563ccb5c376a08505fb2e00e
parentb82bcb3aeb96fd3a867e6e717be3b9431faa70bd (diff)
downloadpty-process-43e517cea6704f0d8424a88b13a1d40550c7e9ca.tar.gz
pty-process-43e517cea6704f0d8424a88b13a1d40550c7e9ca.zip
add spawn_pg
-rw-r--r--src/blocking/command.rs24
-rw-r--r--src/command.rs24
-rw-r--r--src/sys.rs26
3 files changed, 74 insertions, 0 deletions
diff --git a/src/blocking/command.rs b/src/blocking/command.rs
index ed36443..2cbfb97 100644
--- a/src/blocking/command.rs
+++ b/src/blocking/command.rs
@@ -128,6 +128,30 @@ impl Command {
Ok(self.inner.spawn()?)
}
+ pub fn spawn_pg(
+ &mut self,
+ pg: Option<u32>,
+ ) -> crate::Result<std::process::Child> {
+ let mut set_process_group = crate::sys::set_process_group_child(pg);
+ // Safety: setpgid() is an async-signal-safe function and ioctl() is a
+ // raw syscall (which is inherently async-signal-safe).
+ if let Some(mut custom) = self.pre_exec.take() {
+ unsafe {
+ self.inner.pre_exec(move || {
+ set_process_group()?;
+ custom()?;
+ Ok(())
+ })
+ };
+ } else {
+ unsafe { self.inner.pre_exec(set_process_group) };
+ }
+
+ let child = self.inner.spawn()?;
+ crate::sys::set_process_group_parent(child.id(), pg)?;
+ Ok(child)
+ }
+
pub fn uid(&mut self, id: u32) -> &mut Self {
self.inner.uid(id);
self
diff --git a/src/command.rs b/src/command.rs
index cd1c8a3..c6dac9d 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -128,6 +128,30 @@ impl Command {
Ok(self.inner.spawn()?)
}
+ pub fn spawn_pg(
+ &mut self,
+ pg: Option<u32>,
+ ) -> crate::Result<async_process::Child> {
+ let mut set_process_group = crate::sys::set_process_group_child(pg);
+ // Safety: setpgid() is an async-signal-safe function and ioctl() is a
+ // raw syscall (which is inherently async-signal-safe).
+ if let Some(mut custom) = self.pre_exec.take() {
+ unsafe {
+ self.inner.pre_exec(move || {
+ set_process_group()?;
+ custom()?;
+ Ok(())
+ })
+ };
+ } else {
+ unsafe { self.inner.pre_exec(set_process_group) };
+ }
+
+ let child = self.inner.spawn()?;
+ crate::sys::set_process_group_parent(child.id(), pg)?;
+ Ok(child)
+ }
+
pub fn uid(&mut self, id: u32) -> &mut Self {
self.inner.uid(id);
self
diff --git a/src/sys.rs b/src/sys.rs
index 0d897bc..36d87c1 100644
--- a/src/sys.rs
+++ b/src/sys.rs
@@ -76,6 +76,32 @@ pub fn session_leader(
}
}
+pub fn set_process_group_child(
+ pg: Option<u32>,
+) -> impl FnMut() -> std::io::Result<()> {
+ move || {
+ nix::unistd::setpgid(
+ nix::unistd::Pid::from_raw(0),
+ pg.map_or(nix::unistd::Pid::from_raw(0), |pid| {
+ nix::unistd::Pid::from_raw(pid.try_into().unwrap())
+ }),
+ )?;
+ Ok(())
+ }
+}
+
+pub fn set_process_group_parent(
+ pid: u32,
+ pg: Option<u32>,
+) -> nix::Result<()> {
+ nix::unistd::setpgid(
+ nix::unistd::Pid::from_raw(pid.try_into().unwrap()),
+ pg.map_or(nix::unistd::Pid::from_raw(0), |pid| {
+ nix::unistd::Pid::from_raw(pid.try_into().unwrap())
+ }),
+ )
+}
+
fn set_controlling_terminal(fd: std::os::unix::io::RawFd) -> nix::Result<()> {
// Safety: std::fs::File is required to contain a valid file descriptor
unsafe { set_controlling_terminal_unsafe(fd, std::ptr::null()) }