1 //! Helper for creating a pseudo-terminal
3 //! see [PTY](struct.PTY.html) for an example on how to use it
5 use std
::os
::unix
::io
::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}
;
8 use nix
::pty
::{grantpt, posix_openpt, ptsname_r, unlockpt, PtyMaster}
;
9 use nix
::sys
::stat
::Mode
;
10 use nix
::unistd
::{dup2, setsid}
;
11 use nix
::{ioctl_write_int_bad, ioctl_write_ptr_bad, Result}
;
13 ioctl_write_int_bad
!(set_controlling_tty
, libc
::TIOCSCTTY
);
14 ioctl_write_ptr_bad
!(set_size
, libc
::TIOCSWINSZ
, nix
::pty
::Winsize
);
18 /// Implements Read and Write (from std::io) so one can simply use it
19 /// to read and write the terminal of a child process
23 /// # use proxmox_sys::linux::pty::*;
24 /// # use std::process::Command;
25 /// # use nix::Result;
26 /// fn fork() -> Result<u64> {
27 /// // Code that forks and returs the pid/0
31 /// fn exec(cmd: &str) -> Result<()> {
32 /// // Code that execs the cmd
36 /// fn main() -> Result<()> {
37 /// let (mut pty, secondary) = PTY::new()?;
39 /// let child = fork()?;
41 /// make_controlling_terminal(&secondary)?;
42 /// exec("/some/binary")?;
45 /// // read/write or set size of the terminal
46 /// pty.set_size(80, 20);
55 /// Used to make a new process group of the current process,
56 /// and make the given terminal its controlling terminal
57 pub fn make_controlling_terminal(terminal
: &str) -> Result
<()> {
58 setsid()?
; // make new process group
59 let mode
= Mode
::S_IRUSR
64 | Mode
::S_IWOTH
; // 0666
65 let secondary_fd
= nix
::fcntl
::open(terminal
, OFlag
::O_RDWR
| OFlag
::O_NOCTTY
, mode
)
66 .map(|fd
| unsafe { OwnedFd::from_raw_fd(fd) }
)?
;
67 let s_raw_fd
= secondary_fd
.as_raw_fd();
68 unsafe { set_controlling_tty(s_raw_fd, 0) }?
;
74 std
::mem
::forget(secondary_fd
); // don't call drop handler
81 /// Creates a new PTY by opening /dev/ptmx and returns
82 /// a new PTY and the path to the secondary terminal on success.
83 pub fn new() -> Result
<(Self, String
)> {
85 posix_openpt(OFlag
::O_RDWR
| OFlag
::O_NOCTTY
| OFlag
::O_NONBLOCK
| OFlag
::O_CLOEXEC
)?
;
88 let secondary
= ptsname_r(&primary
)?
; // linux specific
89 Ok((Self { primary }
, secondary
))
92 /// Uses the ioctl 'TIOCSWINSZ' on the terminal fd to set the terminals
94 pub fn set_size(&mut self, col
: u16, row
: u16) -> Result
<()> {
95 let size
= nix
::pty
::Winsize
{
102 unsafe { set_size(self.primary.as_raw_fd(), &size) }?
;
108 impl std
::io
::Read
for PTY
{
109 fn read(&mut self, buf
: &mut [u8]) -> std
::io
::Result
<usize> {
110 Ok(nix
::unistd
::read(self.primary
.as_raw_fd(), buf
)?
)
114 impl std
::io
::Write
for PTY
{
115 fn write(&mut self, buf
: &[u8]) -> std
::io
::Result
<usize> {
116 Ok(nix
::unistd
::write(self.primary
.as_raw_fd(), buf
)?
)
119 fn flush(&mut self) -> std
::io
::Result
<()> {
124 impl AsRawFd
for PTY
{
125 fn as_raw_fd(&self) -> RawFd
{
126 self.primary
.as_raw_fd()
131 fn as_fd(&self) -> BorrowedFd
<'_
> {
132 unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }