//! `pty.h` implementation. //! //! Non-POSIX, see . use core::{mem, ptr, slice}; use crate::{ header::{ bits_sigset_t, fcntl, limits, pthread, signal, sys_ioctl, sys_wait, termios, unistd, utmp, }, platform::{ self, types::{c_char, c_int, c_void}, }, }; #[cfg(target_os = "linux")] #[path = "linux.rs"] mod imp; #[cfg(target_os = "redox")] #[path = "redox.rs"] mod imp; /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn openpty( amaster: *mut c_int, aslave: *mut c_int, namep: *mut c_char, termp: *const termios::termios, winp: *const sys_ioctl::winsize, ) -> c_int { let mut tmp_name = [0; limits::PATH_MAX]; let name = if !namep.is_null() { unsafe { slice::from_raw_parts_mut(namep.cast::(), limits::PATH_MAX) } } else { &mut tmp_name }; let (master, slave) = match unsafe { imp::openpty(name) } { Ok(ok) => ok, Err(()) => return -1, }; if !termp.is_null() { unsafe { termios::tcsetattr(slave, termios::TCSANOW, termp) }; } if !winp.is_null() { unsafe { sys_ioctl::ioctl(slave, sys_ioctl::TIOCSWINSZ, winp as *mut c_void) }; } unsafe { *amaster = master }; unsafe { *aslave = slave }; 0 } /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn forkpty( pm: *mut c_int, name: *mut c_char, tio: *const termios::termios, ws: *const sys_ioctl::winsize, ) -> c_int { let mut m = 0; let mut s = 0; let mut ec = 0; let mut p: [c_int; 2] = [0; 2]; let mut cs = 0; let mut pid = -1; let mut set = bits_sigset_t::sigset_t::default(); let mut oldset = bits_sigset_t::sigset_t::default(); if unsafe { openpty(&raw mut m, &raw mut s, name, tio, ws) } < 0 { return -1; } unsafe { signal::sigfillset(&raw mut set) }; unsafe { signal::pthread_sigmask(signal::SIG_BLOCK, &raw const set, &raw mut oldset) }; unsafe { pthread::pthread_setcancelstate(pthread::PTHREAD_CANCEL_DISABLE, &raw mut cs) }; if unsafe { unistd::pipe2(p.as_mut_ptr(), fcntl::O_CLOEXEC) } != 0 { unistd::close(s); } else { pid = unsafe { unistd::fork() }; if pid == 0 { unistd::close(m); unistd::close(p[0]); if unsafe { utmp::login_tty(s) } != 0 { unsafe { unistd::write( p[1], platform::ERRNO.as_ptr().cast(), mem::size_of_val(&platform::ERRNO), ) }; unistd::_exit(127); } unistd::close(p[1]); unsafe { pthread::pthread_setcancelstate(cs, ptr::null_mut()) }; unsafe { signal::pthread_sigmask(signal::SIG_SETMASK, &raw const oldset, ptr::null_mut()) }; return 0; } unistd::close(s); unistd::close(p[1]); if unsafe { unistd::read( p[0], ptr::from_mut::(&mut ec).cast::(), mem::size_of::(), ) } > 0 { let mut status = 0; unsafe { sys_wait::waitpid(pid, &raw mut status, 0) }; pid = -1; platform::ERRNO.set(ec); } unistd::close(p[0]); } if pid > 0 { unsafe { *pm = m }; } else { unistd::close(m); } unsafe { pthread::pthread_setcancelstate(cs, ptr::null_mut()) }; unsafe { signal::pthread_sigmask(signal::SIG_SETMASK, &raw const oldset, ptr::null_mut()) }; pid }