From d5afd3fe812831da65720fc1da9949071c24ef30 Mon Sep 17 00:00:00 2001 From: auronandace Date: Thu, 9 Jul 2026 13:23:16 +0100 Subject: [PATCH] add documentation for functions relating to controlling terminal --- src/header/limits/mod.rs | 20 +++++++++ src/header/stdio/constants.rs | 1 + src/header/stdio/mod.rs | 19 ++++++++ src/header/stdlib/mod.rs | 79 ++++++++++++++++++++------------- src/header/termios/constants.rs | 4 -- src/header/unistd/mod.rs | 62 +++++++++++++++++++++++--- src/header/unistd/pathconf.rs | 45 ++++++++++++++++++- 7 files changed, 187 insertions(+), 43 deletions(-) diff --git a/src/header/limits/mod.rs b/src/header/limits/mod.rs index 36cefe02d6..cfc5a32f70 100644 --- a/src/header/limits/mod.rs +++ b/src/header/limits/mod.rs @@ -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 diff --git a/src/header/stdio/constants.rs b/src/header/stdio/constants.rs index ad2153f96d..834c18c9a1 100644 --- a/src/header/stdio/constants.rs +++ b/src/header/stdio/constants.rs @@ -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; diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index 18c8c866f3..4e8b30e72f 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -300,6 +300,25 @@ pub unsafe extern "C" fn clearerr(stream: *mut FILE) { } /// See . +/// +/// 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"; diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 743ebe0a4e..a873109daf 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -938,11 +938,25 @@ pub unsafe extern "C" fn posix_openpt(flags: c_int) -> c_int { } /// See . +/// +/// 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 . +/// +/// 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::()) } == 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::()) } == 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() } } diff --git a/src/header/termios/constants.rs b/src/header/termios/constants.rs index db7d67a697..6415d2513f 100644 --- a/src/header/termios/constants.rs +++ b/src/header/termios/constants.rs @@ -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; diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 47fd8fecd5..4c730b9a47 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -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 . +/// +/// 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 . +/// +/// 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 . +/// +/// 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 . +/// +/// 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 . diff --git a/src/header/unistd/pathconf.rs b/src/header/unistd/pathconf.rs index 81848a719e..742f1439a2 100644 --- a/src/header/unistd/pathconf.rs +++ b/src/header/unistd/pathconf.rs @@ -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 . +/// +/// 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 . +/// +/// 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)