summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/backend/libc/termios/syscalls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/backend/libc/termios/syscalls.rs')
-rw-r--r--vendor/rustix/src/backend/libc/termios/syscalls.rs297
1 files changed, 219 insertions, 78 deletions
diff --git a/vendor/rustix/src/backend/libc/termios/syscalls.rs b/vendor/rustix/src/backend/libc/termios/syscalls.rs
index dba73c960..d4182f4fe 100644
--- a/vendor/rustix/src/backend/libc/termios/syscalls.rs
+++ b/vendor/rustix/src/backend/libc/termios/syscalls.rs
@@ -4,46 +4,62 @@
//!
//! See the `rustix::backend::syscalls` module documentation for details.
-use super::super::c;
-use super::super::conv::{borrowed_fd, ret, ret_pid_t};
+use crate::backend::c;
+use crate::backend::conv::{borrowed_fd, ret, ret_pid_t};
use crate::fd::BorrowedFd;
#[cfg(feature = "procfs")]
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
use crate::ffi::CStr;
-#[cfg(not(target_os = "wasi"))]
-use crate::io;
-#[cfg(not(target_os = "wasi"))]
-use crate::process::{Pid, RawNonZeroPid};
-#[cfg(not(target_os = "wasi"))]
-use crate::termios::{Action, OptionalActions, QueueSelector, Speed, Termios, Winsize};
use core::mem::MaybeUninit;
+#[cfg(not(target_os = "wasi"))]
+use {
+ crate::io,
+ crate::pid::Pid,
+ crate::termios::{Action, OptionalActions, QueueSelector, Termios, Winsize},
+ crate::utils::as_mut_ptr,
+};
#[cfg(not(target_os = "wasi"))]
pub(crate) fn tcgetattr(fd: BorrowedFd<'_>) -> io::Result<Termios> {
- let mut result = MaybeUninit::<Termios>::uninit();
+ // If we have `TCGETS2`, use it, so that we fill in the `c_ispeed` and
+ // `c_ospeed` fields.
+ #[cfg(linux_kernel)]
unsafe {
- ret(c::tcgetattr(borrowed_fd(fd), result.as_mut_ptr()))?;
- Ok(result.assume_init())
+ use crate::termios::{ControlModes, InputModes, LocalModes, OutputModes, SpecialCodes};
+ use core::mem::zeroed;
+
+ let mut termios2 = MaybeUninit::<c::termios2>::uninit();
+
+ ret(c::ioctl(
+ borrowed_fd(fd),
+ c::TCGETS2.into(),
+ termios2.as_mut_ptr(),
+ ))?;
+
+ let termios2 = termios2.assume_init();
+
+ // Convert from the Linux `termios2` to our `Termios`.
+ let mut result = Termios {
+ input_modes: InputModes::from_bits_retain(termios2.c_iflag),
+ output_modes: OutputModes::from_bits_retain(termios2.c_oflag),
+ control_modes: ControlModes::from_bits_retain(termios2.c_cflag),
+ local_modes: LocalModes::from_bits_retain(termios2.c_lflag),
+ line_discipline: termios2.c_line,
+ special_codes: SpecialCodes(zeroed()),
+ input_speed: termios2.c_ispeed,
+ output_speed: termios2.c_ospeed,
+ };
+ result.special_codes.0[..termios2.c_cc.len()].copy_from_slice(&termios2.c_cc);
+
+ Ok(result)
}
-}
-#[cfg(all(
- any(target_os = "android", target_os = "linux"),
- any(
- target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "x32",
- target_arch = "riscv64",
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "mips",
- target_arch = "mips64",
- )
-))]
-pub(crate) fn tcgetattr2(fd: BorrowedFd<'_>) -> io::Result<crate::termios::Termios2> {
- let mut result = MaybeUninit::<crate::termios::Termios2>::uninit();
+ #[cfg(not(linux_kernel))]
unsafe {
- ret(c::ioctl(borrowed_fd(fd), c::TCGETS2, result.as_mut_ptr()))?;
+ let mut result = MaybeUninit::<Termios>::uninit();
+
+ ret(c::tcgetattr(borrowed_fd(fd), result.as_mut_ptr().cast()))?;
+
Ok(result.assume_init())
}
}
@@ -52,8 +68,7 @@ pub(crate) fn tcgetattr2(fd: BorrowedFd<'_>) -> io::Result<crate::termios::Termi
pub(crate) fn tcgetpgrp(fd: BorrowedFd<'_>) -> io::Result<Pid> {
unsafe {
let pid = ret_pid_t(c::tcgetpgrp(borrowed_fd(fd)))?;
- debug_assert_ne!(pid, 0);
- Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid)))
+ Ok(Pid::from_raw_unchecked(pid))
}
}
@@ -68,38 +83,65 @@ pub(crate) fn tcsetattr(
optional_actions: OptionalActions,
termios: &Termios,
) -> io::Result<()> {
+ // If we have `TCSETS2`, use it, so that we use the `c_ispeed` and
+ // `c_ospeed` fields.
+ #[cfg(linux_kernel)]
unsafe {
- ret(c::tcsetattr(
- borrowed_fd(fd),
- optional_actions as _,
- termios,
- ))
+ use crate::termios::speed;
+ use core::mem::zeroed;
+ use linux_raw_sys::general::{termios2, BOTHER, CBAUD, IBSHIFT};
+
+ #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))]
+ use linux_raw_sys::ioctl::{TCSETS, TCSETS2};
+
+ // linux-raw-sys' ioctl-generation script for sparc isn't working yet,
+ // so as a temporary workaround, declare these manually.
+ #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
+ const TCSETS: u32 = 0x80245409;
+ #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
+ const TCSETS2: u32 = 0x802c540d;
+
+ // Translate from `optional_actions` into an ioctl request code. On MIPS,
+ // `optional_actions` already has `TCGETS` added to it.
+ let request = TCSETS2
+ + if cfg!(any(target_arch = "mips", target_arch = "mips64")) {
+ optional_actions as u32 - TCSETS
+ } else {
+ optional_actions as u32
+ };
+
+ let input_speed = termios.input_speed();
+ let output_speed = termios.output_speed();
+ let mut termios2 = termios2 {
+ c_iflag: termios.input_modes.bits(),
+ c_oflag: termios.output_modes.bits(),
+ c_cflag: termios.control_modes.bits(),
+ c_lflag: termios.local_modes.bits(),
+ c_line: termios.line_discipline,
+ c_cc: zeroed(),
+ c_ispeed: input_speed,
+ c_ospeed: output_speed,
+ };
+ // Ensure that our input and output speeds are set, as `libc`
+ // routines don't always support setting these separately.
+ termios2.c_cflag &= !CBAUD;
+ termios2.c_cflag |= speed::encode(output_speed).unwrap_or(BOTHER);
+ termios2.c_cflag &= !(CBAUD << IBSHIFT);
+ termios2.c_cflag |= speed::encode(input_speed).unwrap_or(BOTHER) << IBSHIFT;
+ let nccs = termios2.c_cc.len();
+ termios2
+ .c_cc
+ .copy_from_slice(&termios.special_codes.0[..nccs]);
+
+ ret(c::ioctl(borrowed_fd(fd), request as _, &termios2))
}
-}
-#[cfg(all(
- any(target_os = "android", target_os = "linux"),
- any(
- target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "x32",
- target_arch = "riscv64",
- target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "mips",
- target_arch = "mips64",
- )
-))]
-pub(crate) fn tcsetattr2(
- fd: BorrowedFd,
- optional_actions: OptionalActions,
- termios: &crate::termios::Termios2,
-) -> io::Result<()> {
+ #[cfg(not(linux_kernel))]
unsafe {
- ret(c::ioctl(
+ ret(c::tcsetattr(
borrowed_fd(fd),
- (c::TCSETS2 as u32 + optional_actions as u32) as _,
- termios,
+ optional_actions as _,
+ crate::utils::as_ptr(termios).cast(),
))
}
}
@@ -128,8 +170,7 @@ pub(crate) fn tcflow(fd: BorrowedFd, action: Action) -> io::Result<()> {
pub(crate) fn tcgetsid(fd: BorrowedFd) -> io::Result<Pid> {
unsafe {
let pid = ret_pid_t(c::tcgetsid(borrowed_fd(fd)))?;
- debug_assert_ne!(pid, 0);
- Ok(Pid::from_raw_nonzero(RawNonZeroPid::new_unchecked(pid)))
+ Ok(Pid::from_raw_unchecked(pid))
}
}
@@ -151,42 +192,142 @@ pub(crate) fn tcgetwinsize(fd: BorrowedFd) -> io::Result<Winsize> {
}
}
-#[cfg(not(target_os = "wasi"))]
-#[inline]
-#[must_use]
-pub(crate) fn cfgetospeed(termios: &Termios) -> Speed {
- unsafe { c::cfgetospeed(termios) }
+#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
+pub(crate) fn ioctl_tiocexcl(fd: BorrowedFd) -> io::Result<()> {
+ unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCEXCL as _)) }
}
-#[cfg(not(target_os = "wasi"))]
-#[inline]
-#[must_use]
-pub(crate) fn cfgetispeed(termios: &Termios) -> Speed {
- unsafe { c::cfgetispeed(termios) }
+#[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))]
+pub(crate) fn ioctl_tiocnxcl(fd: BorrowedFd) -> io::Result<()> {
+ unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCNXCL as _)) }
}
#[cfg(not(target_os = "wasi"))]
#[inline]
-pub(crate) fn cfmakeraw(termios: &mut Termios) {
- unsafe { c::cfmakeraw(termios) }
+pub(crate) fn set_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> {
+ #[cfg(bsd)]
+ let encoded_speed = arbitrary_speed;
+
+ #[cfg(not(bsd))]
+ let encoded_speed = match crate::termios::speed::encode(arbitrary_speed) {
+ Some(encoded_speed) => encoded_speed,
+ #[cfg(linux_kernel)]
+ None => c::BOTHER,
+ #[cfg(not(linux_kernel))]
+ None => return Err(io::Errno::INVAL),
+ };
+
+ #[cfg(not(linux_kernel))]
+ unsafe {
+ ret(c::cfsetspeed(
+ as_mut_ptr(termios).cast(),
+ encoded_speed.into(),
+ ))
+ }
+
+ // Linux libc implementations don't support arbitrary speeds, so we encode
+ // the speed manually.
+ #[cfg(linux_kernel)]
+ {
+ use crate::termios::ControlModes;
+
+ debug_assert_eq!(encoded_speed & !c::CBAUD, 0);
+
+ termios.control_modes -= ControlModes::from_bits_retain(c::CBAUD | c::CIBAUD);
+ termios.control_modes |=
+ ControlModes::from_bits_retain(encoded_speed | (encoded_speed << c::IBSHIFT));
+
+ termios.input_speed = arbitrary_speed;
+ termios.output_speed = arbitrary_speed;
+
+ Ok(())
+ }
}
#[cfg(not(target_os = "wasi"))]
#[inline]
-pub(crate) fn cfsetospeed(termios: &mut Termios, speed: Speed) -> io::Result<()> {
- unsafe { ret(c::cfsetospeed(termios, speed)) }
+pub(crate) fn set_output_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> {
+ #[cfg(bsd)]
+ let encoded_speed = arbitrary_speed;
+
+ #[cfg(not(bsd))]
+ let encoded_speed = match crate::termios::speed::encode(arbitrary_speed) {
+ Some(encoded_speed) => encoded_speed,
+ #[cfg(linux_kernel)]
+ None => c::BOTHER,
+ #[cfg(not(linux_kernel))]
+ None => return Err(io::Errno::INVAL),
+ };
+
+ #[cfg(not(linux_kernel))]
+ unsafe {
+ ret(c::cfsetospeed(
+ as_mut_ptr(termios).cast(),
+ encoded_speed.into(),
+ ))
+ }
+
+ // Linux libc implementations don't support arbitrary speeds or setting the
+ // input and output speeds separately, so we encode the speed manually.
+ #[cfg(linux_kernel)]
+ {
+ use crate::termios::ControlModes;
+
+ debug_assert_eq!(encoded_speed & !c::CBAUD, 0);
+
+ termios.control_modes -= ControlModes::from_bits_retain(c::CBAUD);
+ termios.control_modes |= ControlModes::from_bits_retain(encoded_speed);
+
+ termios.output_speed = arbitrary_speed;
+
+ Ok(())
+ }
}
#[cfg(not(target_os = "wasi"))]
#[inline]
-pub(crate) fn cfsetispeed(termios: &mut Termios, speed: Speed) -> io::Result<()> {
- unsafe { ret(c::cfsetispeed(termios, speed)) }
+pub(crate) fn set_input_speed(termios: &mut Termios, arbitrary_speed: u32) -> io::Result<()> {
+ #[cfg(bsd)]
+ let encoded_speed = arbitrary_speed;
+
+ #[cfg(not(bsd))]
+ let encoded_speed = match crate::termios::speed::encode(arbitrary_speed) {
+ Some(encoded_speed) => encoded_speed,
+ #[cfg(linux_kernel)]
+ None => c::BOTHER,
+ #[cfg(not(linux_kernel))]
+ None => return Err(io::Errno::INVAL),
+ };
+
+ #[cfg(not(linux_kernel))]
+ unsafe {
+ ret(c::cfsetispeed(
+ as_mut_ptr(termios).cast(),
+ encoded_speed.into(),
+ ))
+ }
+
+ // Linux libc implementations don't support arbitrary speeds or setting the
+ // input and output speeds separately, so we encode the speed manually.
+ #[cfg(linux_kernel)]
+ {
+ use crate::termios::ControlModes;
+
+ debug_assert_eq!(encoded_speed & !c::CBAUD, 0);
+
+ termios.control_modes -= ControlModes::from_bits_retain(c::CIBAUD);
+ termios.control_modes |= ControlModes::from_bits_retain(encoded_speed << c::IBSHIFT);
+
+ termios.input_speed = arbitrary_speed;
+
+ Ok(())
+ }
}
#[cfg(not(target_os = "wasi"))]
#[inline]
-pub(crate) fn cfsetspeed(termios: &mut Termios, speed: Speed) -> io::Result<()> {
- unsafe { ret(c::cfsetspeed(termios, speed)) }
+pub(crate) fn cfmakeraw(termios: &mut Termios) {
+ unsafe { c::cfmakeraw(as_mut_ptr(termios).cast()) }
}
pub(crate) fn isatty(fd: BorrowedFd<'_>) -> bool {
@@ -200,7 +341,7 @@ pub(crate) fn isatty(fd: BorrowedFd<'_>) -> bool {
#[cfg(feature = "procfs")]
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
-pub(crate) fn ttyname(dirfd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> {
+pub(crate) fn ttyname(dirfd: BorrowedFd<'_>, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
unsafe {
// `ttyname_r` returns its error status rather than using `errno`.
match c::ttyname_r(borrowed_fd(dirfd), buf.as_mut_ptr().cast(), buf.len()) {