diff --git a/src/header/sys_ioctl/mod.rs b/src/header/sys_ioctl/mod.rs index 9b24f49451..7f53d5f1d1 100644 --- a/src/header/sys_ioctl/mod.rs +++ b/src/header/sys_ioctl/mod.rs @@ -21,6 +21,13 @@ pub struct sgttyb { sg_flags: c_ushort, } +/// Non-POSIX, see . +/// +/// Manipulates the underlying device parameters of special files. +/// +/// Upon success, usually returns `0`. A few operations use the return value +/// as an output parameter and returns a nonnegative value on success. Upon +/// failure, `-1` is returned and errno set to indicate the error. #[unsafe(no_mangle)] pub unsafe extern "C" fn ioctl(fd: c_int, request: c_ulong, out: *mut c_void) -> c_int { // TODO: Somehow support varargs to syscall?? diff --git a/src/header/termios/mod.rs b/src/header/termios/mod.rs index fcb3d140b2..c12e3110d2 100644 --- a/src/header/termios/mod.rs +++ b/src/header/termios/mod.rs @@ -91,67 +91,122 @@ pub struct termios { } /// See . +/// +/// Gets the parameters associated with the terminal referred to by `fildes` +/// and stores them in the termios structure referenced by `termios_p`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcgetattr(fd: c_int, out: *mut termios) -> c_int { - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCGETS, out.cast::()) } +pub unsafe extern "C" fn tcgetattr(fildes: c_int, termios_p: *mut termios) -> c_int { + unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TCGETS, termios_p.cast::()) } } /// See . +/// +/// Sets the parameters associated with the terminal referred to by `fildes` +/// from the termios structure referred to by `termios_p`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcsetattr(fd: c_int, act: c_int, value: *const termios) -> c_int { - if !(0..=2).contains(&act) { - platform::ERRNO.set(errno::EINVAL); - return -1; +pub unsafe extern "C" fn tcsetattr( + fildes: c_int, + optional_actions: c_int, + termios_p: *const termios, +) -> c_int { + match optional_actions { + TCSANOW | TCSADRAIN | TCSAFLUSH => { + // This is safe because ioctl shouldn't modify the value + unsafe { + sys_ioctl::ioctl( + fildes, + sys_ioctl::TCSETS + optional_actions as c_ulong, + termios_p as *mut c_void, + ) + } + } + _ => { + platform::ERRNO.set(errno::EINVAL); + -1 + } } - // This is safe because ioctl shouldn't modify the value - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCSETS + act as c_ulong, value as *mut c_void) } } /// See . +/// +/// Obtains the process group ID of the session for which the terminal +/// specified by `fildes` is the controlling terminal. +/// +/// Upon success, returns the process group ID of the session associated with +/// the terminal. Upon failure, returns `-1` and sets errno to indicate the +/// error. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcgetsid(fd: c_int) -> pid_t { +pub unsafe extern "C" fn tcgetsid(fildes: c_int) -> pid_t { let mut sid = 0; - if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCGSID, (&raw mut sid).cast::()) } < 0 { + if unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TIOCGSID, (&raw mut sid).cast::()) } < 0 + { return -1; } sid } /// See . -#[cfg(target_os = "linux")] +/// +/// Extracts the input baud rate from the termios structure reference to by +/// `termios_p`. +/// +/// Returns a value representing the input baud rate. +/// +/// # Implementation +/// Infallible. Always returns a value. #[unsafe(no_mangle)] pub unsafe extern "C" fn cfgetispeed(termios_p: *const termios) -> speed_t { - unsafe { (*termios_p).__c_ispeed } -} - -/// See . -#[cfg(target_os = "redox")] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn cfgetispeed(termios_p: *const termios) -> speed_t { - //TODO - 0 + #[cfg(target_os = "linux")] + { + unsafe { (*termios_p).__c_ispeed } + } + #[cfg(target_os = "redox")] + { + //TODO + 0 + } } /// See . -#[cfg(target_os = "linux")] +/// +/// Extracts the output baud rate from the termios structure reference to by +/// `termios_p`. +/// +/// Returns a value representing the output baud rate. +/// +/// # Implementation +/// Infallible. Always returns a value. #[unsafe(no_mangle)] pub unsafe extern "C" fn cfgetospeed(termios_p: *const termios) -> speed_t { - unsafe { (*termios_p).__c_ospeed } -} - -/// See . -#[cfg(target_os = "redox")] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn cfgetospeed(termios_p: *const termios) -> speed_t { - //TODO - 0 + #[cfg(target_os = "linux")] + { + unsafe { (*termios_p).__c_ospeed } + } + #[cfg(target_os = "redox")] + { + //TODO + 0 + } } /// See . -#[cfg(target_os = "linux")] +/// +/// Sets the input baud rate stored in the structure pointed to by `termios_p` +/// to `speed`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] pub unsafe extern "C" fn cfsetispeed(termios_p: *mut termios, speed: speed_t) -> c_int { match speed as usize { + // TODO redox impl + #[cfg(target_os = "linux")] B0..=B38400 | B57600..=B4000000 => { unsafe { (*termios_p).__c_ispeed = speed }; 0 @@ -163,20 +218,18 @@ pub unsafe extern "C" fn cfsetispeed(termios_p: *mut termios, speed: speed_t) -> } } -/// See . -#[cfg(target_os = "redox")] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn cfsetispeed(termios_p: *mut termios, speed: speed_t) -> c_int { - //TODO - platform::ERRNO.set(errno::EINVAL); - -1 -} - /// See . -#[cfg(target_os = "linux")] +/// +/// Sets the output baud rate stored in the structure pointed to by `termios_p` +/// to `speed`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] pub unsafe extern "C" fn cfsetospeed(termios_p: *mut termios, speed: speed_t) -> c_int { match speed as usize { + // TODO redox impl + #[cfg(target_os = "linux")] B0..=B38400 | B57600..=B4000000 => { unsafe { (*termios_p).__c_ospeed = speed }; 0 @@ -188,18 +241,18 @@ pub unsafe extern "C" fn cfsetospeed(termios_p: *mut termios, speed: speed_t) -> } } -/// See . -#[cfg(target_os = "redox")] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn cfsetospeed(termios_p: *mut termios, speed: speed_t) -> c_int { - //TODO - platform::ERRNO.set(errno::EINVAL); - -1 -} - -/// Non-POSIX, 4.4 BSD extension +// TODO should be guarded by _BSD_SOURCE or _DEFAULT_SOURCE +/// Non-POSIX, 4.4 BSD extension, see +/// . /// -/// See . +/// Sets both the input and output baud rate stored in the structure pointed to +/// by `termios_p` to `speed`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. +/// +/// # Implementation +/// Calls `cfsetispeed()` and if successful then calls `cfsetospeed()`. #[unsafe(no_mangle)] pub unsafe extern "C" fn cfsetspeed(termios_p: *mut termios, speed: speed_t) -> c_int { let r = unsafe { cfsetispeed(termios_p, speed) }; @@ -210,48 +263,109 @@ pub unsafe extern "C" fn cfsetspeed(termios_p: *mut termios, speed: speed_t) -> } /// See . +/// +/// Discards data written to the object referred to by `fildes` but not +/// transmitted, or data received but not read, depending on the value of +/// `queue_selector`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcflush(fd: c_int, queue: c_int) -> c_int { - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCFLSH, queue as *mut c_void) } +pub unsafe extern "C" fn tcflush(fildes: c_int, queue_selector: c_int) -> c_int { + match queue_selector { + TCIFLUSH | TCOFLUSH | TCIOFLUSH => unsafe { + sys_ioctl::ioctl(fildes, sys_ioctl::TCFLSH, queue_selector as *mut c_void) + }, + _ => { + platform::ERRNO.set(errno::EINVAL); + -1 + } + } } /// See . +/// +/// Blocks until all output written to the object referred to by `fildes` is +/// transmitted. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcdrain(fd: c_int) -> c_int { - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCSBRK, core::ptr::dangling_mut()) } +pub unsafe extern "C" fn tcdrain(fildes: c_int) -> c_int { + unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TCSBRK, core::ptr::dangling_mut()) } } /// See . +/// +/// Causes transmission of a continuous stream of zero-valued bits for at least +/// 0.25 seconds, and not more than 0.5 seconds. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. +/// +/// # Implementation +/// This function does not accept a non-zero duration. `_duration` is ignored +/// and assumed to be `0`. Matches behaviour of musl. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcsendbreak(fd: c_int, _dur: c_int) -> c_int { - // non-zero duration is ignored by musl due to it being - // implementation-defined. we do the same. - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCSBRK, core::ptr::null_mut()) } +pub unsafe extern "C" fn tcsendbreak(fildes: c_int, _duration: c_int) -> c_int { + unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TCSBRK, core::ptr::null_mut()) } } /// See . +/// +/// Gets the terminal window size associated with the terminal referred to by +/// `fildes` and stores it in the winsize structure pointed to by `winsize_p`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcgetwinsize(fd: c_int, sws: *mut winsize) -> c_int { - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCGWINSZ, sws.cast()) } +pub unsafe extern "C" fn tcgetwinsize(fildes: c_int, winsize_p: *mut winsize) -> c_int { + unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TIOCGWINSZ, winsize_p.cast()) } } /// See . +/// +/// Sets the terminal window size associated with the terminal referred to by +/// `fildes` and stores it in the winsize structure pointed to by `winsize_p`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. +/// +/// # Safety +/// It is undefined behaviour if the value of the winsize structure pointed to +/// by `winsize_p` was not derived from the result of a call to +/// `tcsgetwinsize()` on `fildes`. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcsetwinsize(fd: c_int, sws: *const winsize) -> c_int { - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCSWINSZ, sws.cast_mut().cast()) } +pub unsafe extern "C" fn tcsetwinsize(fildes: c_int, winsize_p: *const winsize) -> c_int { + unsafe { sys_ioctl::ioctl(fildes, sys_ioctl::TIOCSWINSZ, winsize_p.cast_mut().cast()) } } /// See . +/// +/// Suspends or restarts transmission or reception of data on the object +/// referred to by `fildes`, depending on the value of `action`. +/// +/// Upon success, returns `0`. Upon failure, returns `-1` and sets errno to +/// indicate the error. #[unsafe(no_mangle)] -pub unsafe extern "C" fn tcflow(fd: c_int, action: c_int) -> c_int { - // non-zero duration is ignored by musl due to it being - // implementation-defined. we do the same. - unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCXONC, action as *mut _) } +pub unsafe extern "C" fn tcflow(fildes: c_int, action: c_int) -> c_int { + match action { + TCIOFF | TCION | TCOOFF | TCOON => unsafe { + sys_ioctl::ioctl(fildes, sys_ioctl::TCXONC, action as *mut _) + }, + _ => { + platform::ERRNO.set(errno::EINVAL); + -1 + } + } } -/// Non-POSIX, BSD extension +// TODO should be guarded by _BSD_SOURCE or _DEFAULT_SOURCE +/// Non-POSIX, BSD extension, see . /// -/// See . +/// Sets the terminal to something similar to "raw" mode: input is available +/// character by character, echoing is disabled, and all special processing of +/// terminal input and output characters is disabled. #[unsafe(no_mangle)] pub unsafe extern "C" fn cfmakeraw(termios_p: *mut termios) { unsafe { diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index cc717d4278..6c04a564d8 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -715,10 +715,16 @@ pub unsafe extern "C" fn getwd(path_name: *mut c_char) -> *mut c_char { } /// See . +/// +/// Checks whether `fildes`, an open file descriptor, is associated with a +/// terminal device. +/// +/// Returns `1` to indicate `fildes` is associated with a terminal device or +/// returns `0` to indicate it is not. #[unsafe(no_mangle)] -pub extern "C" fn isatty(fd: c_int) -> c_int { +pub extern "C" fn isatty(fildes: c_int) -> c_int { let mut t = termios::termios::default(); - if unsafe { termios::tcgetattr(fd, &raw mut t) == 0 } { + if unsafe { termios::tcgetattr(fildes, &raw mut t) == 0 } { 1 } else { 0