use std::os::unix::process::CommandExt as _; pub struct Command { inner: std::process::Command, stdin: Option, stdout: Option, stderr: Option, } impl Command { pub fn new>(program: S) -> Self { Self { inner: std::process::Command::new(program), stdin: None, stdout: None, stderr: None, } } pub fn arg>(&mut self, arg: S) -> &mut Self { self.inner.arg(arg); self } pub fn args(&mut self, args: I) -> &mut Self where I: IntoIterator, S: AsRef, { self.inner.args(args); self } pub fn env(&mut self, key: K, val: V) -> &mut Self where K: AsRef, V: AsRef, { self.inner.env(key, val); self } pub fn envs(&mut self, vars: I) -> &mut Self where I: IntoIterator, K: AsRef, V: AsRef, { self.inner.envs(vars); self } pub fn env_remove>( &mut self, key: K, ) -> &mut Self { self.inner.env_remove(key); self } pub fn env_clear(&mut self) -> &mut Self { self.inner.env_clear(); self } pub fn current_dir>( &mut self, dir: P, ) -> &mut Self { self.inner.current_dir(dir); self } pub fn stdin>( &mut self, cfg: Option, ) -> &mut Self { self.stdin = cfg.map(Into::into); self } pub fn stdout>( &mut self, cfg: Option, ) -> &mut Self { self.stdout = cfg.map(Into::into); self } pub fn stderr>( &mut self, cfg: Option, ) -> &mut Self { self.stderr = cfg.map(Into::into); self } pub fn spawn( &mut self, pty: crate::blocking::Pty, ) -> crate::Result { let (stdin, stdout, stderr, pre_exec) = crate::sys::setup_subprocess(&pty, pty.pts()?)?; self.inner.stdin(self.stdin.take().unwrap_or(stdin)); self.inner.stdout(self.stdout.take().unwrap_or(stdout)); self.inner.stderr(self.stderr.take().unwrap_or(stderr)); // safe because setsid() and close() are async-signal-safe functions // and ioctl() is a raw syscall (which is inherently // async-signal-safe). unsafe { self.inner.pre_exec(pre_exec) }; let child = self.inner.spawn()?; Ok(Child::new(child, pty)) } } pub struct Child { inner: std::process::Child, pty: crate::blocking::Pty, } impl Child { fn new(inner: std::process::Child, pty: crate::blocking::Pty) -> Self { Self { inner, pty } } #[must_use] pub fn pty(&self) -> &crate::blocking::Pty { &self.pty } #[must_use] pub fn pty_mut(&mut self) -> &mut crate::blocking::Pty { &mut self.pty } } impl std::ops::Deref for Child { type Target = std::process::Child; fn deref(&self) -> &Self::Target { &self.inner } } impl std::ops::DerefMut for Child { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } }