add documentation for functions relating to controlling terminal

This commit is contained in:
auronandace
2026-07-09 13:23:16 +01:00
parent 88483b96fe
commit d5afd3fe81
7 changed files with 187 additions and 43 deletions
+20
View File
@@ -88,14 +88,20 @@ pub const _POSIX_CHILD_MAX: c_long = 25;
pub const _POSIX_CLOCKRES_MIN: c_long = 20000000;
pub const _POSIX_DELAYTIMER_MAX: c_long = 32;
pub const _POSIX_HOST_NAME_MAX: c_long = 255;
/// Minimum required value for `LINK_MAX`.
pub const _POSIX_LINK_MAX: c_long = 8;
pub const _POSIX_LOGIN_NAME_MAX: c_long = 9;
/// Minimum required value for `MAX_CANON`.
pub const _POSIX_MAX_CANON: c_long = 255;
/// Minimum required value for `MAX_INPUT`.
pub const _POSIX_MAX_INPUT: c_long = 255;
/// Minimum required value for `NAME_MAX`.
pub const _POSIX_NAME_MAX: c_long = 14;
pub const _POSIX_NGROUPS_MAX: c_long = 8;
pub const _POSIX_OPEN_MAX: c_long = 20;
/// Minimum required value for `PATH_MAX`.
pub const _POSIX_PATH_MAX: c_long = 256;
/// Minimum required value for `PIPE_BUF`.
pub const _POSIX_PIPE_BUF: c_long = 512;
pub const _POSIX_RE_DUP_MAX: c_long = 255;
pub const _POSIX_RTSIG_MAX: c_long = 8;
@@ -104,6 +110,7 @@ pub const _POSIX_SEM_VALUE_MAX: c_long = 32767;
pub const _POSIX_SIGQUEUE_MAX: c_long = 32;
pub const _POSIX_SSIZE_MAX: c_long = 32767;
pub const _POSIX_STREAM_MAX: c_long = 8;
/// Minimum required value for `SYMLINK_MAX`.
pub const _POSIX_SYMLINK_MAX: c_long = 255;
/// Minimum required value for `SYMLOOP_MAX`.
pub const _POSIX_SYMLOOP_MAX: c_long = 8;
@@ -138,12 +145,24 @@ pub const RE_DUP_MAX: c_long = _POSIX2_RE_DUP_MAX;
pub const HOST_NAME_MAX: c_long = _POSIX_HOST_NAME_MAX;
pub const LOGIN_NAME_MAX: c_long = 255;
pub const GETENTROPY_MAX: c_long = 256;
/// Maximum number of links to a single file.
pub const LINK_MAX: c_long = 127;
/// Maximum number of bytes that is guaranteed to be atomic when writing to a
/// pipe.
pub const PIPE_BUF: c_long = 4096;
/// Minimum number of bits needed to represent, as a signed integer value, the
/// maximum size of a regular file allowed in the specified directory.
pub const FILESIZEBITS: c_long = 64;
/// Maximum number of bytes in a terminal canonical input line.
pub const MAX_CANON: c_long = _POSIX_MAX_CANON;
/// Maximum number of bytes for which space is available in a terminal input
/// queue; therefore, the maximum number of bytes a conforming application may
/// require to be typed as input before reading them.
pub const MAX_INPUT: c_long = _POSIX_MAX_INPUT;
/// Maximum number of bytes in a symbolic link.
pub const SYMLINK_MAX: c_long = _POSIX_SYMLINK_MAX;
/// Minimum number of bytes of storage actually allocated for any portion of a
/// file.
pub const POSIX_ALLOC_SIZE_MIN: c_long = 4096;
// PTHREAD_DESTRUCTOR_ITERATIONS defined in bits file
@@ -153,4 +172,5 @@ pub const PTHREAD_STACK_MIN: c_long = 65536;
/// Maximum number of symbolic links that can be reliably traversed in the
/// resolution of a pathname in the absence of a loop.
pub const SYMLOOP_MAX: c_long = 64;
/// Maximum length of terminal device name.
pub const TTY_NAME_MAX: c_long = 32; // "/scheme/pty/".len() + size of usize::MAX as string + 1
+1
View File
@@ -33,6 +33,7 @@ pub const RENAME_EXCHANGE: c_uint = 0x02;
pub const RENAME_WHITEOUT: c_uint = 0x04;
// /dev/tty + nul
/// Maximum size of character array to hold `ctermid()` output.
pub const L_ctermid: usize = 9;
// form of name is /XXXXXX, so 7
pub const L_tmpnam: c_int = 7;
+19
View File
@@ -300,6 +300,25 @@ pub unsafe extern "C" fn clearerr(stream: *mut FILE) {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ctermid.html>.
///
/// Generates a string that, when used as a pathname, refers to the current
/// controlling terminal for the current process. If a pathname is returned,
/// access to the file is not guaranteed.
///
/// If `s` is a null pointer, the string is generated in a static area, the
/// address of which is returned. If `s` is not a null pointer, `s` is assumed
/// to point to a character array of at least `L_ctermid` bytes; the string is
/// placed in this array and the value of `s` shall be returned. An empty
/// string shall be returned if the pathname that would refer to the
/// controlling terminal cannot be determined, or if the function is
/// unsuccessful.
///
/// # Safety
/// - The application shall not modify the string returned.
/// - The returned pointer might be invalidated or the string content might be
/// overwritten by a subsequent call to `ctermid()`.
/// - The returned pointer might be invalidated if the calling thread is
/// terminated.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ctermid(s: *mut c_char) -> *mut c_char {
static mut TERMID: [u8; L_ctermid] = *b"/dev/tty\0";
+47 -32
View File
@@ -938,11 +938,25 @@ pub unsafe extern "C" fn posix_openpt(flags: c_int) -> c_int {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ptsname.html>.
///
/// Returns the name of the subsidiary pseudo-terminal device associated with a
/// manager pseudo-terminal device.
///
/// Upon success, returns a pointer to a string which is the name of the
/// subsidiary pseudo-terminal device. Upon failure, returns a null pointer and
/// sets errno to indicate the error value.
///
/// # Safety
/// - The application shall not modify the string returned.
/// - The returned pointer might be invalidated or the string content might be
/// overwritten by a subsequent call to `ptsname()`.
/// - The returned pointer and string content might be invalidated if the
/// calling thread is terminated.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ptsname(fd: c_int) -> *mut c_char {
pub unsafe extern "C" fn ptsname(fildes: c_int) -> *mut c_char {
const PTS_BUFFER_LEN: usize = limits::TTY_NAME_MAX as usize;
static mut PTS_BUFFER: [c_char; PTS_BUFFER_LEN] = [0; PTS_BUFFER_LEN];
let ret = unsafe { ptsname_r(fd, (&raw mut PTS_BUFFER).cast(), PTS_BUFFER_LEN) };
let ret = unsafe { ptsname_r(fildes, (&raw mut PTS_BUFFER).cast(), PTS_BUFFER_LEN) };
if ret != 0 {
platform::ERRNO.set(ret);
ptr::null_mut()
@@ -952,42 +966,43 @@ pub unsafe extern "C" fn ptsname(fd: c_int) -> *mut c_char {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/ptsname.html>.
///
/// Stores the name of the subsidiary pseudo-terminal device corresponding to
/// `fildes` in the character array referenced by `name`. The array is
/// `namesize` characters long and should have space for the `name` and the
/// terminating null character.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicate the error.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
if buf.is_null() {
platform::ERRNO.set(EINVAL);
pub unsafe extern "C" fn ptsname_r(fildes: c_int, name: *mut c_char, namesize: size_t) -> c_int {
if name.is_null() {
EINVAL
} else {
unsafe { __ptsname_r(fd, buf, buflen) }
}
}
let mut pty: c_int = 0;
// 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 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();
// We need + 1 to account for the NUL terminator.
if len + 1 > buflen {
ERANGE
if unsafe { ioctl(fildes, 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 inner_name = format!("/dev/pts/{}", pty);
#[cfg(target_os = "redox")]
let inner_name = format!("/scheme/pty/{}", pty);
let len = inner_name.len();
// We need + 1 to account for the NUL terminator.
if len + 1 > namesize {
ERANGE
} else {
// we have checked the string will fit in the buffer
// so can use strcpy safely
let s = inner_name.as_ptr().cast();
unsafe { ptr::copy_nonoverlapping(s, name, len) };
// NUL-terminate the result.
unsafe { *(name.add(len + 1)) = 0 };
0
}
} 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) };
// NUL-terminate the result.
unsafe { *(buf.add(len + 1)) = 0 };
0
platform::ERRNO.get()
}
} else {
platform::ERRNO.get()
}
}
-4
View File
@@ -95,7 +95,3 @@ pub const CS5: usize = 0o000_000;
/// Enable echo.
pub const ECHO: usize = 0o000_010;
/* } c_lflag */
// POSIX extensions
/// Sentinel value to disable a control char.
pub const _POSIX_VDISABLE: u8 = 0;
+57 -5
View File
@@ -87,6 +87,10 @@ pub const STDERR_FILENO: c_int = 2;
pub const L_cuserid: usize = 9;
/// This symbol shall be defined to be the value of a character that shall
/// disable terminal special character handling.
pub const _POSIX_VDISABLE: u8 = 0;
// confstr constants
// These are copied from Rust's libc and match musl as well.
pub const _CS_PATH: c_int = 0;
@@ -437,6 +441,20 @@ pub extern "C" fn fdatasync(fildes: c_int) -> c_int {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fork.html>.
///
/// Creates a new process. After `fork()`, both the parent and the child
/// processes shall be capable of executing independently before either one
/// terminates.
///
/// Upon success, returns `0` to the child process and returns the process ID
/// of the child process to the parent process. Upon failure, returns `-1` to
/// the parent process, no child process shall be created, and sets errno to
/// indicate the error.
///
/// # Safety
/// For locks held by any thread in the calling process that have not been set
/// to be process-shared, any attempt by the child process to perform any
/// operation on the lock results in undefined behaviour.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn fork() -> pid_t {
for prepare in unsafe { &fork_hooks[0] } {
@@ -1039,6 +1057,17 @@ pub extern "C" fn setreuid(ruid: uid_t, euid: uid_t) -> c_int {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setsid.html>.
///
/// Creates a new session, if the calling process is not a process group
/// leader. Upon return the calling process shall be the session leader of this
/// new session, shall be the process group leader of a new process group, and
/// shall have no controlling terminal. The process group ID of the calling
/// process shall be set equal to the process ID of the calling process. The
/// calling process shall be the only process in the new process group and the
/// only process in the new session.
///
/// Upon success, returns the value of the new process group ID of the calling
/// process. Upon failure, returns `-1` and sets errno to indicate the error.
#[unsafe(no_mangle)]
pub extern "C" fn setsid() -> pid_t {
Sys::setsid().or_minus_one_errno()
@@ -1123,22 +1152,45 @@ pub extern "C" fn sync() {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcgetpgrp.html>.
///
/// Returns the value of the process group ID of the foreground process group
/// associated with the terminal. Calling this function is allowed from a
/// process that is a member of the background process group; however, the
/// information may be subsequently changed by a process that is a member of
/// the foreground process group.
///
/// Upon success, returns the value of the process group ID of the foreground
/// process group associated with the terminal. If there is no foreground
/// process group, returns a value greater than `1` that does not match the
/// process group ID of any existing process group. Upon failure, returns `-1`
/// and sets errno to indicate the error.
#[unsafe(no_mangle)]
pub extern "C" fn tcgetpgrp(fd: c_int) -> pid_t {
pub extern "C" fn tcgetpgrp(fildes: c_int) -> pid_t {
let mut pgrp = 0;
if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCGPGRP, (&raw mut pgrp).cast()) } < 0 {
if unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TIOCGPGRP, (&raw mut pgrp).cast()) } < 0 {
return -1;
}
pgrp
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcsetpgrp.html>.
///
/// If the process has a controlling terminal, sets the foreground process
/// group ID associated with the terminal to `pgid_id`. Using this function
/// from a process which is a member of the background process group on a
/// `fildes` associated with its controlling terminal shall cause the process
/// group to be sent a `SIGTTOU` signal. If the calling thread is blocking
/// `SIGTTOU` signals or the process is ignoring `SIGTTOU` signals, the process
/// shall be allowed to perform the operation, and no signal is sent.
///
/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to
/// indicate the error.
#[unsafe(no_mangle)]
pub extern "C" fn tcsetpgrp(fd: c_int, pgrp: pid_t) -> c_int {
if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCSPGRP, &raw const pgrp as _) } < 0 {
pub extern "C" fn tcsetpgrp(fildes: c_int, pgid_id: pid_t) -> c_int {
if unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TIOCSPGRP, &raw const pgid_id as _) } < 0 {
return -1;
}
pgrp
pgid_id
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/truncate.html>.
+43 -2
View File
@@ -5,7 +5,7 @@ use crate::{
FILESIZEBITS, LINK_MAX, MAX_CANON, MAX_INPUT, NAME_MAX, PATH_MAX, PIPE_BUF,
POSIX_ALLOC_SIZE_MIN, SYMLINK_MAX,
},
termios::_POSIX_VDISABLE,
unistd::_POSIX_VDISABLE,
},
platform::{
self,
@@ -13,27 +13,50 @@ use crate::{
},
};
/// Corresponding pathconf constant for `LINK_MAX` from `limits.h`.
pub const _PC_LINK_MAX: c_int = 0;
/// Corresponding pathconf constant for `MAX_CANON` from `limits.h`.
pub const _PC_MAX_CANON: c_int = 1;
/// Corresponding pathconf constant for `MAX_INPUT` from `limits.h`.
pub const _PC_MAX_INPUT: c_int = 2;
/// Corresponding pathconf constant for `NAME_MAX` from `limits.h`.
pub const _PC_NAME_MAX: c_int = 3;
/// Corresponding pathconf constant for `PATH_MAX` from `limits.h`.
pub const _PC_PATH_MAX: c_int = 4;
/// Corresponding pathconf constant for `PIPE_BUF` from `limits.h`.
pub const _PC_PIPE_BUF: c_int = 5;
/// Corresponding pathconf constant for `_POSIX_CHOWN_RESTRICTED` from
/// `unistd.h`.
pub const _PC_CHOWN_RESTRICTED: c_int = 6;
/// Corresponding pathconf constant for `_POSIX_NO_TRUNC` from `unistd.h`.
pub const _PC_NO_TRUNC: c_int = 7;
/// Check if file (terminal) supports disabling control chars (CC)
/// Corresponding pathconf constant for `_POSIX_VDISABLE` from `unistd.h`.
pub const _PC_VDISABLE: c_int = 8;
/// Corresponding pathconf constant for `_POSIX_SYNC_IO` from `unistd.h`.
pub const _PC_SYNC_IO: c_int = 9;
/// Corresponding pathconf constant for `_POSIX_ASYNC_IO` from `unistd.h`.
pub const _PC_ASYNC_IO: c_int = 10;
/// Corresponding pathconf constant for `_POSIX_PRIO_IO` from `unistd.h`.
pub const _PC_PRIO_IO: c_int = 11;
pub const _PC_SOCK_MAXBUF: c_int = 12;
/// Corresponding pathconf constant for `FILESIZEBITS` from `limits.h`.
pub const _PC_FILESIZEBITS: c_int = 13;
/// Corresponding pathconf constant for `POSIX_REC_INCR_XFER_SIZE` from
/// `limits.h`.
pub const _PC_REC_INCR_XFER_SIZE: c_int = 14;
/// Corresponding pathconf constant for `POSIX_REC_MAX_XFER_SIZE` from
/// `limits.h`.
pub const _PC_REC_MAX_XFER_SIZE: c_int = 15;
/// Corresponding pathconf constant for `POSIX_REC_MIN_XFER_SIZE` from
/// `limits.h`.
pub const _PC_REC_MIN_XFER_SIZE: c_int = 16;
/// Corresponding pathconf constant for `POSIX_REC_XFER_ALIGN` from `limits.h`.
pub const _PC_REC_XFER_ALIGN: c_int = 17;
/// Corresponding pathconf constant for `POSIX_ALLOC_SIZE_MIN` from `limits.h`.
pub const _PC_ALLOC_SIZE_MIN: c_int = 18;
/// Corresponding pathconf constant for `SYMLINK_MAX` from `limits.h`.
pub const _PC_SYMLINK_MAX: c_int = 19;
/// Corresponding pathconf constant for `_POSIX2_SYMLINKS` from `unistd.h`.
pub const _PC_2_SYMLINKS: c_int = 20;
fn pc(name: c_int) -> c_long {
@@ -68,12 +91,30 @@ fn pc(name: c_int) -> c_long {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fpathconf.html>.
///
/// Determines the current value of a configurable limit or option (variable)
/// that is associated with a file or directory.
///
/// Upon success, returns the value of the variable corresponding to `name`. If
/// `name` is invalid, returns `-1` and sets errno to indicate the error.
///
/// # Implementation
/// `_fildes` is ignored.
#[unsafe(no_mangle)]
pub extern "C" fn fpathconf(_fildes: c_int, name: c_int) -> c_long {
pc(name)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fpathconf.html>.
///
/// Determines the current value of a configurable limit or option (variable)
/// that is associated with a file or directory.
///
/// Upon success, returns the value of the variable corresponding to `name`. If
/// `name` is invalid, returns `-1` and sets errno to indicate the error.
///
/// # Implementation
/// `_path` is ignored.
#[unsafe(no_mangle)]
pub extern "C" fn pathconf(_path: *const c_char, name: c_int) -> c_long {
pc(name)