diff --git a/Cargo.lock b/Cargo.lock index 949eb7f4c9..1a0463cefc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4136,7 +4136,7 @@ dependencies = [ "cfg_aliases", "clap", "fluent", - "nix", + "libc", "rustix", "uucore", ] diff --git a/Cargo.toml b/Cargo.toml index 24b4c700b6..50f43418bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -117,7 +117,7 @@ rlimit = "0.11.0" rstest = "0.28.0" rstest_reuse = "0.7.0" rustc-hash = "2.1.1" -rustix = { version = "1.1.4", default-features = false } +rustix = { version = "1.1.6", default-features = false } self_cell = "1.0.4" selinux = "0.6" tempfile = "3.15.0" @@ -174,6 +174,7 @@ renamed_and_removed_lints = { level = "allow", priority = -1 } # https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(fuzzing)', + 'cfg(gnu_test_mock)', 'cfg(pgo_training)', 'cfg(target_os, values("cygwin"))', 'cfg(wasi_runner)', diff --git a/src/uu/stty/Cargo.toml b/src/uu/stty/Cargo.toml index 93d0cca7e5..47fe26a893 100644 --- a/src/uu/stty/Cargo.toml +++ b/src/uu/stty/Cargo.toml @@ -18,7 +18,7 @@ doctest = false [target.'cfg(all(unix, not(any(target_os = "aix", target_os = "dragonfly"))))'.dependencies] clap = { workspace = true } fluent = { workspace = true } -nix = { workspace = true, features = ["ioctl", "term"] } +libc = { workspace = true } rustix = { workspace = true, features = ["fs", "termios"] } uucore = { workspace = true, features = ["parser"] } diff --git a/src/uu/stty/src/flags.rs b/src/uu/stty/src/flags.rs index ed38c067de..2555b59cdb 100644 --- a/src/uu/stty/src/flags.rs +++ b/src/uu/stty/src/flags.rs @@ -10,14 +10,12 @@ // spell-checker:ignore lnext rprnt susp swtch vdiscard veof veol verase vintr vkill vlnext vquit vreprint vstart vstop vsusp vswtc vwerase werase // spell-checker:ignore sigquit sigtstp // spell-checker:ignore cbreak decctlq evenp litout oddp +// spell-checker:ignore VDSUSP VMIN VSTATUS VTIME VSWTCH use crate::Flag; -#[cfg(not(bsd))] -use nix::sys::termios::BaudRate; -use nix::sys::termios::{ - ControlFlags as C, InputFlags as I, LocalFlags as L, OutputFlags as O, - SpecialCharacterIndices as S, +use rustix::termios::{ + ControlModes as C, InputModes as I, LocalModes as L, OutputModes as O, SpecialCodeIndex as S, }; #[derive(Debug)] @@ -31,10 +29,7 @@ pub enum BaudType { #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub enum AllFlags<'a> { - #[cfg(bsd)] Baud(u32, BaudType), - #[cfg(not(bsd))] - Baud(BaudRate, BaudType), ControlFlags((&'a Flag, bool)), InputFlags((&'a Flag, bool)), LocalFlags((&'a Flag, bool)), @@ -84,6 +79,14 @@ pub const INPUT_FLAGS: &[Flag] = &[ Flag::new("iutf8", I::IUTF8), ]; +// workaround for unexposed const of OutputModes +#[allow(unused_macros)] +macro_rules! o { + ($val:expr) => { + O::from_bits_retain($val as _) + }; +} + pub const OUTPUT_FLAGS: &[Flag] = &[ Flag::new("opost", O::OPOST).sane(), #[cfg(any( @@ -131,21 +134,21 @@ pub const OUTPUT_FLAGS: &[Flag] = &[ target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("cr1", O::CR1, O::CRDLY), + Flag::new_grouped("cr1", o!(libc::CR1), O::CRDLY), #[cfg(any( target_vendor = "apple", target_os = "android", target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("cr2", O::CR2, O::CRDLY), + Flag::new_grouped("cr2", o!(libc::CR2), O::CRDLY), #[cfg(any( target_vendor = "apple", target_os = "android", target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("cr3", O::CR3, O::CRDLY), + Flag::new_grouped("cr3", o!(libc::CR3), O::CRDLY), #[cfg(any( target_vendor = "apple", target_os = "android", @@ -159,21 +162,21 @@ pub const OUTPUT_FLAGS: &[Flag] = &[ target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("tab1", O::TAB1, O::TABDLY), + Flag::new_grouped("tab1", o!(libc::TAB1), O::TABDLY), #[cfg(any( target_vendor = "apple", target_os = "android", target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("tab2", O::TAB2, O::TABDLY), + Flag::new_grouped("tab2", o!(libc::TAB2), O::TABDLY), #[cfg(any( target_vendor = "apple", target_os = "android", target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("tab3", O::TAB3, O::TABDLY), + Flag::new_grouped("tab3", o!(libc::TAB3), O::BSDLY), #[cfg(any( target_vendor = "apple", target_os = "android", @@ -187,7 +190,7 @@ pub const OUTPUT_FLAGS: &[Flag] = &[ target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("bs1", O::BS1, O::BSDLY), + Flag::new_grouped("bs1", o!(libc::BS1), O::BSDLY), #[cfg(any( target_vendor = "apple", target_os = "android", @@ -201,7 +204,7 @@ pub const OUTPUT_FLAGS: &[Flag] = &[ target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("vt1", O::VT1, O::VTDLY), + Flag::new_grouped("vt1", o!(libc::VT1), O::VTDLY), #[cfg(any( target_vendor = "apple", target_os = "android", @@ -215,7 +218,7 @@ pub const OUTPUT_FLAGS: &[Flag] = &[ target_os = "haiku", target_os = "linux" ))] - Flag::new_grouped("ff1", O::FF1, O::FFDLY), + Flag::new_grouped("ff1", o!(libc::FF1), O::FFDLY), ]; pub const LOCAL_FLAGS: &[Flag] = &[ @@ -249,79 +252,6 @@ pub const LOCAL_FLAGS: &[Flag] = &[ Flag::new("extproc", L::EXTPROC), ]; -// BSD's use u32 as baud rate, so using the enum is unnecessary. -#[cfg(not(bsd))] -pub const BAUD_RATES: &[(&str, BaudRate)] = &[ - ("0", BaudRate::B0), - ("50", BaudRate::B50), - ("75", BaudRate::B75), - ("110", BaudRate::B110), - ("134", BaudRate::B134), - ("150", BaudRate::B150), - ("200", BaudRate::B200), - ("300", BaudRate::B300), - ("600", BaudRate::B600), - ("1200", BaudRate::B1200), - ("1800", BaudRate::B1800), - ("2400", BaudRate::B2400), - ("4800", BaudRate::B4800), - ("9600", BaudRate::B9600), - ("19200", BaudRate::B19200), - ("38400", BaudRate::B38400), - ("57600", BaudRate::B57600), - ("115200", BaudRate::B115200), - ("230400", BaudRate::B230400), - // TODO: https://github.com/nix-rust/nix/pull/2815 - #[cfg(not(any( - target_os = "cygwin", - target_os = "fuchsia", - target_os = "haiku", - target_os = "hurd", - target_os = "redox" - )))] - ("460800", BaudRate::B460800), - #[cfg(any(target_os = "android", target_os = "linux"))] - ("500000", BaudRate::B500000), - #[cfg(any(target_os = "android", target_os = "linux"))] - ("576000", BaudRate::B576000), - // TODO: https://github.com/nix-rust/nix/pull/2815 - #[cfg(not(any( - target_os = "cygwin", - target_os = "fuchsia", - target_os = "haiku", - target_os = "hurd", - target_os = "redox" - )))] - ("921600", BaudRate::B921600), - #[cfg(any(target_os = "android", target_os = "linux"))] - ("1000000", BaudRate::B1000000), - #[cfg(any(target_os = "android", target_os = "linux"))] - ("1152000", BaudRate::B1152000), - #[cfg(any(target_os = "android", target_os = "linux"))] - ("1500000", BaudRate::B1500000), - #[cfg(any(target_os = "android", target_os = "linux"))] - ("2000000", BaudRate::B2000000), - #[cfg(any( - target_os = "android", - all(target_os = "linux", not(target_arch = "sparc64")) - ))] - ("2500000", BaudRate::B2500000), - #[cfg(any( - target_os = "android", - all(target_os = "linux", not(target_arch = "sparc64")) - ))] - ("3000000", BaudRate::B3000000), - #[cfg(any( - target_os = "android", - all(target_os = "linux", not(target_arch = "sparc64")) - ))] - ("3500000", BaudRate::B3500000), - #[cfg(any( - target_os = "android", - all(target_os = "linux", not(target_arch = "sparc64")) - ))] - ("4000000", BaudRate::B4000000), -]; /// Control characters for the stty command. /// /// This constant provides a mapping between the names of control characters @@ -384,3 +314,101 @@ pub const COMBINATION_SETTINGS: &[(&str, bool)] = &[ ("sane", false), ("tabs", true), ]; + +// rustix::termios::SpecialCodeIndex, but ordered as same as C header +#[cfg(bsd)] // different order with Linux +pub const SPECIAL_INDICES: &[S] = &[ + S::VEOF, + S::VEOL, + S::VEOL2, + S::VERASE, + S::VWERASE, + S::VKILL, + S::VREPRINT, + S::VINTR, + S::VQUIT, + S::VSUSP, + S::VDSUSP, + S::VSTART, + S::VSTOP, + S::VLNEXT, + S::VDISCARD, + S::VMIN, + S::VTIME, + S::VSTATUS, +]; + +#[cfg(not(bsd))] +pub const SPECIAL_INDICES: &[S] = &[ + S::VINTR, + S::VQUIT, + S::VERASE, + S::VKILL, + S::VEOF, + S::VTIME, + S::VMIN, + #[cfg(not(any(target_os = "haiku", target_os = "hurd")))] + S::VSWTC, + S::VSTART, + S::VSTOP, + S::VSUSP, + S::VEOL, + #[cfg(not(target_os = "haiku"))] + S::VREPRINT, + #[cfg(not(target_os = "haiku"))] + S::VDISCARD, + #[cfg(not(target_os = "haiku"))] + S::VWERASE, + #[cfg(not(target_os = "haiku"))] + S::VLNEXT, + S::VEOL2, + #[cfg(target_os = "haiku")] + S::VSWTCH, + #[cfg(target_os = "hurd")] + S::VDSUSP, + #[cfg(any(target_os = "hurd", target_os = "illumos"))] + S::VSTATUS, +]; + +// On Linux, rustix::termios::ControlModes removes enum baud rate from c_flag. +// But we still need it for stty --save +// However, missing baud does not break stty $(stty --save) +// FIXME: On platforms supporting any baud, --save does not save baud rate which is +// bug-compatible with GNU 9.12 +#[cfg(any(target_os = "android", target_os = "linux"))] +pub fn encoded_baud(b: u32) -> libc::speed_t { + match b { + 0 => libc::B0, + 50 => libc::B50, + 75 => libc::B75, + 110 => libc::B110, + 134 => libc::B134, + 150 => libc::B150, + 200 => libc::B200, + 300 => libc::B300, + 600 => libc::B600, + 1_200 => libc::B1200, + 1_800 => libc::B1800, + 2_400 => libc::B2400, + 4_800 => libc::B4800, + 9_600 => libc::B9600, + 19_200 => libc::B19200, + 38_400 => libc::B38400, + 57_600 => libc::B57600, + 115_200 => libc::B115200, + 230_400 => libc::B230400, + 460_800 => libc::B460800, + 500_000 => libc::B500000, + 576_000 => libc::B576000, + 921_600 => libc::B921600, + 1_000_000 => libc::B1000000, + 1_152_000 => libc::B1152000, + 1_500_000 => libc::B1500000, + 2_000_000 => libc::B2000000, + 2_500_000 => libc::B2500000, + 3_000_000 => libc::B3000000, + 3_500_000 => libc::B3500000, + 4_000_000 => libc::B4000000, + _ => libc::BOTHER, + } +} diff --git a/src/uu/stty/src/stty.rs b/src/uu/stty/src/stty.rs index aca06d6e0e..72670a0102 100644 --- a/src/uu/stty/src/stty.rs +++ b/src/uu/stty/src/stty.rs @@ -19,14 +19,14 @@ mod flags; use crate::flags::AllFlags; -use crate::flags::COMBINATION_SETTINGS; +use crate::flags::{COMBINATION_SETTINGS, SPECIAL_INDICES}; use clap::{Arg, ArgAction, ArgMatches, Command}; -use nix::sys::termios::{ - ControlFlags, InputFlags, LocalFlags, OutputFlags, SetArg, SpecialCharacterIndices as S, - Termios, cfsetispeed, cfsetospeed, tcgetattr, tcsetattr, +use rustix::termios::{ + ControlModes as ControlFlags, InputModes as InputFlags, LocalModes as LocalFlags, + OptionalActions, OutputModes as OutputFlags, SpecialCodeIndex as S, Termios, Winsize, + tcgetattr, tcgetwinsize, tcsetattr, tcsetwinsize, }; -use rustix::termios::{Winsize, tcgetwinsize, tcsetwinsize}; use std::cmp::Ordering; use std::fs::File; use std::io::{self, Stdin, stdin, stdout}; @@ -38,8 +38,6 @@ use uucore::format_usage; use uucore::parser::num_parser::ExtendedParser; use uucore::translate; -#[cfg(not(bsd))] -use flags::BAUD_RATES; use flags::{CONTROL_CHARS, CONTROL_FLAGS, INPUT_FLAGS, LOCAL_FLAGS, OUTPUT_FLAGS}; const ASCII_DEL: u8 = 127; @@ -149,7 +147,7 @@ enum PrintSetting { } type CFlags = [u32; 4]; -type CCFlags = [u8; nix::libc::NCCS]; +type CCFlags = [u8; libc::NCCS]; enum ArgOptions<'a> { Flags(AllFlags<'a>), @@ -245,7 +243,7 @@ fn stty(opts: &Options) -> UResult<()> { )); } - let mut set_arg = SetArg::TCSADRAIN; + let mut set_arg = OptionalActions::Drain; let mut valid_args: Vec = Vec::new(); if let Some(args) = &opts.settings { @@ -290,10 +288,10 @@ fn stty(opts: &Options) -> UResult<()> { valid_args.push(ArgOptions::Special(SpecialSetting::Cols(n))); } "drain" => { - set_arg = SetArg::TCSADRAIN; + set_arg = OptionalActions::Drain; } "-drain" => { - set_arg = SetArg::TCSANOW; + set_arg = OptionalActions::Now; } "size" => { valid_args.push(ArgOptions::Print(PrintSetting::Size)); @@ -351,8 +349,9 @@ fn stty(opts: &Options) -> UResult<()> { } } - let mut termios = - tcgetattr(opts.file.as_fd()).map_err_context(|| opts.device_name.clone())?; + let mut termios = tcgetattr(&opts.file) + .map_err(io::Error::from) + .map_err_context(|| opts.device_name.clone())?; // iterate over valid_args, match on the arg type, do the matching apply function for arg in &valid_args { @@ -370,9 +369,11 @@ fn stty(opts: &Options) -> UResult<()> { } } } - tcsetattr(opts.file.as_fd(), set_arg, &termios)?; + tcsetattr(&opts.file, set_arg, &termios).map_err(io::Error::from)?; } else { - let termios = tcgetattr(opts.file.as_fd()).map_err_context(|| opts.device_name.clone())?; + let termios = tcgetattr(&opts.file) + .map_err(io::Error::from) + .map_err_context(|| opts.device_name.clone())?; print_settings(&termios, opts)?; } Ok(()) @@ -446,7 +447,7 @@ fn parse_rows_cols(arg: &str) -> Option { /// Parse a saved terminal state string in stty format. /// /// The format is colon-separated hexadecimal values: -/// `input_flags:output_flags:control_flags:local_flags:cc0:cc1:cc2:...` +/// `input_modes:output_modes:control_modes:local_modes:cc0:cc1:cc2:...` /// /// - Must have exactly 4 + NCCS parts (4 flags + platform-specific control characters) /// - All parts must be non-empty valid hex values @@ -544,7 +545,7 @@ impl WrappedPrinter { } fn print_terminal_size( - termios: &rustix::termios::Termios, + termios: &Termios, opts: &Options, window_size: Option<&Winsize>, term_size: Option<&Winsize>, @@ -645,19 +646,7 @@ fn string_to_baud(arg: &str, baud_type: flags::BaudType) -> Option> let normalized = normalized.strip_suffix('.').unwrap_or(normalized); let value = parse_baud_with_rounding(normalized)?; - // BSDs use a u32 for the baud rate, so any decimal number applies. - #[cfg(bsd)] - return Some(AllFlags::Baud(value, baud_type)); - - #[cfg(not(bsd))] - { - for (text, baud_rate) in BAUD_RATES { - if text.parse::().ok() == Some(value) { - return Some(AllFlags::Baud(*baud_rate, baud_type)); - } - } - None - } + Some(AllFlags::Baud(value, baud_type)) } /// return `Some(flag)` if the input is a valid flag, `None` if not @@ -680,7 +669,7 @@ fn string_to_flag(option: &str) -> Option> { None } -fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result { +fn control_char_to_string(cc: u8) -> io::Result { let (meta_prefix, code) = match cc { 0 => return Ok(translate!("stty-output-undef")), 0x80.. => ("M-", cc - 0x80), @@ -696,22 +685,22 @@ fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result { // DEL character 0x7f => Ok(("^", '?')), // Out of range (above 8 bits) - _ => Err(nix::errno::Errno::ERANGE), + _ => Err(rustix::io::Errno::RANGE), }?; Ok(format!("{meta_prefix}{ctrl_prefix}{character}")) } -fn print_control_chars( +fn print_control_modes( termios: &Termios, opts: &Options, term_size: Option<&Winsize>, -) -> nix::Result<()> { +) -> io::Result<()> { if !opts.all { // Print only control chars that differ from sane defaults let mut printer = WrappedPrinter::new(term_size); for (text, cc_index) in CONTROL_CHARS { - let current_val = termios.control_chars[*cc_index as usize]; + let current_val = termios.special_codes[*cc_index]; let sane_val = get_sane_control_char(*cc_index); if current_val != sane_val { @@ -729,28 +718,47 @@ fn print_control_chars( for (text, cc_index) in CONTROL_CHARS { printer.print(&format!( "{text} = {};", - control_char_to_string(termios.control_chars[*cc_index as usize])? + control_char_to_string(termios.special_codes[*cc_index])? )); } printer.print(&translate!("stty-output-min-time", - "min" => termios.control_chars[S::VMIN as usize], - "time" => termios.control_chars[S::VTIME as usize] + "min" => termios.special_codes[S::VMIN], + "time" => termios.special_codes[S::VTIME] )); printer.flush(); Ok(()) } +#[allow(clippy::uninlined_format_args)] fn print_in_save_format(termios: &Termios) { + // rustix omits ispeed matching with ospeed + #[cfg(any(target_os = "android", target_os = "linux"))] + let omitted_flag = { + let ospeed = termios.output_speed(); + if termios.input_speed() == ospeed { + flags::encoded_baud(ospeed) << 16 + } else { + 0 + } + }; + #[cfg(not(any(target_os = "android", target_os = "linux")))] + let omitted_flag = 0; print!( "{:x}:{:x}:{:x}:{:x}", - termios.input_flags.bits(), - termios.output_flags.bits(), - termios.control_flags.bits(), - termios.local_flags.bits() + termios.input_modes.bits(), + termios.output_modes.bits(), + termios.control_modes.bits() | omitted_flag, + termios.local_modes.bits() ); - for cc in termios.control_chars { + for &i in SPECIAL_INDICES { + let cc = termios.special_codes[i]; print!(":{cc:x}"); } + for _ in SPECIAL_INDICES.len()..libc::NCCS { + print!(":0"); + } + // FIXME: On platforms supporting any baud, --save does not save baud rate which is + // bug-compatible with GNU 9.12 println!(); } @@ -771,16 +779,8 @@ fn print_settings(termios: &Termios, opts: &Options) -> io::Result<()> { &tcgetwinsize(stdout).ok() }; - // GNU linked against glibc 2.42 provides us baudrate 51 which panics nix::sys::termios::cfgetospeed - // so we repeat syscall until we replace nix with rustix... - let rustix_termios = rustix::termios::tcgetattr(&opts.file)?; - print_terminal_size( - &rustix_termios, - opts, - window_size.as_ref(), - term_size.as_ref(), - ); - print_control_chars(termios, opts, window_size.as_ref())?; + print_terminal_size(termios, opts, window_size.as_ref(), term_size.as_ref()); + print_control_modes(termios, opts, window_size.as_ref())?; print_flags(termios, opts, CONTROL_FLAGS, window_size.as_ref()); print_flags(termios, opts, INPUT_FLAGS, window_size.as_ref()); print_flags(termios, opts, OUTPUT_FLAGS, window_size.as_ref()); @@ -821,7 +821,7 @@ fn print_flags( } /// Apply a single setting -fn apply_setting(termios: &mut Termios, setting: &AllFlags) -> nix::Result<()> { +fn apply_setting(termios: &mut Termios, setting: &AllFlags) -> io::Result<()> { match setting { AllFlags::Baud(_, _) => apply_baud_rate_flag(termios, setting)?, AllFlags::ControlFlags((setting, disable)) => { @@ -840,22 +840,33 @@ fn apply_setting(termios: &mut Termios, setting: &AllFlags) -> nix::Result<()> { Ok(()) } -fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) -> nix::Result<()> { +fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) -> io::Result<()> { + #[cfg(gnu_test_mock)] + // `stty/bad-speed.sh` intercepts `cfsetispeed` which just edits a struct in the user space + // which means the test cannot be patched to use `strace`. + // GNU supports any baud only on newer glibc and the test emulates the system + // without support of any baud. The test is not useful for us since we support + // any baud on Linux independently on libc via set_input_speed. + // However, we still test exit code on platforms without support of any baud + // when set_input_speed failed. + if std::env::var("LD_PRELOAD").is_ok_and(|s| s.contains("./k.so")) { + let _ = File::create("preloaded"); // the test checks that `cfsetispeed` was intercepted using this file + return Err(io::Error::other( + "gnu_test_mock: emulated unsupported u32 baud rate", + )); + } if let AllFlags::Baud(rate, baud_type) = input { match baud_type { - flags::BaudType::Input => cfsetispeed(termios, *rate)?, - flags::BaudType::Output => cfsetospeed(termios, *rate)?, - flags::BaudType::Both => { - cfsetispeed(termios, *rate)?; - cfsetospeed(termios, *rate)?; - } + flags::BaudType::Input => termios.set_input_speed(*rate)?, + flags::BaudType::Output => termios.set_output_speed(*rate)?, + flags::BaudType::Both => termios.set_speed(*rate)?, } } Ok(()) } fn apply_char_mapping(termios: &mut Termios, mapping: &(S, u8)) { - termios.control_chars[mapping.0 as usize] = mapping.1; + termios.special_codes[mapping.0] = mapping.1; } /// Apply a saved terminal state to the current termios. @@ -869,14 +880,14 @@ fn apply_char_mapping(termios: &mut Termios, mapping: &(S, u8)) { fn apply_saved_state(termios: &mut Termios, state: &(CFlags, CCFlags)) { let (c_flags, cc_flags) = state; // Apply the four flag groups, done (as _) for MacOS size compatibility - termios.input_flags = InputFlags::from_bits_truncate(c_flags[0] as _); - termios.output_flags = OutputFlags::from_bits_truncate(c_flags[1] as _); - termios.control_flags = ControlFlags::from_bits_truncate(c_flags[2] as _); - termios.local_flags = LocalFlags::from_bits_truncate(c_flags[3] as _); + termios.input_modes = InputFlags::from_bits_truncate(c_flags[0] as _); + termios.output_modes = OutputFlags::from_bits_truncate(c_flags[1] as _); + termios.control_modes = ControlFlags::from_bits_truncate(c_flags[2] as _); + termios.local_modes = LocalFlags::from_bits_truncate(c_flags[3] as _); // Apply control characters if present - for (c, &cc_val) in termios.control_chars.iter_mut().zip(cc_flags) { - *c = cc_val; + for (&index, &cc_val) in SPECIAL_INDICES.iter().zip(cc_flags) { + termios.special_codes[index] = cc_val; } } @@ -1079,45 +1090,45 @@ pub fn uu_app() -> Command { impl TermiosFlag for ControlFlags { fn is_in(&self, termios: &Termios, group: Option) -> bool { - termios.control_flags.contains(*self) - && group.is_none_or(|g| !termios.control_flags.intersects(g - *self)) + termios.control_modes.contains(*self) + && group.is_none_or(|g| !termios.control_modes.intersects(g - *self)) } fn apply(&self, termios: &mut Termios, val: bool) { - termios.control_flags.set(*self, val); + termios.control_modes.set(*self, val); } } impl TermiosFlag for InputFlags { fn is_in(&self, termios: &Termios, group: Option) -> bool { - termios.input_flags.contains(*self) - && group.is_none_or(|g| !termios.input_flags.intersects(g - *self)) + termios.input_modes.contains(*self) + && group.is_none_or(|g| !termios.input_modes.intersects(g - *self)) } fn apply(&self, termios: &mut Termios, val: bool) { - termios.input_flags.set(*self, val); + termios.input_modes.set(*self, val); } } impl TermiosFlag for OutputFlags { fn is_in(&self, termios: &Termios, group: Option) -> bool { - termios.output_flags.contains(*self) - && group.is_none_or(|g| !termios.output_flags.intersects(g - *self)) + termios.output_modes.contains(*self) + && group.is_none_or(|g| !termios.output_modes.intersects(g - *self)) } fn apply(&self, termios: &mut Termios, val: bool) { - termios.output_flags.set(*self, val); + termios.output_modes.set(*self, val); } } impl TermiosFlag for LocalFlags { fn is_in(&self, termios: &Termios, group: Option) -> bool { - termios.local_flags.contains(*self) - && group.is_none_or(|g| !termios.local_flags.intersects(g - *self)) + termios.local_modes.contains(*self) + && group.is_none_or(|g| !termios.local_modes.intersects(g - *self)) } fn apply(&self, termios: &mut Termios, val: bool) { - termios.local_flags.set(*self, val); + termios.local_modes.set(*self, val); } } @@ -1241,33 +1252,19 @@ mod tests { // Tests for string_to_baud #[test] - fn test_string_to_baud_valid() { - #[cfg(not(bsd))] - { - assert!(string_to_baud("9600", flags::BaudType::Both).is_some()); - assert!(string_to_baud("115200", flags::BaudType::Both).is_some()); - assert!(string_to_baud("38400", flags::BaudType::Both).is_some()); - assert!(string_to_baud("19200", flags::BaudType::Both).is_some()); - } - - #[cfg(bsd)] - { - assert!(string_to_baud("9600", flags::BaudType::Both).is_some()); - assert!(string_to_baud("115200", flags::BaudType::Both).is_some()); - assert!(string_to_baud("1000000", flags::BaudType::Both).is_some()); - assert!(string_to_baud("0", flags::BaudType::Both).is_some()); - } + fn test_string_to_baud_u32() { + // any u32 baud is accepted. + // unsupported baud rate (e.g. 995 on Cygwin) is caught by rustix::termios::Termios::set_speed, etc... + assert!(string_to_baud("995", flags::BaudType::Both).is_some()); + assert!(string_to_baud("0", flags::BaudType::Both).is_some()); + assert!(string_to_baud("4294967295", flags::BaudType::Both).is_some()); } #[test] fn test_string_to_baud_invalid() { - #[cfg(not(bsd))] - { - assert_eq!(string_to_baud("995", flags::BaudType::Both), None); - assert_eq!(string_to_baud("invalid", flags::BaudType::Both), None); - assert_eq!(string_to_baud("", flags::BaudType::Both), None); - assert_eq!(string_to_baud("abc", flags::BaudType::Both), None); - } + assert_eq!(string_to_baud("invalid", flags::BaudType::Both), None); + assert_eq!(string_to_baud("", flags::BaudType::Both), None); + assert_eq!(string_to_baud("abc", flags::BaudType::Both), None); } #[test] diff --git a/tests/by-util/test_stty.rs b/tests/by-util/test_stty.rs index 2161074d9b..69811c24e7 100644 --- a/tests/by-util/test_stty.rs +++ b/tests/by-util/test_stty.rs @@ -155,6 +155,8 @@ fn invalid_setting() { fn invalid_baud_setting() { #[cfg(not(any( target_vendor = "apple", + target_os = "android", + target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", @@ -182,6 +184,8 @@ fn invalid_baud_setting() { #[cfg(not(any( target_vendor = "apple", + target_os = "android", + target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", @@ -194,6 +198,8 @@ fn invalid_baud_setting() { #[cfg(not(any( target_vendor = "apple", + target_os = "android", + target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", @@ -1471,10 +1477,12 @@ fn invalid_baud_rate() { .fails() .stderr_contains("invalid ispeed"); - // On non-BSD systems, test invalid numeric baud rate - // On BSD systems, any u32 is accepted, so we skip this test + // On Linux and BSD, any u32 is accepted, so we skip this test + // On other systems, test invalid numeric baud rate #[cfg(not(any( target_vendor = "apple", + target_os = "android", + target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd", diff --git a/util/build-gnu.sh b/util/build-gnu.sh index 70889387de..bf15bcadeb 100755 --- a/util/build-gnu.sh +++ b/util/build-gnu.sh @@ -23,6 +23,7 @@ REPO_main_dir="$(dirname -- "${ME_dir}")" : ${PROFILE:=debug} # default profile export PROFILE # tell to make +export RUSTFLAGS+=" --cfg=gnu_test_mock" unset CARGOFLAGS ### * config (from environment with fallback defaults); note: GNU is expected to be a sibling repo directory