@@ -155,7 +155,6 @@ use cfg_if::cfg_if;
155
155
use crate :: { Error , Result } ;
156
156
use crate :: errno:: Errno ;
157
157
use libc:: { self , c_int, tcflag_t} ;
158
- use std:: cell:: { Ref , RefCell } ;
159
158
use std:: convert:: { From , TryFrom } ;
160
159
use std:: mem;
161
160
use std:: os:: unix:: io:: RawFd ;
@@ -167,9 +166,20 @@ use crate::unistd::Pid;
167
166
/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
168
167
/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
169
168
/// an open port using `tcgetattr()`.
170
- #[ derive( Clone , Debug , Eq , PartialEq ) ]
169
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
171
170
pub struct Termios {
172
- inner : RefCell < libc:: termios > ,
171
+ // The actual fields present in `libc::termios`, their types, and even their interpretations
172
+ // vary from one platform to another. We want to expose a portable subset as public fields of
173
+ // `Termios`, using stable types, and allow access to the rest via accessors, if at all.
174
+ //
175
+ // So we carry around this private `libc::termios`, initialize our public fields from it
176
+ // whenever it's changed (see `set_libc_termios`), and propagate our public fields' values back
177
+ // into it whenever we need a real `libc::termios` to pass to `tcsetattr`, `cfmakeraw`, or the
178
+ // like (see `get_libc_termios`).
179
+ //
180
+ // Any fields unknown to us get reasonable values from the initial `tcgetattr` used to create
181
+ // this `Termios`, and are thus passed through to subsequent `tcsetattr` calls unchanged.
182
+ inner : libc:: termios ,
173
183
/// Input mode flags (see `termios.c_iflag` documentation)
174
184
pub input_flags : InputFlags ,
175
185
/// Output mode flags (see `termios.c_oflag` documentation)
@@ -183,43 +193,24 @@ pub struct Termios {
183
193
}
184
194
185
195
impl Termios {
186
- /// Exposes an immutable reference to the underlying `libc::termios` data structure.
196
+ /// Return a copy of the internal `libc::termios` structure.
187
197
///
188
198
/// This is not part of `nix`'s public API because it requires additional work to maintain type
189
199
/// 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 ( )
200
+ pub ( crate ) fn get_libc_termios ( & self ) -> libc:: termios {
201
+ let mut termios = self . inner ;
202
+ termios. c_iflag = self . input_flags . bits ( ) ;
203
+ termios. c_oflag = self . output_flags . bits ( ) ;
204
+ termios. c_cflag = self . control_flags . bits ( ) ;
205
+ termios. c_lflag = self . local_flags . bits ( ) ;
206
+ termios. c_cc = self . control_chars ;
207
+ termios
218
208
}
219
209
220
- /// 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 ( ) ;
210
+ /// Set the internal `libc::termios` structure to `termios`,
211
+ /// and update the public fields.
212
+ pub ( crate ) fn set_libc_termios ( & mut self , termios : & libc:: termios ) {
213
+ self . inner = * termios;
223
214
self . input_flags = InputFlags :: from_bits_truncate ( termios. c_iflag ) ;
224
215
self . output_flags = OutputFlags :: from_bits_truncate ( termios. c_oflag ) ;
225
216
self . control_flags = ControlFlags :: from_bits_truncate ( termios. c_cflag ) ;
@@ -231,7 +222,7 @@ impl Termios {
231
222
impl From < libc:: termios > for Termios {
232
223
fn from ( termios : libc:: termios ) -> Self {
233
224
Termios {
234
- inner : RefCell :: new ( termios) ,
225
+ inner : termios,
235
226
input_flags : InputFlags :: from_bits_truncate ( termios. c_iflag ) ,
236
227
output_flags : OutputFlags :: from_bits_truncate ( termios. c_oflag ) ,
237
228
control_flags : ControlFlags :: from_bits_truncate ( termios. c_cflag ) ,
@@ -243,7 +234,7 @@ impl From<libc::termios> for Termios {
243
234
244
235
impl From < Termios > for libc:: termios {
245
236
fn from ( termios : Termios ) -> Self {
246
- termios. inner . into_inner ( )
237
+ termios. inner
247
238
}
248
239
}
249
240
@@ -881,7 +872,7 @@ cfg_if!{
881
872
/// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
882
873
pub fn cfgetispeed( termios: & Termios ) -> u32 {
883
874
let inner_termios = termios. get_libc_termios( ) ;
884
- unsafe { libc:: cfgetispeed( & * inner_termios) as u32 }
875
+ unsafe { libc:: cfgetispeed( & inner_termios) as u32 }
885
876
}
886
877
887
878
/// Get output baud rate (see
@@ -890,17 +881,17 @@ cfg_if!{
890
881
/// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
891
882
pub fn cfgetospeed( termios: & Termios ) -> u32 {
892
883
let inner_termios = termios. get_libc_termios( ) ;
893
- unsafe { libc:: cfgetospeed( & * inner_termios) as u32 }
884
+ unsafe { libc:: cfgetospeed( & inner_termios) as u32 }
894
885
}
895
886
896
887
/// Set input baud rate (see
897
888
/// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
898
889
///
899
890
/// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
900
891
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 ( ) ;
892
+ let mut inner_termios = termios. get_libc_termios ( ) ;
893
+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
894
+ termios. set_libc_termios ( & inner_termios ) ;
904
895
Errno :: result( res) . map( drop)
905
896
}
906
897
@@ -909,9 +900,9 @@ cfg_if!{
909
900
///
910
901
/// `cfsetospeed()` sets the output baud rate in the given termios structure.
911
902
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 ( ) ;
903
+ let mut inner_termios = termios. get_libc_termios ( ) ;
904
+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
905
+ termios. set_libc_termios ( & inner_termios ) ;
915
906
Errno :: result( res) . map( drop)
916
907
}
917
908
@@ -921,9 +912,9 @@ cfg_if!{
921
912
/// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
922
913
/// this is part of the 4.4BSD standard and not part of POSIX.
923
914
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 ( ) ;
915
+ let mut inner_termios = termios. get_libc_termios ( ) ;
916
+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud. into( ) as libc:: speed_t) } ;
917
+ termios. set_libc_termios ( & inner_termios ) ;
927
918
Errno :: result( res) . map( drop)
928
919
}
929
920
} else {
@@ -935,7 +926,7 @@ cfg_if!{
935
926
/// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
936
927
pub fn cfgetispeed( termios: & Termios ) -> BaudRate {
937
928
let inner_termios = termios. get_libc_termios( ) ;
938
- unsafe { libc:: cfgetispeed( & * inner_termios) } . try_into( ) . unwrap( )
929
+ unsafe { libc:: cfgetispeed( & inner_termios) } . try_into( ) . unwrap( )
939
930
}
940
931
941
932
/// Get output baud rate (see
@@ -944,17 +935,17 @@ cfg_if!{
944
935
/// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
945
936
pub fn cfgetospeed( termios: & Termios ) -> BaudRate {
946
937
let inner_termios = termios. get_libc_termios( ) ;
947
- unsafe { libc:: cfgetospeed( & * inner_termios) } . try_into( ) . unwrap( )
938
+ unsafe { libc:: cfgetospeed( & inner_termios) } . try_into( ) . unwrap( )
948
939
}
949
940
950
941
/// Set input baud rate (see
951
942
/// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
952
943
///
953
944
/// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
954
945
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 ( ) ;
946
+ let mut inner_termios = termios. get_libc_termios ( ) ;
947
+ let res = unsafe { libc:: cfsetispeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
948
+ termios. set_libc_termios ( & inner_termios ) ;
958
949
Errno :: result( res) . map( drop)
959
950
}
960
951
@@ -963,9 +954,9 @@ cfg_if!{
963
954
///
964
955
/// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
965
956
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 ( ) ;
957
+ let mut inner_termios = termios. get_libc_termios ( ) ;
958
+ let res = unsafe { libc:: cfsetospeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
959
+ termios. set_libc_termios ( & inner_termios ) ;
969
960
Errno :: result( res) . map( drop)
970
961
}
971
962
@@ -975,9 +966,9 @@ cfg_if!{
975
966
/// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
976
967
/// this is part of the 4.4BSD standard and not part of POSIX.
977
968
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 ( ) ;
969
+ let mut inner_termios = termios. get_libc_termios ( ) ;
970
+ let res = unsafe { libc:: cfsetspeed( & mut inner_termios as * mut _ , baud as libc:: speed_t) } ;
971
+ termios. set_libc_termios ( & inner_termios ) ;
981
972
Errno :: result( res) . map( drop)
982
973
}
983
974
}
@@ -990,11 +981,11 @@ cfg_if!{
990
981
/// character, echoing is disabled, and all special input and output processing is disabled. Note
991
982
/// that this is a non-standard function, but is available on Linux and BSDs.
992
983
pub fn cfmakeraw ( termios : & mut Termios ) {
993
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
984
+ let mut inner_termios = termios. get_libc_termios ( ) ;
994
985
unsafe {
995
- libc:: cfmakeraw ( inner_termios) ;
986
+ libc:: cfmakeraw ( & mut inner_termios as * mut _ ) ;
996
987
}
997
- termios. update_wrapper ( ) ;
988
+ termios. set_libc_termios ( & inner_termios ) ;
998
989
}
999
990
1000
991
/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
@@ -1003,11 +994,11 @@ pub fn cfmakeraw(termios: &mut Termios) {
1003
994
/// Note that this is a non-standard function, available on FreeBSD.
1004
995
#[ cfg( target_os = "freebsd" ) ]
1005
996
pub fn cfmakesane ( termios : & mut Termios ) {
1006
- let inner_termios = unsafe { termios. get_libc_termios_mut ( ) } ;
997
+ let mut inner_termios = termios. get_libc_termios ( ) ;
1007
998
unsafe {
1008
- libc:: cfmakesane ( inner_termios) ;
999
+ libc:: cfmakesane ( & mut inner_termios as * mut _ ) ;
1009
1000
}
1010
- termios. update_wrapper ( ) ;
1001
+ termios. set_libc_termios ( & inner_termios ) ;
1011
1002
}
1012
1003
1013
1004
/// Return the configuration of a port
@@ -1034,7 +1025,7 @@ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
1034
1025
/// *any* of the parameters were successfully set, not only if all were set successfully.
1035
1026
pub fn tcsetattr ( fd : RawFd , actions : SetArg , termios : & Termios ) -> Result < ( ) > {
1036
1027
let inner_termios = termios. get_libc_termios ( ) ;
1037
- Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & * inner_termios) } ) . map ( drop)
1028
+ Errno :: result ( unsafe { libc:: tcsetattr ( fd, actions as c_int , & inner_termios) } ) . map ( drop)
1038
1029
}
1039
1030
1040
1031
/// Block until all output data is written (see
0 commit comments