diff --git a/src/header/limits/mod.rs b/src/header/limits/mod.rs index 192a82eafb..50054fd399 100644 --- a/src/header/limits/mod.rs +++ b/src/header/limits/mod.rs @@ -130,3 +130,4 @@ pub const PTHREAD_DESTRUCTOR_ITERATIONS: c_long = _POSIX_THREAD_DESTRUCTOR_ITERA pub const PTHREAD_KEYS_MAX: c_long = 4096 * 32; pub const PTHREAD_STACK_MIN: c_long = 65536; pub const SYMLOOP_MAX: c_long = 64; +pub const TTY_NAME_MAX: c_long = 32; // "/scheme/pty/".len() + size of usize::MAX as string + 1 diff --git a/src/header/pty/linux.rs b/src/header/pty/linux.rs deleted file mode 100644 index 020e336915..0000000000 --- a/src/header/pty/linux.rs +++ /dev/null @@ -1,58 +0,0 @@ -use core::ptr; - -use crate::{ - header::{fcntl, sys_ioctl, unistd}, - io::{Cursor, Write}, - platform::types::{c_char, c_int, c_void}, -}; - -pub(super) unsafe fn openpty(name: &mut [u8]) -> Result<(c_int, c_int), ()> { - //TODO: wrap in auto-close struct - let master = unsafe { fcntl::open(c"/dev/ptmx".as_ptr(), fcntl::O_RDWR | fcntl::O_NOCTTY, 0) }; - if master < 0 { - return Err(()); - } - - let mut lock: c_int = 0; - if unsafe { - sys_ioctl::ioctl( - master, - sys_ioctl::TIOCSPTLCK, - ptr::from_mut::(&mut lock).cast::(), - ) - } != 0 - { - unistd::close(master); - return Err(()); - } - - let mut ptn: c_int = 0; - if unsafe { - sys_ioctl::ioctl( - master, - sys_ioctl::TIOCGPTN, - ptr::from_mut::(&mut ptn).cast::(), - ) - } != 0 - { - unistd::close(master); - return Err(()); - } - - let mut cursor = Cursor::new(name); - if let Ok(()) = write!(cursor, "/dev/pts/{}\0", ptn) {}; // TODO handle error - - let slave = unsafe { - fcntl::open( - cursor.get_ref().as_ptr().cast::(), - fcntl::O_RDWR | fcntl::O_NOCTTY, - 0, - ) - }; - if slave < 0 { - unistd::close(master); - return Err(()); - } - - Ok((master, slave)) -} diff --git a/src/header/pty/mod.rs b/src/header/pty/mod.rs index 3620c45581..739d423dbe 100644 --- a/src/header/pty/mod.rs +++ b/src/header/pty/mod.rs @@ -6,7 +6,9 @@ use core::{mem, ptr, slice}; use crate::{ header::{ - bits_sigset_t, fcntl, limits, pthread, signal, sys_ioctl, sys_wait, termios, unistd, utmp, + bits_sigset_t, fcntl, limits, pthread, signal, + stdlib::{grantpt, posix_openpt, ptsname_r, unlockpt}, + sys_ioctl, sys_wait, termios, unistd, utmp, }, platform::{ self, @@ -14,13 +16,44 @@ use crate::{ }, }; -#[cfg(target_os = "linux")] -#[path = "linux.rs"] -mod imp; +unsafe fn openpty_inner(name: &mut [u8]) -> Result<(c_int, c_int), ()> { + // TODO: wrap in auto-close struct + let master = unsafe { posix_openpt(fcntl::O_RDWR | fcntl::O_NOCTTY) }; + if master < 0 { + return Err(()); + } -#[cfg(target_os = "redox")] -#[path = "redox.rs"] -mod imp; + let ret = grantpt(master); + if ret == -1 { + unistd::close(master); + return Err(()); + } + let ret = unsafe { unlockpt(master) }; + if ret == -1 { + unistd::close(master); + return Err(()); + } + + let ret = unsafe { ptsname_r(master, name.as_mut_ptr().cast(), name.len()) }; + if ret < 0 { + unistd::close(master); + return Err(()); + } + + let slave = unsafe { + fcntl::open( + name.as_ptr() as *const c_char, + fcntl::O_RDWR | fcntl::O_NOCTTY, + 0, + ) + }; + if slave < 0 { + unistd::close(master); + return Err(()); + } + + Ok((master, slave)) +} /// See . #[unsafe(no_mangle)] @@ -38,7 +71,7 @@ pub unsafe extern "C" fn openpty( &mut tmp_name }; - let (master, slave) = match unsafe { imp::openpty(name) } { + let (master, slave) = match unsafe { openpty_inner(name) } { Ok(ok) => ok, Err(()) => return -1, }; diff --git a/src/header/pty/redox.rs b/src/header/pty/redox.rs deleted file mode 100644 index a4fad5c608..0000000000 --- a/src/header/pty/redox.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::{ - error::ResultExt, - header::{fcntl, unistd}, - platform::{ - Pal, Sys, - types::{c_char, c_int, ssize_t}, - }, -}; - -pub(super) unsafe fn openpty(name: &mut [u8]) -> Result<(c_int, c_int), ()> { - let master = unsafe { fcntl::open(c"/scheme/pty".as_ptr(), fcntl::O_RDWR, 0) }; - if master < 0 { - return Err(()); - } - - // TODO: better error handling - let count = Sys::fpath(master, name) - .map(|u| u as ssize_t) - .or_minus_one_errno(); - if count < 0 { - unistd::close(master); - return Err(()); - } - name[count as usize] = 0; - - let slave = unsafe { fcntl::open(name.as_ptr() as *const c_char, fcntl::O_RDWR, 0) }; - if slave < 0 { - unistd::close(master); - return Err(()); - } - - Ok((master, slave)) -} diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 70662f4230..14b8f46f8f 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -924,8 +924,7 @@ pub unsafe extern "C" fn posix_memalign( #[unsafe(no_mangle)] pub unsafe extern "C" fn posix_openpt(flags: c_int) -> c_int { #[cfg(target_os = "redox")] - let r = unsafe { open(c"/scheme/pty".as_ptr(), flags) }; - + let r = unsafe { open(c"/scheme/pty/ptmx".as_ptr(), flags) }; #[cfg(target_os = "linux")] let r = unsafe { open(c"/dev/ptmx".as_ptr(), flags) }; @@ -939,9 +938,11 @@ pub unsafe extern "C" fn posix_openpt(flags: c_int) -> c_int { /// See . #[unsafe(no_mangle)] pub unsafe extern "C" fn ptsname(fd: c_int) -> *mut c_char { - const PTS_BUFFER_LEN: usize = 9 + mem::size_of::() * 3 + 1; + const PTS_BUFFER_LEN: usize = limits::TTY_NAME_MAX as usize; static mut PTS_BUFFER: [c_char; PTS_BUFFER_LEN] = [0; PTS_BUFFER_LEN]; - if unsafe { ptsname_r(fd, (&raw mut PTS_BUFFER).cast(), PTS_BUFFER_LEN) } != 0 { + let ret = unsafe { ptsname_r(fd, (&raw mut PTS_BUFFER).cast(), PTS_BUFFER_LEN) }; + if ret != 0 { + platform::ERRNO.set(ret); ptr::null_mut() } else { (&raw mut PTS_BUFFER).cast() @@ -959,49 +960,28 @@ pub unsafe extern "C" fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) } } -#[cfg(target_os = "redox")] +// ptsname_r is not allowed to set errno, but it has it as a return value. #[inline(always)] unsafe fn __ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int { - let tty_ptr = unsafe { unistd::ttyname(fd) }; - - if !tty_ptr.is_null() { - if let Ok(name) = unsafe { CStr::from_ptr(tty_ptr) }.to_str() { - let len = name.len(); - if len > buflen { - platform::ERRNO.set(ERANGE); - return ERANGE; - } else { - // we have checked the string will fit in the buffer - // so can use strcpy safely - let s = name.as_ptr().cast(); - unsafe { - ptr::copy_nonoverlapping(s, buf, len); - } - return 0; - } - } - } - platform::ERRNO.get() -} - -#[cfg(target_os = "linux")] -#[inline(always)] -unsafe fn __ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int { - let mut pty = 0; - let err = platform::ERRNO.get(); + let mut pty: c_int = 0; if unsafe { ioctl(fd, TIOCGPTN, ptr::from_mut(&mut pty).cast::()) } == 0 { + // Linux and Redox use different resource names for PTS's. + #[cfg(target_os = "linux")] let name = format!("/dev/pts/{}", pty); + #[cfg(target_os = "redox")] + let name = format!("/scheme/pty/{}", pty); let len = name.len(); - if len > buflen { - platform::ERRNO.set(ERANGE); + // We need + 1 to account for the NUL terminator. + if len + 1 > buflen { ERANGE } else { // we have checked the string will fit in the buffer // so can use strcpy safely let s = name.as_ptr().cast(); unsafe { ptr::copy_nonoverlapping(s, buf, len) }; - platform::ERRNO.set(err); + // NUL-terminate the result. + unsafe { *(buf.add(len + 1)) = 0 }; 0 } } else { diff --git a/src/header/sys_ioctl/constants.rs b/src/header/sys_ioctl/constants.rs index 86596b4c0b..8849a7ce0d 100644 --- a/src/header/sys_ioctl/constants.rs +++ b/src/header/sys_ioctl/constants.rs @@ -55,5 +55,7 @@ pub const TIOCSPTLCK: c_ulong = 0x4004_5431; /// location pointed to by `lock`. pub const TIOCGPTLCK: c_ulong = 0x8004_5439; +// Get the name of the PT as a c_int. +pub const TIOCGPTN: c_ulong = 0x8004_5430; /// POSIX `sockatmark()` from `sys/socket.h` is intended to replace this. pub const SIOCATMARK: c_ulong = 0x8905; diff --git a/src/header/sys_ioctl/linux.rs b/src/header/sys_ioctl/linux.rs index 2d55989a13..4484b78818 100644 --- a/src/header/sys_ioctl/linux.rs +++ b/src/header/sys_ioctl/linux.rs @@ -28,7 +28,6 @@ pub const TIOCSBRK: c_ulong = 0x5427; pub const TIOCCBRK: c_ulong = 0x5428; pub const TIOCGRS485: c_ulong = 0x542E; pub const TIOCSRS485: c_ulong = 0x542F; -pub const TIOCGPTN: c_ulong = 0x8004_5430; pub const TIOCGDEV: c_ulong = 0x8004_5432; pub const TCGETX: c_ulong = 0x5432; pub const TCSETX: c_ulong = 0x5433; diff --git a/src/header/sys_ioctl/redox/mod.rs b/src/header/sys_ioctl/redox/mod.rs index 4003041d53..04ed92dc7a 100644 --- a/src/header/sys_ioctl/redox/mod.rs +++ b/src/header/sys_ioctl/redox/mod.rs @@ -123,10 +123,16 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu dup_write(fd, "winsize", winsize)?; } TIOCGPTLCK => { - todo_skip!(0, "ioctl TIOCGPTLCK"); + let lock = unsafe { &mut *(out as *mut c_int) }; + dup_read(fd, "ptlock", lock)?; } TIOCSPTLCK => { - todo_skip!(0, "ioctl TIOCSPTLCK"); + let lock = unsafe { &*(out as *const c_int) }; + dup_write(fd, "ptlock", lock)?; + } + TIOCGPTN => { + let name = unsafe { &mut *(out as *mut c_int) }; + dup_read(fd, "ptsname", name)?; } TCSBRK => { todo_skip!(0, "ioctl TCSBRK");