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/redox.rs b/src/header/pty/redox.rs index a4fad5c608..8ecfc0a2cd 100644 --- a/src/header/pty/redox.rs +++ b/src/header/pty/redox.rs @@ -1,29 +1,42 @@ use crate::{ - error::ResultExt, - header::{fcntl, unistd}, - platform::{ - Pal, Sys, - types::{c_char, c_int, ssize_t}, + header::{ + fcntl, + stdlib::{grantpt, posix_openpt, ptsname_r, unlockpt}, + unistd, }, + platform::types::{c_char, c_int}, }; 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) }; + let master = unsafe { posix_openpt(fcntl::O_RDWR | fcntl::O_NOCTTY) }; 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 { + 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(()); } - name[count as usize] = 0; - let slave = unsafe { fcntl::open(name.as_ptr() as *const c_char, fcntl::O_RDWR, 0) }; + 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(()); 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");