@@ -155,7 +155,6 @@ use cfg_if::cfg_if;
155155use crate :: { Error , Result } ;
156156use crate :: errno:: Errno ;
157157use libc:: { self , c_int, tcflag_t} ;
158- use std:: cell:: { Ref , RefCell } ;
159158use std:: convert:: { From , TryFrom } ;
160159use std:: mem;
161160use std:: os:: unix:: io:: RawFd ;
@@ -167,9 +166,14 @@ use crate::unistd::Pid;
167166/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
168167/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
169168/// an open port using `tcgetattr()`.
170- #[ derive( Clone , Debug , Eq , PartialEq ) ]
169+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
171170pub struct Termios {
172- inner : RefCell < libc:: termios > ,
171+ // The actual fields present in `libc::termios` vary from one platform to
172+ // another. By only constructing `Termios` values from actual tcgetattr
173+ // calls, we ensure that unknown fields have reasonable values. We just need
174+ // to remember to update `inner` before it's read, and update the public
175+ // fields after `inner` has been modified.
176+ inner : libc:: termios ,
173177 /// Input mode flags (see `termios.c_iflag` documentation)
174178 pub input_flags : InputFlags ,
175179 /// Output mode flags (see `termios.c_oflag` documentation)
@@ -187,39 +191,19 @@ impl Termios {
187191 ///
188192 /// This is not part of `nix`'s public API because it requires additional work to maintain type
189193 /// safety.
190- pub ( crate ) fn get_libc_termios ( & self ) -> Ref < libc:: termios > {
191- {
192- let mut termios = self . inner . borrow_mut ( ) ;
193- termios. c_iflag = self . input_flags . bits ( ) ;
194- termios. c_oflag = self . output_flags . bits ( ) ;
195- termios. c_cflag = self . control_flags . bits ( ) ;
196- termios. c_lflag = self . local_flags . bits ( ) ;
197- termios. c_cc = self . control_chars ;
198- }
199- self . inner . borrow ( )
200- }
201-
202- /// Exposes the inner `libc::termios` datastore within `Termios`.
203- ///
204- /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will
205- /// not automatically update the safe wrapper type around it. In this case it should also be
206- /// paired with a call to `update_wrapper()` so that the wrapper-type and internal
207- /// representation stay consistent.
208- pub ( crate ) unsafe fn get_libc_termios_mut ( & mut self ) -> * mut libc:: termios {
209- {
210- let mut termios = self . inner . borrow_mut ( ) ;
211- termios. c_iflag = self . input_flags . bits ( ) ;
212- termios. c_oflag = self . output_flags . bits ( ) ;
213- termios. c_cflag = self . control_flags . bits ( ) ;
214- termios. c_lflag = self . local_flags . bits ( ) ;
215- termios. c_cc = self . control_chars ;
216- }
217- self . inner . as_ptr ( )
194+ pub ( crate ) fn get_libc_termios ( & self ) -> libc:: termios {
195+ let mut termios = self . inner . clone ( ) ;
196+ termios. c_iflag = self . input_flags . bits ( ) ;
197+ termios. c_oflag = self . output_flags . bits ( ) ;
198+ termios. c_cflag = self . control_flags . bits ( ) ;
199+ termios. c_lflag = self . local_flags . bits ( ) ;
200+ termios. c_cc = self . control_chars ;
201+ termios
218202 }
219203
220204 /// Updates the wrapper values from the internal `libc::termios` data structure.
221- pub ( crate ) fn update_wrapper ( & mut self ) {
222- let termios = * self . inner . borrow_mut ( ) ;
205+ pub ( crate ) fn set_libc_termios ( & mut self , termios : & libc :: termios ) {
206+ self . inner = * termios ;
223207 self . input_flags = InputFlags :: from_bits_truncate ( termios. c_iflag ) ;
224208 self . output_flags = OutputFlags :: from_bits_truncate ( termios. c_oflag ) ;
225209 self . control_flags = ControlFlags :: from_bits_truncate ( termios. c_cflag ) ;
@@ -231,7 +215,7 @@ impl Termios {
231215impl From < libc:: termios > for Termios {
232216 fn from ( termios : libc:: termios ) -> Self {
233217 Termios {
234- inner : RefCell :: new ( termios) ,
218+ inner : termios,
235219 input_flags : InputFlags :: from_bits_truncate ( termios. c_iflag ) ,
236220 output_flags : OutputFlags :: from_bits_truncate ( termios. c_oflag ) ,
237221 control_flags : ControlFlags :: from_bits_truncate ( termios. c_cflag ) ,
@@ -243,7 +227,7 @@ impl From<libc::termios> for Termios {
243227
244228impl From < Termios > for libc:: termios {
245229 fn from ( termios : Termios ) -> Self {
246- termios. inner . into_inner ( )
230+ termios. inner
247231 }
248232}
249233
@@ -881,7 +865,7 @@ cfg_if!{
881865 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
882866 pub fn cfgetispeed( termios: & Termios ) -> u32 {
883867 let inner_termios = termios. get_libc_termios( ) ;
884- unsafe { libc:: cfgetispeed( & * inner_termios) as u32 }
868+ unsafe { libc:: cfgetispeed( & inner_termios) as u32 }
885869 }
886870
887871 /// Get output baud rate (see
@@ -890,17 +874,17 @@ cfg_if!{
890874 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
891875 pub fn cfgetospeed( termios: & Termios ) -> u32 {
892876 let inner_termios = termios. get_libc_termios( ) ;
893- unsafe { libc:: cfgetospeed( & * inner_termios) as u32 }
877+ unsafe { libc:: cfgetospeed( & inner_termios) as u32 }
894878 }
895879
896880 /// Set input baud rate (see
897881 /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
898882 ///
899883 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
900884 pub fn cfsetispeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
901- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
902- let res = unsafe { libc:: cfsetispeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
903- termios. update_wrapper ( ) ;
885+ let mut inner_termios = termios. get_libc_termios ( ) ;
886+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
887+ termios. set_libc_termios ( & inner_termios ) ;
904888 Errno :: result( res) . map( drop)
905889 }
906890
@@ -909,9 +893,9 @@ cfg_if!{
909893 ///
910894 /// `cfsetospeed()` sets the output baud rate in the given termios structure.
911895 pub fn cfsetospeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
912- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
913- let res = unsafe { libc:: cfsetospeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
914- termios. update_wrapper ( ) ;
896+ let mut inner_termios = termios. get_libc_termios ( ) ;
897+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
898+ termios. set_libc_termios ( & inner_termios ) ;
915899 Errno :: result( res) . map( drop)
916900 }
917901
@@ -921,9 +905,9 @@ cfg_if!{
921905 /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
922906 /// this is part of the 4.4BSD standard and not part of POSIX.
923907 pub fn cfsetspeed<T : Into <u32 >>( termios: & mut Termios , baud: T ) -> Result <( ) > {
924- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
925- let res = unsafe { libc:: cfsetspeed( inner_termios, baud. into( ) as libc:: speed_t) } ;
926- termios. update_wrapper ( ) ;
908+ let mut inner_termios = termios. get_libc_termios ( ) ;
909+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
910+ termios. set_libc_termios ( & inner_termios ) ;
927911 Errno :: result( res) . map( drop)
928912 }
929913 } else {
@@ -935,7 +919,7 @@ cfg_if!{
935919 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
936920 pub fn cfgetispeed( termios: & Termios ) -> BaudRate {
937921 let inner_termios = termios. get_libc_termios( ) ;
938- unsafe { libc:: cfgetispeed( & * inner_termios) } . try_into( ) . unwrap( )
922+ unsafe { libc:: cfgetispeed( & inner_termios) } . try_into( ) . unwrap( )
939923 }
940924
941925 /// Get output baud rate (see
@@ -944,17 +928,17 @@ cfg_if!{
944928 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
945929 pub fn cfgetospeed( termios: & Termios ) -> BaudRate {
946930 let inner_termios = termios. get_libc_termios( ) ;
947- unsafe { libc:: cfgetospeed( & * inner_termios) } . try_into( ) . unwrap( )
931+ unsafe { libc:: cfgetospeed( & inner_termios) } . try_into( ) . unwrap( )
948932 }
949933
950934 /// Set input baud rate (see
951935 /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
952936 ///
953937 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
954938 pub fn cfsetispeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
955- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
956- let res = unsafe { libc:: cfsetispeed( inner_termios, baud as libc:: speed_t) } ;
957- termios. update_wrapper ( ) ;
939+ let mut inner_termios = termios. get_libc_termios ( ) ;
940+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
941+ termios. set_libc_termios ( & inner_termios ) ;
958942 Errno :: result( res) . map( drop)
959943 }
960944
@@ -963,9 +947,9 @@ cfg_if!{
963947 ///
964948 /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
965949 pub fn cfsetospeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
966- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
967- let res = unsafe { libc:: cfsetospeed( inner_termios, baud as libc:: speed_t) } ;
968- termios. update_wrapper ( ) ;
950+ let mut inner_termios = termios. get_libc_termios ( ) ;
951+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
952+ termios. set_libc_termios ( & inner_termios ) ;
969953 Errno :: result( res) . map( drop)
970954 }
971955
@@ -975,9 +959,9 @@ cfg_if!{
975959 /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
976960 /// this is part of the 4.4BSD standard and not part of POSIX.
977961 pub fn cfsetspeed( termios: & mut Termios , baud: BaudRate ) -> Result <( ) > {
978- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
979- let res = unsafe { libc:: cfsetspeed( inner_termios, baud as libc:: speed_t) } ;
980- termios. update_wrapper ( ) ;
962+ let mut inner_termios = termios. get_libc_termios ( ) ;
963+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
964+ termios. set_libc_termios ( & inner_termios ) ;
981965 Errno :: result( res) . map( drop)
982966 }
983967 }
@@ -990,11 +974,11 @@ cfg_if!{
990974/// character, echoing is disabled, and all special input and output processing is disabled. Note
991975/// that this is a non-standard function, but is available on Linux and BSDs.
992976pub fn cfmakeraw ( termios : & mut Termios ) {
993- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
977+ let mut inner_termios = termios. get_libc_termios ( ) ;
994978 unsafe {
995- libc:: cfmakeraw ( inner_termios) ;
979+ libc:: cfmakeraw ( & mut inner_termios as * mut _ ) ;
996980 }
997- termios. update_wrapper ( ) ;
981+ termios. set_libc_termios ( & inner_termios ) ;
998982}
999983
1000984/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
@@ -1003,9 +987,9 @@ pub fn cfmakeraw(termios: &mut Termios) {
1003987/// Note that this is a non-standard function, available on FreeBSD.
1004988#[ cfg( target_os = "freebsd" ) ]
1005989pub fn cfmakesane ( termios : & mut Termios ) {
1006- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
990+ let mut inner_termios = termios. get_libc_termios ( ) ;
1007991 unsafe {
1008- libc:: cfmakesane ( inner_termios) ;
992+ libc:: cfmakesane ( & mut inner_termios as * mut _ ) ;
1009993 }
1010994 termios. update_wrapper ( ) ;
1011995}
@@ -1034,7 +1018,7 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
10341018/// *any* of the parameters were successfully set, not only if all were set successfully.
10351019pub fn tcsetattr ( fd : RawFd , actions : SetArg , termios : & Termios ) -> Result < ( ) > {
10361020 let inner_termios = termios. get_libc_termios ( ) ;
1037- Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & * inner_termios) } ) . map ( drop)
1021+ Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & inner_termios) } ) . map ( drop)
10381022}
10391023
10401024/// Block until all output data is written (see
0 commit comments