pty: update libc functions for ptyd changes

Of note is that `unlockpt` is required, both by the standard, and our
implementation. This has been taken care of inside of `openpty`, which
is the only non-libc way we are acquiring ptys. Additionally, it has
been modified such that it is POSIX compliant, so any outside future
changes to ptyd will not affect it.

This is part of my ptyd changes (#100). This can be safely merged once
the changes from base/ and userutils/ are merged alongside it.
This commit is contained in:
Connor-GH
2026-06-03 19:41:38 -05:00
parent cef4ba679c
commit 38737af78d
6 changed files with 52 additions and 51 deletions
+1
View File
@@ -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
+26 -13
View File
@@ -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(());
+15 -35
View File
@@ -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 <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ptsname.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ptsname(fd: c_int) -> *mut c_char {
const PTS_BUFFER_LEN: usize = 9 + mem::size_of::<c_int>() * 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::<c_void>()) } == 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 {
+2
View File
@@ -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;
-1
View File
@@ -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;
+8 -2
View File
@@ -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");