1010// spell-checker:ignore isig icanon iexten echoe crterase echok echonl noflsh xcase tostop echoprt prterase echoctl ctlecho echoke crtkill flusho extproc
1111// spell-checker:ignore lnext rprnt susp swtch vdiscard veof veol verase vintr vkill vlnext vquit vreprint vstart vstop vsusp vswtc vwerase werase
1212// spell-checker:ignore sigquit sigtstp
13- // spell-checker:ignore cbreak decctlq evenp litout oddp tcsadrain exta extb NCCS
13+ // spell-checker:ignore cbreak decctlq evenp litout oddp tcsadrain exta extb NCCS cfsetispeed
1414
1515mod flags;
1616
@@ -20,7 +20,7 @@ use clap::{Arg, ArgAction, ArgMatches, Command};
2020use nix:: libc:: { O_NONBLOCK , TIOCGWINSZ , TIOCSWINSZ , c_ushort} ;
2121use nix:: sys:: termios:: {
2222 ControlFlags , InputFlags , LocalFlags , OutputFlags , SetArg , SpecialCharacterIndices as S ,
23- Termios , cfgetospeed, cfsetospeed, tcgetattr, tcsetattr,
23+ Termios , cfgetospeed, cfsetispeed , cfsetospeed, tcgetattr, tcsetattr,
2424} ;
2525use nix:: { ioctl_read_bad, ioctl_write_ptr_bad} ;
2626use std:: cmp:: Ordering ;
@@ -273,19 +273,24 @@ fn stty(opts: &Options) -> UResult<()> {
273273 let mut args_iter = args. iter ( ) ;
274274 while let Some ( & arg) = args_iter. next ( ) {
275275 match arg {
276- "ispeed" | "ospeed" => match args_iter. next ( ) {
276+ "ispeed" => match args_iter. next ( ) {
277277 Some ( speed) => {
278- if let Some ( baud_flag) = string_to_baud ( speed) {
278+ if let Some ( baud_flag) = string_to_baud ( speed, flags :: BaudType :: Input ) {
279279 valid_args. push ( ArgOptions :: Flags ( baud_flag) ) ;
280280 } else {
281- return Err ( USimpleError :: new (
282- 1 ,
283- translate ! (
284- "stty-error-invalid-speed" ,
285- "arg" => * arg,
286- "speed" => * speed,
287- ) ,
288- ) ) ;
281+ return invalid_speed ( arg, speed) ;
282+ }
283+ }
284+ None => {
285+ return missing_arg ( arg) ;
286+ }
287+ } ,
288+ "ospeed" => match args_iter. next ( ) {
289+ Some ( speed) => {
290+ if let Some ( baud_flag) = string_to_baud ( speed, flags:: BaudType :: Output ) {
291+ valid_args. push ( ArgOptions :: Flags ( baud_flag) ) ;
292+ } else {
293+ return invalid_speed ( arg, speed) ;
289294 }
290295 }
291296 None => {
@@ -382,12 +387,12 @@ fn stty(opts: &Options) -> UResult<()> {
382387 return missing_arg ( arg) ;
383388 }
384389 // baud rate
385- } else if let Some ( baud_flag) = string_to_baud ( arg) {
390+ } else if let Some ( baud_flag) = string_to_baud ( arg, flags :: BaudType :: Both ) {
386391 valid_args. push ( ArgOptions :: Flags ( baud_flag) ) ;
387392 // non control char flag
388393 } else if let Some ( flag) = string_to_flag ( arg) {
389394 let remove_group = match flag {
390- AllFlags :: Baud ( _) => false ,
395+ AllFlags :: Baud ( _, _ ) => false ,
391396 AllFlags :: ControlFlags ( ( flag, remove) ) => {
392397 check_flag_group ( flag, remove)
393398 }
@@ -416,7 +421,7 @@ fn stty(opts: &Options) -> UResult<()> {
416421 for arg in & valid_args {
417422 match arg {
418423 ArgOptions :: Mapping ( mapping) => apply_char_mapping ( & mut termios, mapping) ,
419- ArgOptions :: Flags ( flag) => apply_setting ( & mut termios, flag) ,
424+ ArgOptions :: Flags ( flag) => apply_setting ( & mut termios, flag) ? ,
420425 ArgOptions :: Special ( setting) => {
421426 apply_special_setting ( & mut termios, setting, opts. file . as_raw_fd ( ) ) ?;
422427 }
@@ -468,6 +473,17 @@ fn invalid_integer_arg<T>(arg: &str) -> Result<T, Box<dyn UError>> {
468473 ) )
469474}
470475
476+ fn invalid_speed < T > ( arg : & str , speed : & str ) -> Result < T , Box < dyn UError > > {
477+ Err ( UUsageError :: new (
478+ 1 ,
479+ translate ! (
480+ "stty-error-invalid-speed" ,
481+ "arg" => arg,
482+ "speed" => speed,
483+ ) ,
484+ ) )
485+ }
486+
471487/// GNU uses different error messages if values overflow or underflow a u8,
472488/// this function returns the appropriate error message in the case of overflow or underflow, or u8 on success
473489fn parse_u8_or_err ( arg : & str ) -> Result < u8 , String > {
@@ -657,7 +673,7 @@ fn parse_baud_with_rounding(normalized: &str) -> Option<u32> {
657673 Some ( value)
658674}
659675
660- fn string_to_baud ( arg : & str ) -> Option < AllFlags < ' _ > > {
676+ fn string_to_baud ( arg : & str , baud_type : flags :: BaudType ) -> Option < AllFlags < ' _ > > {
661677 // Reject invalid formats
662678 if arg != arg. trim_end ( )
663679 || arg. trim ( ) . starts_with ( '-' )
@@ -682,7 +698,7 @@ fn string_to_baud(arg: &str) -> Option<AllFlags<'_>> {
682698 target_os = "netbsd" ,
683699 target_os = "openbsd"
684700 ) ) ]
685- return Some ( AllFlags :: Baud ( value) ) ;
701+ return Some ( AllFlags :: Baud ( value, baud_type ) ) ;
686702
687703 #[ cfg( not( any(
688704 target_os = "freebsd" ,
@@ -695,7 +711,7 @@ fn string_to_baud(arg: &str) -> Option<AllFlags<'_>> {
695711 {
696712 for ( text, baud_rate) in BAUD_RATES {
697713 if text. parse :: < u32 > ( ) . ok ( ) == Some ( value) {
698- return Some ( AllFlags :: Baud ( * baud_rate) ) ;
714+ return Some ( AllFlags :: Baud ( * baud_rate, baud_type ) ) ;
699715 }
700716 }
701717 None
@@ -853,9 +869,9 @@ fn print_flags<T: TermiosFlag>(termios: &Termios, opts: &Options, flags: &[Flag<
853869}
854870
855871/// Apply a single setting
856- fn apply_setting ( termios : & mut Termios , setting : & AllFlags ) {
872+ fn apply_setting ( termios : & mut Termios , setting : & AllFlags ) -> nix :: Result < ( ) > {
857873 match setting {
858- AllFlags :: Baud ( _) => apply_baud_rate_flag ( termios, setting) ,
874+ AllFlags :: Baud ( _, _ ) => apply_baud_rate_flag ( termios, setting) ? ,
859875 AllFlags :: ControlFlags ( ( setting, disable) ) => {
860876 setting. flag . apply ( termios, !disable) ;
861877 }
@@ -869,9 +885,10 @@ fn apply_setting(termios: &mut Termios, setting: &AllFlags) {
869885 setting. flag . apply ( termios, !disable) ;
870886 }
871887 }
888+ Ok ( ( ) )
872889}
873890
874- fn apply_baud_rate_flag ( termios : & mut Termios , input : & AllFlags ) {
891+ fn apply_baud_rate_flag ( termios : & mut Termios , input : & AllFlags ) -> nix :: Result < ( ) > {
875892 // BSDs use a u32 for the baud rate, so any decimal number applies.
876893 #[ cfg( any(
877894 target_os = "freebsd" ,
@@ -881,8 +898,15 @@ fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) {
881898 target_os = "netbsd" ,
882899 target_os = "openbsd"
883900 ) ) ]
884- if let AllFlags :: Baud ( n) = input {
885- cfsetospeed ( termios, * n) . expect ( "Failed to set baud rate" ) ;
901+ if let AllFlags :: Baud ( n, baud_type) = input {
902+ match baud_type {
903+ flags:: BaudType :: Input => cfsetispeed ( termios, * n) ?,
904+ flags:: BaudType :: Output => cfsetospeed ( termios, * n) ?,
905+ flags:: BaudType :: Both => {
906+ cfsetispeed ( termios, * n) ?;
907+ cfsetospeed ( termios, * n) ?;
908+ }
909+ }
886910 }
887911
888912 // Other platforms use an enum.
@@ -894,9 +918,17 @@ fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) {
894918 target_os = "netbsd" ,
895919 target_os = "openbsd"
896920 ) ) ) ]
897- if let AllFlags :: Baud ( br) = input {
898- cfsetospeed ( termios, * br) . expect ( "Failed to set baud rate" ) ;
921+ if let AllFlags :: Baud ( br, baud_type) = input {
922+ match baud_type {
923+ flags:: BaudType :: Input => cfsetispeed ( termios, * br) ?,
924+ flags:: BaudType :: Output => cfsetospeed ( termios, * br) ?,
925+ flags:: BaudType :: Both => {
926+ cfsetispeed ( termios, * br) ?;
927+ cfsetospeed ( termios, * br) ?;
928+ }
929+ }
899930 }
931+ Ok ( ( ) )
900932}
901933
902934fn apply_char_mapping ( termios : & mut Termios , mapping : & ( S , u8 ) ) {
0 commit comments