diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index dcfa376c81e3b..dd140d708e4e5 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -36,14 +36,18 @@ pub trait CommandExt { /// that the child is the leader of a new process group. The parent process /// remains the child reaper of the new process. /// + /// If the tty argument is not `None`, this file will be the controlling + /// terminal for the new session (cf. `login_tty(3)` and tty_ioctl(4), + /// specifically the section on `TIOCSCTTY`). Note that this does not set + /// that file to be the stdio handles for the child process, to do that you + /// must set them directly with the `stdin()` et al methods. + /// /// This is not enough to create a daemon process. The *init* process should /// be the child reaper of a daemon. This can be achieved if the parent /// process exit. Moreover, a daemon should not have a controlling terminal. - /// To achieve this, a session leader (the child) must spawn another process - /// (the daemon) in the same session. #[unstable(feature = "process_session_leader", reason = "recently added", issue = "27811")] - fn session_leader(&mut self, on: bool) -> &mut process::Command; + fn session_leader(&mut self, tty: Option<&T>) -> &mut process::Command; } #[stable(feature = "rust1", since = "1.0.0")] @@ -58,8 +62,12 @@ impl CommandExt for process::Command { self } - fn session_leader(&mut self, on: bool) -> &mut process::Command { - self.as_inner_mut().session_leader = on; + fn session_leader(&mut self, tty: Option<&T>) -> &mut process::Command { + { + let inner = self.as_inner_mut(); + inner.session_leader = true; + inner.tty = tty.map(T::as_raw_fd); + } self } } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 7f50e75f6fc64..f8f0e59b3b7ca 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -37,6 +37,7 @@ pub struct Command { pub uid: Option, pub gid: Option, pub session_leader: bool, + pub tty: Option, } impl Command { @@ -49,6 +50,7 @@ impl Command { uid: None, gid: None, session_leader: false, + tty: None, } } @@ -307,7 +309,23 @@ impl Process { // process leader already. We just forked so it shouldn't return // error, but ignore it anyway. let _ = libc::setsid(); + + // Associate the tty file descriptor with the controlling terminal, + // then close it unless it is an stdio handle. Errors returned by + // close are ignored. + if let Some(tty) = cfg.tty { + + const TIOCSCTTY: u64 = 0x540E; + + if cvt_r(|| libc::funcs::bsd44::ioctl(tty, TIOCSCTTY)).is_err() { + fail(&mut output); + } else if tty > 2 { + let _ = libc::close(tty); + } + + } } + if !dirp.is_null() && libc::chdir(dirp) == -1 { fail(&mut output); }