/// Representation of a master/slave pty pair /// /// This is returned by [`openpty`]. #[derive(Debug)] pubstruct OpenptyResult { /// The master port in a virtual pty pair pub master: OwnedFd, /// The slave port in a virtual pty pair pub slave: OwnedFd,
}
feature! { #![feature = "process"] /// A successful result of [`forkpty()`]. #[derive(Debug)] pubenum ForkptyResult { /// This is the parent process of the underlying fork.
Parent { /// The PID of the fork's child process
child: Pid, /// A file descriptor referring to master side of the pseudoterminal of /// the child process.
master: OwnedFd,
}, /// This is the child process of the underlying fork.
Child,
}
}
/// Representation of the Master device in a master/slave pty pair /// /// While this datatype is a thin wrapper around `OwnedFd`, it enforces that the available PTY /// functions are given the correct file descriptor. #[derive(Debug)] pubstruct PtyMaster(OwnedFd);
/// Grant access to a slave pseudoterminal (see /// [`grantpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html)) /// /// `grantpt()` changes the mode and owner of the slave pseudoterminal device corresponding to the /// master pseudoterminal referred to by `fd`. This is a necessary step towards opening the slave. #[inline] pubfn grantpt(fd: &PtyMaster) -> Result<()> { ifunsafe { libc::grantpt(fd.as_raw_fd()) } < 0 { return Err(Errno::last());
}
Ok(())
}
/// Open a pseudoterminal device (see /// [`posix_openpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html)) /// /// `posix_openpt()` returns a file descriptor to an existing unused pseudoterminal master device. /// /// # Examples /// /// A common use case with this function is to open both a master and slave PTY pair. This can be /// done as follows: /// /// ``` /// use std::path::Path; /// use nix::fcntl::{OFlag, open}; /// use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt}; /// use nix::sys::stat::Mode; /// /// # #[allow(dead_code)] /// # fn run() -> nix::Result<()> { /// // Open a new PTY master /// let master_fd = posix_openpt(OFlag::O_RDWR)?; /// /// // Allow a slave to be generated for it /// grantpt(&master_fd)?; /// unlockpt(&master_fd)?; /// /// // Get the name of the slave /// let slave_name = unsafe { ptsname(&master_fd) }?; /// /// // Try to open the slave /// let _slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, Mode::empty())?; /// # Ok(()) /// # } /// ``` #[inline] pubfn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> { let fd = unsafe { libc::posix_openpt(flags.bits()) };
/// Get the name of the slave pseudoterminal (see /// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) /// /// `ptsname()` returns the name of the slave pseudoterminal device corresponding to the master /// referred to by `fd`. /// /// This value is useful for opening the slave pty once the master has already been opened with /// `posix_openpt()`. /// /// # Safety /// /// `ptsname()` mutates global variables and is *not* threadsafe. /// Mutating global variables is always considered `unsafe` by Rust and this /// function is marked as `unsafe` to reflect that. /// /// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`. #[inline] pubunsafefn ptsname(fd: &PtyMaster) -> Result<String> { let name_ptr = unsafe { libc::ptsname(fd.as_raw_fd()) }; if name_ptr.is_null() { return Err(Errno::last());
}
let name = unsafe { CStr::from_ptr(name_ptr) };
Ok(name.to_string_lossy().into_owned())
}
/// Get the name of the slave pseudoterminal (see /// [`ptsname(3)`](https://man7.org/linux/man-pages/man3/ptsname.3.html)) /// /// `ptsname_r()` returns the name of the slave pseudoterminal device corresponding to the master /// referred to by `fd`. This is the threadsafe version of `ptsname()`, but it is not part of the /// POSIX standard and is instead a Linux-specific extension. /// /// This value is useful for opening the slave ptty once the master has already been opened with /// `posix_openpt()`. #[cfg(linux_android)] #[inline] pubfn ptsname_r(fd: &PtyMaster) -> Result<String> { letmut name_buf = Vec::<libc::c_char>::with_capacity(64); let name_buf_ptr = name_buf.as_mut_ptr(); let cname = unsafe { let cap = name_buf.capacity(); if libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, cap) != 0 { return Err(crate::Error::last());
}
CStr::from_ptr(name_buf.as_ptr())
};
let name = cname.to_string_lossy().into_owned();
Ok(name)
}
/// Unlock a pseudoterminal master/slave pseudoterminal pair (see /// [`unlockpt(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html)) /// /// `unlockpt()` unlocks the slave pseudoterminal device corresponding to the master pseudoterminal /// referred to by `fd`. This must be called before trying to open the slave side of a /// pseudoterminal. #[inline] pubfn unlockpt(fd: &PtyMaster) -> Result<()> { ifunsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 { return Err(Errno::last());
}
Ok(())
}
/// Create a new pseudoterminal, returning the slave and master file descriptors /// in `OpenptyResult` /// (see [`openpty`](https://man7.org/linux/man-pages/man3/openpty.3.html)). /// /// If `winsize` is not `None`, the window size of the slave will be set to /// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's /// terminal settings of the slave will be set to the values in `termios`. #[inline] #[cfg(not(target_os = "aix"))] pubfn openpty< 'a, 'b,
T: Into<Option<&'a Winsize>>,
U: Into<Option<&'b Termios>>,
>(
winsize: T,
termios: U,
) -> Result<OpenptyResult> { use std::ptr;
letmut slave = mem::MaybeUninit::<libc::c_int>::uninit(); letmut master = mem::MaybeUninit::<libc::c_int>::uninit(); let ret = { match (termios.into(), winsize.into()) {
(Some(termios), Some(winsize)) => { let inner_termios = termios.get_libc_termios(); unsafe {
libc::openpty(
master.as_mut_ptr(),
slave.as_mut_ptr(),
ptr::null_mut(),
&*inner_termios as *const libc::termios as *mut _,
winsize as *const Winsize as *mut _,
)
}
}
(None, Some(winsize)) => unsafe {
libc::openpty(
master.as_mut_ptr(),
slave.as_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
winsize as *const Winsize as *mut _,
)
},
(Some(termios), None) => { let inner_termios = termios.get_libc_termios(); unsafe {
libc::openpty(
master.as_mut_ptr(),
slave.as_mut_ptr(),
ptr::null_mut(),
&*inner_termios as *const libc::termios as *mut _,
ptr::null_mut(),
)
}
}
(None, None) => unsafe {
libc::openpty(
master.as_mut_ptr(),
slave.as_mut_ptr(),
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
)
},
}
};
feature! { #![feature = "process"] /// Create a new process operating in a pseudoterminal. /// /// If `winsize` is not `None`, the window size of the slave will be set to /// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's /// terminal settings of the slave will be set to the values in `termios`. /// /// # Safety /// /// In a multithreaded program, only [async-signal-safe] functions like `pause` /// and `_exit` may be called by the child (the parent isn't restricted). Note /// that memory allocation may **not** be async-signal-safe and thus must be /// prevented. /// /// Those functions are only a small subset of your operating system's API, so /// special care must be taken to only invoke code you can control and audit. /// /// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html /// /// # Reference /// /// * [FreeBSD](https://man.freebsd.org/cgi/man.cgi?query=forkpty) /// * [Linux](https://man7.org/linux/man-pages/man3/forkpty.3.html) #[cfg(not(target_os = "aix"))] pubunsafefn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(
winsize: T,
termios: U,
) -> Result<ForkptyResult> { use std::ptr;
let term = match termios.into() {
Some(termios) => { let inner_termios = termios.get_libc_termios();
&*inner_termios as *const libc::termios as *mut _
},
None => ptr::null_mut(),
};
let win = winsize
.into()
.map(|ws| ws as *const Winsize as *mut _)
.unwrap_or(ptr::null_mut());
let res = unsafe { libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win) };
let success_ret = Errno::result(res)?; let forkpty_result = match success_ret { // In the child process 0 => ForkptyResult::Child, // In the parent process
child_pid => { // SAFETY: // 1. The master buffer is guaranteed to be initialized in the parent process // 2. OwnedFd::from_raw_fd won't panic as the fd is a valid file descriptor let master = unsafe { OwnedFd::from_raw_fd( master.assume_init() ) };
ForkptyResult::Parent {
master,
child: Pid::from_raw(child_pid),
}
}
};
Ok(forkpty_result)
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-17)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.