diff --git a/CHANGELOG.md b/CHANGELOG.md index ff4c9beb68..8ef0cd6f8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate ### Added - Added `mremap` (#[1306](https://github.com/nix-rust/nix/pull/1306)) +- `nix::sys::termios::Termios` now implements `Sync` and `Copy`. +- There are now `From` implementations for converting both ways between + `libc::termios` and `nix::sys::termios::Termios`. ### Changed ### Fixed ### Removed diff --git a/src/pty.rs b/src/pty.rs index 3a6a9232f4..450fb8ba42 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -243,7 +243,7 @@ pub fn openpty<'a, 'b, T: Into>, U: Into master.as_mut_ptr(), slave.as_mut_ptr(), ptr::null_mut(), - &*inner_termios as *const libc::termios as *mut _, + &inner_termios as *const libc::termios as *mut _, winsize as *const Winsize as *mut _, ) } @@ -266,7 +266,7 @@ pub fn openpty<'a, 'b, T: Into>, U: Into master.as_mut_ptr(), slave.as_mut_ptr(), ptr::null_mut(), - &*inner_termios as *const libc::termios as *mut _, + &inner_termios as *const libc::termios as *mut _, ptr::null_mut(), ) } @@ -313,7 +313,7 @@ pub fn forkpty<'a, 'b, T: Into>, U: Into let term = match termios.into() { Some(termios) => { let inner_termios = termios.get_libc_termios(); - &*inner_termios as *const libc::termios as *mut _ + &inner_termios as *const libc::termios as *mut _ }, None => ptr::null_mut(), }; diff --git a/src/sys/termios.rs b/src/sys/termios.rs index c30de80d4b..eb4314a962 100644 --- a/src/sys/termios.rs +++ b/src/sys/termios.rs @@ -155,7 +155,6 @@ use cfg_if::cfg_if; use crate::{Error, Result}; use crate::errno::Errno; use libc::{self, c_int, tcflag_t}; -use std::cell::{Ref, RefCell}; use std::convert::{From, TryFrom}; use std::mem; use std::os::unix::io::RawFd; @@ -167,9 +166,14 @@ use crate::unistd::Pid; /// This is a wrapper around the `libc::termios` struct that provides a safe interface for the /// standard fields. The only safe way to obtain an instance of this struct is to extract it from /// an open port using `tcgetattr()`. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Termios { - inner: RefCell, + // The actual fields present in `libc::termios` vary from one platform to + // another. By only constructing `Termios` values from actual tcgetattr + // calls, we ensure that unknown fields have reasonable values. We just need + // to remember to update `inner` before it's read, and update the public + // fields after `inner` has been modified. + inner: libc::termios, /// Input mode flags (see `termios.c_iflag` documentation) pub input_flags: InputFlags, /// Output mode flags (see `termios.c_oflag` documentation) @@ -187,39 +191,19 @@ impl Termios { /// /// This is not part of `nix`'s public API because it requires additional work to maintain type /// safety. - pub(crate) fn get_libc_termios(&self) -> Ref { - { - let mut termios = self.inner.borrow_mut(); - termios.c_iflag = self.input_flags.bits(); - termios.c_oflag = self.output_flags.bits(); - termios.c_cflag = self.control_flags.bits(); - termios.c_lflag = self.local_flags.bits(); - termios.c_cc = self.control_chars; - } - self.inner.borrow() - } - - /// Exposes the inner `libc::termios` datastore within `Termios`. - /// - /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will - /// not automatically update the safe wrapper type around it. In this case it should also be - /// paired with a call to `update_wrapper()` so that the wrapper-type and internal - /// representation stay consistent. - pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios { - { - let mut termios = self.inner.borrow_mut(); - termios.c_iflag = self.input_flags.bits(); - termios.c_oflag = self.output_flags.bits(); - termios.c_cflag = self.control_flags.bits(); - termios.c_lflag = self.local_flags.bits(); - termios.c_cc = self.control_chars; - } - self.inner.as_ptr() + pub(crate) fn get_libc_termios(&self) -> libc::termios { + let mut termios = self.inner.clone(); + termios.c_iflag = self.input_flags.bits(); + termios.c_oflag = self.output_flags.bits(); + termios.c_cflag = self.control_flags.bits(); + termios.c_lflag = self.local_flags.bits(); + termios.c_cc = self.control_chars; + termios } /// Updates the wrapper values from the internal `libc::termios` data structure. - pub(crate) fn update_wrapper(&mut self) { - let termios = *self.inner.borrow_mut(); + pub(crate) fn set_libc_termios(&mut self, termios: &libc::termios) { + self.inner = *termios; self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag); self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag); self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); @@ -231,7 +215,7 @@ impl Termios { impl From for Termios { fn from(termios: libc::termios) -> Self { Termios { - inner: RefCell::new(termios), + inner: termios, input_flags: InputFlags::from_bits_truncate(termios.c_iflag), output_flags: OutputFlags::from_bits_truncate(termios.c_oflag), control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), @@ -243,7 +227,7 @@ impl From for Termios { impl From for libc::termios { fn from(termios: Termios) -> Self { - termios.inner.into_inner() + termios.inner } } @@ -881,7 +865,7 @@ cfg_if!{ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. pub fn cfgetispeed(termios: &Termios) -> u32 { let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetispeed(&*inner_termios) as u32 } + unsafe { libc::cfgetispeed(&inner_termios) as u32 } } /// Get output baud rate (see @@ -890,7 +874,7 @@ cfg_if!{ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. pub fn cfgetospeed(termios: &Termios) -> u32 { let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetospeed(&*inner_termios) as u32 } + unsafe { libc::cfgetospeed(&inner_termios) as u32 } } /// Set input baud rate (see @@ -898,9 +882,9 @@ cfg_if!{ /// /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. pub fn cfsetispeed>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); + let mut inner_termios = termios.get_libc_termios(); + let res = unsafe { libc::cfsetispeed(&mut inner_termios as *mut _, baud.into() as libc::speed_t) }; + termios.set_libc_termios(&inner_termios); Errno::result(res).map(drop) } @@ -909,9 +893,9 @@ cfg_if!{ /// /// `cfsetospeed()` sets the output baud rate in the given termios structure. pub fn cfsetospeed>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); + let mut inner_termios = termios.get_libc_termios(); + let res = unsafe { libc::cfsetospeed(&mut inner_termios as *mut _, baud.into() as libc::speed_t) }; + termios.set_libc_termios(&inner_termios); Errno::result(res).map(drop) } @@ -921,9 +905,9 @@ cfg_if!{ /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that /// this is part of the 4.4BSD standard and not part of POSIX. pub fn cfsetspeed>(termios: &mut Termios, baud: T) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) }; - termios.update_wrapper(); + let mut inner_termios = termios.get_libc_termios(); + let res = unsafe { libc::cfsetspeed(&mut inner_termios as *mut _, baud.into() as libc::speed_t) }; + termios.set_libc_termios(&inner_termios); Errno::result(res).map(drop) } } else { @@ -935,7 +919,7 @@ cfg_if!{ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. pub fn cfgetispeed(termios: &Termios) -> BaudRate { let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap() + unsafe { libc::cfgetispeed(&inner_termios) }.try_into().unwrap() } /// Get output baud rate (see @@ -944,7 +928,7 @@ cfg_if!{ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. pub fn cfgetospeed(termios: &Termios) -> BaudRate { let inner_termios = termios.get_libc_termios(); - unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap() + unsafe { libc::cfgetospeed(&inner_termios) }.try_into().unwrap() } /// Set input baud rate (see @@ -952,9 +936,9 @@ cfg_if!{ /// /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); + let mut inner_termios = termios.get_libc_termios(); + let res = unsafe { libc::cfsetispeed(&mut inner_termios as *mut _, baud as libc::speed_t) }; + termios.set_libc_termios(&inner_termios); Errno::result(res).map(drop) } @@ -963,9 +947,9 @@ cfg_if!{ /// /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure. pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); + let mut inner_termios = termios.get_libc_termios(); + let res = unsafe { libc::cfsetospeed(&mut inner_termios as *mut _, baud as libc::speed_t) }; + termios.set_libc_termios(&inner_termios); Errno::result(res).map(drop) } @@ -975,9 +959,9 @@ cfg_if!{ /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that /// this is part of the 4.4BSD standard and not part of POSIX. pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; - let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) }; - termios.update_wrapper(); + let mut inner_termios = termios.get_libc_termios(); + let res = unsafe { libc::cfsetspeed(&mut inner_termios as *mut _, baud as libc::speed_t) }; + termios.set_libc_termios(&inner_termios); Errno::result(res).map(drop) } } @@ -990,11 +974,11 @@ cfg_if!{ /// character, echoing is disabled, and all special input and output processing is disabled. Note /// that this is a non-standard function, but is available on Linux and BSDs. pub fn cfmakeraw(termios: &mut Termios) { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let mut inner_termios = termios.get_libc_termios(); unsafe { - libc::cfmakeraw(inner_termios); + libc::cfmakeraw(&mut inner_termios as *mut _); } - termios.update_wrapper(); + termios.set_libc_termios(&inner_termios); } /// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see @@ -1003,11 +987,11 @@ pub fn cfmakeraw(termios: &mut Termios) { /// Note that this is a non-standard function, available on FreeBSD. #[cfg(target_os = "freebsd")] pub fn cfmakesane(termios: &mut Termios) { - let inner_termios = unsafe { termios.get_libc_termios_mut() }; + let mut inner_termios = termios.get_libc_termios(); unsafe { - libc::cfmakesane(inner_termios); + libc::cfmakesane(&mut inner_termios as *mut _); } - termios.update_wrapper(); + termios.set_libc_termios(&inner_termios); } /// Return the configuration of a port @@ -1034,7 +1018,7 @@ pub fn tcgetattr(fd: RawFd) -> Result { /// *any* of the parameters were successfully set, not only if all were set successfully. pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { let inner_termios = termios.get_libc_termios(); - Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(drop) + Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &inner_termios) }).map(drop) } /// Block until all output data is written (see