diff --git a/src/uu/mknod/src/mknod.rs b/src/uu/mknod/src/mknod.rs index 1343501bb..98404f89f 100644 --- a/src/uu/mknod/src/mknod.rs +++ b/src/uu/mknod/src/mknod.rs @@ -7,8 +7,6 @@ // spell-checker:ignore (ToDO) parsemode makedev sysmacros makenod newmode perror IFBLK IFCHR IFIFO -mod parsemode; - #[macro_use] extern crate uucore; @@ -98,7 +96,7 @@ for details about the options it supports.", let mut last_umask: mode_t = 0; let mut newmode: mode_t = MODE_RW_UGO; if matches.opt_present("mode") { - match parsemode::parse_mode(matches.opt_str("mode")) { + match uucore::mode::parse_mode(matches.opt_str("mode")) { Ok(parsed) => { if parsed > 0o777 { show_info!("mode must specify only file permission bits"); diff --git a/src/uu/mknod/src/parsemode.rs b/src/uu/mknod/src/parsemode.rs deleted file mode 100644 index 8f8f9af61..000000000 --- a/src/uu/mknod/src/parsemode.rs +++ /dev/null @@ -1,58 +0,0 @@ -// spell-checker:ignore (ToDO) fperm - -use libc::{mode_t, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR}; - -use uucore::mode; - -pub fn parse_mode(mode: Option) -> Result { - let fperm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - if let Some(mode) = mode { - let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - let result = if mode.contains(arr) { - mode::parse_numeric(fperm as u32, mode.as_str()) - } else { - mode::parse_symbolic(fperm as u32, mode.as_str(), true) - }; - result.map(|mode| mode as mode_t) - } else { - Ok(fperm) - } -} - -#[cfg(test)] -mod test { - /// Test if the program is running under WSL - // ref: @@ - // ToDO: test on WSL2 which likely doesn't need special handling; plan change to `is_wsl_1()` if WSL2 is less needy - pub fn is_wsl() -> bool { - #[cfg(target_os = "linux")] - { - if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") { - if let Ok(s) = std::str::from_utf8(&b) { - let a = s.to_ascii_lowercase(); - return a.contains("microsoft") || a.contains("wsl"); - } - } - } - false - } - - #[test] - fn symbolic_modes() { - assert_eq!(super::parse_mode(Some("u+x".to_owned())).unwrap(), 0o766); - assert_eq!( - super::parse_mode(Some("+x".to_owned())).unwrap(), - if !is_wsl() { 0o777 } else { 0o776 } - ); - assert_eq!(super::parse_mode(Some("a-w".to_owned())).unwrap(), 0o444); - assert_eq!(super::parse_mode(Some("g-r".to_owned())).unwrap(), 0o626); - } - - #[test] - fn numeric_modes() { - assert_eq!(super::parse_mode(Some("644".to_owned())).unwrap(), 0o644); - assert_eq!(super::parse_mode(Some("+100".to_owned())).unwrap(), 0o766); - assert_eq!(super::parse_mode(Some("-4".to_owned())).unwrap(), 0o662); - assert_eq!(super::parse_mode(None).unwrap(), 0o666); - } -} diff --git a/src/uucore/src/lib/features/mode.rs b/src/uucore/src/lib/features/mode.rs index 8b5e71799..1bb79ac03 100644 --- a/src/uucore/src/lib/features/mode.rs +++ b/src/uucore/src/lib/features/mode.rs @@ -7,6 +7,8 @@ // spell-checker:ignore (vars) fperm srwx +use libc::{mode_t, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR}; + pub fn parse_numeric(fperm: u32, mut mode: &str) -> Result { let (op, pos) = parse_op(mode, Some('='))?; mode = mode[pos..].trim().trim_start_matches('0'); @@ -129,3 +131,41 @@ fn parse_change(mode: &str, fperm: u32, considering_dir: bool) -> (u32, usize) { } (srwx, pos) } + +pub fn parse_mode(mode: Option) -> Result { + let fperm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + if let Some(mode) = mode { + let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + let result = if mode.contains(arr) { + parse_numeric(fperm as u32, mode.as_str()) + } else { + parse_symbolic(fperm as u32, mode.as_str(), true) + }; + result.map(|mode| mode as mode_t) + } else { + Ok(fperm) + } +} + +#[cfg(test)] +mod test { + + #[test] + fn symbolic_modes() { + assert_eq!(super::parse_mode(Some("u+x".to_owned())).unwrap(), 0o766); + assert_eq!( + super::parse_mode(Some("+x".to_owned())).unwrap(), + if !crate::os::is_wsl_1() { 0o777 } else { 0o776 } + ); + assert_eq!(super::parse_mode(Some("a-w".to_owned())).unwrap(), 0o444); + assert_eq!(super::parse_mode(Some("g-r".to_owned())).unwrap(), 0o626); + } + + #[test] + fn numeric_modes() { + assert_eq!(super::parse_mode(Some("644".to_owned())).unwrap(), 0o644); + assert_eq!(super::parse_mode(Some("+100".to_owned())).unwrap(), 0o766); + assert_eq!(super::parse_mode(Some("-4".to_owned())).unwrap(), 0o662); + assert_eq!(super::parse_mode(None).unwrap(), 0o666); + } +} diff --git a/src/uucore/src/lib/lib.rs b/src/uucore/src/lib/lib.rs index 324095b6a..208e9536c 100644 --- a/src/uucore/src/lib/lib.rs +++ b/src/uucore/src/lib/lib.rs @@ -26,6 +26,7 @@ mod mods; // core cross-platform modules // * cross-platform modules pub use crate::mods::coreopts; +pub use crate::mods::os; pub use crate::mods::panic; pub use crate::mods::ranges; diff --git a/src/uucore/src/lib/mods.rs b/src/uucore/src/lib/mods.rs index c73909dcc..74725e141 100644 --- a/src/uucore/src/lib/mods.rs +++ b/src/uucore/src/lib/mods.rs @@ -1,5 +1,6 @@ // mods ~ cross-platforms modules (core/bundler file) pub mod coreopts; +pub mod os; pub mod panic; pub mod ranges; diff --git a/src/uucore/src/lib/mods/os.rs b/src/uucore/src/lib/mods/os.rs new file mode 100644 index 000000000..da2002161 --- /dev/null +++ b/src/uucore/src/lib/mods/os.rs @@ -0,0 +1,30 @@ +/// Test if the program is running under WSL +// ref: @@ +pub fn is_wsl_1() -> bool { + #[cfg(target_os = "linux")] + { + if is_wsl_2() { + return false; + } + if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") { + if let Ok(s) = std::str::from_utf8(&b) { + let a = s.to_ascii_lowercase(); + return a.contains("microsoft") || a.contains("wsl"); + } + } + } + false +} + +pub fn is_wsl_2() -> bool { + #[cfg(target_os = "linux")] + { + if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") { + if let Ok(s) = std::str::from_utf8(&b) { + let a = s.to_ascii_lowercase(); + return a.contains("wsl2"); + } + } + } + false +} diff --git a/tests/by-util/test_chgrp.rs b/tests/by-util/test_chgrp.rs index 613f52fd2..ffb078137 100644 --- a/tests/by-util/test_chgrp.rs +++ b/tests/by-util/test_chgrp.rs @@ -1,5 +1,6 @@ use crate::common::util::*; use rust_users::*; +use uucore; #[test] fn test_invalid_option() { @@ -104,7 +105,7 @@ fn test_reference() { // skip for root or MS-WSL // * MS-WSL is bugged (as of 2019-12-25), allowing non-root accounts su-level privileges for `chgrp` // * for MS-WSL, succeeds and stdout == 'group of /etc retained as root' - if !(get_effective_gid() == 0 || is_wsl()) { + if !(get_effective_gid() == 0 || uucore::os::is_wsl_1()) { new_ucmd!() .arg("-v") .arg("--reference=/etc/passwd") diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 5619aed94..b4e49e775 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -4,6 +4,7 @@ use self::regex::Regex; use crate::common::util::*; #[cfg(all(unix, not(target_os = "macos")))] use rust_users::*; +use uucore; #[test] fn test_date_email() { @@ -159,7 +160,7 @@ fn test_date_set_invalid() { #[test] #[cfg(all(unix, not(target_os = "macos")))] fn test_date_set_permissions_error() { - if !(get_effective_uid() == 0 || is_wsl()) { + if !(get_effective_uid() == 0 || uucore::os::is_wsl_1()) { let (_, mut ucmd) = at_and_ucmd!(); let result = ucmd.arg("--set").arg("2020-03-11 21:45:00+08:00").fails(); let result = result.no_stdout(); diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index b3b1b3465..a0d698de0 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -1,4 +1,5 @@ use crate::common::util::*; +use uucore; const SUB_DIR: &str = "subdir/deeper"; const SUB_DIR_LINKS: &str = "subdir/links"; @@ -52,7 +53,7 @@ fn _du_basics_subdir(s: String) { #[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))] fn _du_basics_subdir(s: String) { // MS-WSL linux has altered expected output - if !is_wsl() { + if !uucore::os::is_wsl_1() { assert_eq!(s, "8\tsubdir/deeper\n"); } else { assert_eq!(s, "0\tsubdir/deeper\n"); @@ -96,7 +97,7 @@ fn _du_soft_link(s: String) { #[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))] fn _du_soft_link(s: String) { // MS-WSL linux has altered expected output - if !is_wsl() { + if !uucore::os::is_wsl_1() { assert_eq!(s, "16\tsubdir/links\n"); } else { assert_eq!(s, "8\tsubdir/links\n"); @@ -128,7 +129,7 @@ fn _du_hard_link(s: String) { #[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))] fn _du_hard_link(s: String) { // MS-WSL linux has altered expected output - if !is_wsl() { + if !uucore::os::is_wsl_1() { assert_eq!(s, "16\tsubdir/links\n"); } else { assert_eq!(s, "8\tsubdir/links\n"); @@ -156,7 +157,7 @@ fn _du_d_flag(s: String) { #[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))] fn _du_d_flag(s: String) { // MS-WSL linux has altered expected output - if !is_wsl() { + if !uucore::os::is_wsl_1() { assert_eq!(s, "28\t./subdir\n36\t./\n"); } else { assert_eq!(s, "8\t./subdir\n8\t./\n"); diff --git a/tests/by-util/test_logname.rs b/tests/by-util/test_logname.rs index b15941c06..baaad63cc 100644 --- a/tests/by-util/test_logname.rs +++ b/tests/by-util/test_logname.rs @@ -1,5 +1,6 @@ use crate::common::util::*; use std::env; +use uucore; #[test] fn test_normal() { @@ -13,7 +14,7 @@ fn test_normal() { for (key, value) in env::vars() { println!("{}: {}", key, value); } - if (is_ci() || is_wsl()) && result.stderr.contains("error: no login name") { + if (is_ci() || uucore::os::is_wsl_1()) && result.stderr.contains("error: no login name") { // ToDO: investigate WSL failure // In the CI, some server are failing to return logname. // As seems to be a configuration issue, ignoring it diff --git a/tests/common/util.rs b/tests/common/util.rs index 708b8dbba..38f5a90cc 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -40,22 +40,6 @@ pub fn is_ci() -> bool { .eq_ignore_ascii_case("true") } -/// Test if the program is running under WSL -// ref: @@ -// ToDO: test on WSL2 which likely doesn't need special handling; plan change to `is_wsl_1()` if WSL2 is less needy -pub fn is_wsl() -> bool { - #[cfg(target_os = "linux")] - { - if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") { - if let Ok(s) = std::str::from_utf8(&b) { - let a = s.to_ascii_lowercase(); - return a.contains("microsoft") || a.contains("wsl"); - } - } - } - false -} - /// Read a test scenario fixture, returning its bytes fn read_scenario_fixture>(tmpd: &Option>, file_rel_path: S) -> Vec { let tmpdir_path = tmpd.as_ref().unwrap().as_ref().path();