From 576341bb9389b254fd198ed2906b8838b406c707 Mon Sep 17 00:00:00 2001 From: Jadi Date: Thu, 16 May 2024 17:54:22 +0330 Subject: [PATCH] users: support OpenBS using utmp OpenBSD uses the original utmp file format so the general `users` does not work there. By using the `utmp-classic` lib, we cna process the current users on the system from the /var/run/utmp and show the list. fixes #5665 --- Cargo.lock | 34 +++++++++-- Cargo.toml | 1 + src/uu/users/Cargo.toml | 3 + src/uu/users/src/platform/mod.rs | 14 ----- src/uu/users/src/platform/openbsd.rs | 17 ------ src/uu/users/src/platform/unix.rs | 53 ----------------- src/uu/users/src/users.rs | 82 ++++++++++++++++++++++++++- tests/by-util/test_users.rs | 9 +++ tests/fixtures/users/openbsd_utmp | Bin 0 -> 9728 bytes 9 files changed, 123 insertions(+), 90 deletions(-) delete mode 100644 src/uu/users/src/platform/mod.rs delete mode 100644 src/uu/users/src/platform/openbsd.rs delete mode 100644 src/uu/users/src/platform/unix.rs create mode 100644 tests/fixtures/users/openbsd_utmp diff --git a/Cargo.lock b/Cargo.lock index 856d392a3..23dd9d442 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2449,6 +2449,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "utmp-classic" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24c654e19afaa6b8f3877ece5d3bed849c2719c56f6752b18ca7da4fcc6e85a" +dependencies = [ + "cfg-if", + "libc", + "thiserror", + "time", + "utmp-classic-raw", + "zerocopy", +] + +[[package]] +name = "utmp-classic-raw" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22c226537a3d6e01c440c1926ca0256dbee2d19b2229ede6fc4863a6493dd831" +dependencies = [ + "cfg-if", + "zerocopy", +] + [[package]] name = "uu_arch" version = "0.0.27" @@ -3390,6 +3414,7 @@ name = "uu_users" version = "0.0.27" dependencies = [ "clap", + "utmp-classic", "uucore", ] @@ -3897,18 +3922,19 @@ checksum = "2a599daf1b507819c1121f0bf87fa37eb19daac6aff3aefefd4e6e2e0f2020fc" [[package]] name = "zerocopy" -version = "0.7.33" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "087eca3c1eaf8c47b94d02790dd086cd594b912d2043d4de4bfdd466b3befb7c" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.33" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4b6c273f496d8fd4eaf18853e6b448760225dc030ff2c485a786859aea6393" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index aa6b4424d..d3d726ae6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -330,6 +330,7 @@ time = { version = "0.3.36" } unicode-segmentation = "1.11.0" unicode-width = "0.1.12" utf-8 = "0.7.6" +utmp-classic = "0.1.6" walkdir = "2.5" winapi-util = "0.1.8" windows-sys = { version = "0.48.0", default-features = false } diff --git a/src/uu/users/Cargo.toml b/src/uu/users/Cargo.toml index 8b280c7a6..9625bbf50 100644 --- a/src/uu/users/Cargo.toml +++ b/src/uu/users/Cargo.toml @@ -18,6 +18,9 @@ path = "src/users.rs" clap = { workspace = true } uucore = { workspace = true, features = ["utmpx"] } +[target.'cfg(target_os = "openbsd")'.dependencies] +utmp-classic = { workspace = true } + [[bin]] name = "users" path = "src/main.rs" diff --git a/src/uu/users/src/platform/mod.rs b/src/uu/users/src/platform/mod.rs deleted file mode 100644 index e0e87dca1..000000000 --- a/src/uu/users/src/platform/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -// This file is part of the uutils coreutils package. -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -#[cfg(not(target_os = "openbsd"))] -mod unix; -#[cfg(not(target_os = "openbsd"))] -pub use self::unix::*; - -#[cfg(target_os = "openbsd")] -mod openbsd; -#[cfg(target_os = "openbsd")] -pub use self::openbsd::*; diff --git a/src/uu/users/src/platform/openbsd.rs b/src/uu/users/src/platform/openbsd.rs deleted file mode 100644 index 7e6970c1f..000000000 --- a/src/uu/users/src/platform/openbsd.rs +++ /dev/null @@ -1,17 +0,0 @@ -// This file is part of the uutils coreutils package. -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -// Specific implementation for OpenBSD: tool unsupported (utmpx not supported) - -use crate::uu_app; - -use uucore::error::UResult; - -pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let _matches = uu_app().try_get_matches_from(args)?; - - println!("unsupported command on OpenBSD"); - Ok(()) -} diff --git a/src/uu/users/src/platform/unix.rs b/src/uu/users/src/platform/unix.rs deleted file mode 100644 index 99c9ce776..000000000 --- a/src/uu/users/src/platform/unix.rs +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of the uutils coreutils package. -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -// spell-checker:ignore (paths) wtmp - -use crate::uu_app; - -use std::ffi::OsString; -use std::path::Path; - -use uucore::error::UResult; -use uucore::utmpx::{self, Utmpx}; - -static ARG_FILES: &str = "files"; - -fn get_long_usage() -> String { - format!( - "Output who is currently logged in according to FILE. -If FILE is not specified, use {}. /var/log/wtmp as FILE is common.", - utmpx::DEFAULT_FILE - ) -} - -pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let matches = uu_app() - .after_help(get_long_usage()) - .try_get_matches_from(args)?; - - let files: Vec<&Path> = matches - .get_many::(ARG_FILES) - .map(|v| v.map(AsRef::as_ref).collect()) - .unwrap_or_default(); - - let filename = if files.is_empty() { - utmpx::DEFAULT_FILE.as_ref() - } else { - files[0] - }; - - let mut users = Utmpx::iter_all_records_from(filename) - .filter(Utmpx::is_user_process) - .map(|ut| ut.user()) - .collect::>(); - - if !users.is_empty() { - users.sort(); - println!("{}", users.join(" ")); - } - - Ok(()) -} diff --git a/src/uu/users/src/users.rs b/src/uu/users/src/users.rs index d299399f3..a6978a8d9 100644 --- a/src/uu/users/src/users.rs +++ b/src/uu/users/src/users.rs @@ -5,19 +5,97 @@ // spell-checker:ignore (paths) wtmp +use std::ffi::OsString; +use std::path::Path; + use clap::builder::ValueParser; use clap::{crate_version, Arg, Command}; +use uucore::error::UResult; use uucore::{format_usage, help_about, help_usage}; -mod platform; +#[cfg(target_os = "openbsd")] +use utmp_classic::{parse_from_path, UtmpEntry}; +#[cfg(not(target_os = "openbsd"))] +use uucore::utmpx::{self, Utmpx}; const ABOUT: &str = help_about!("users.md"); const USAGE: &str = help_usage!("users.md"); +#[cfg(target_os = "openbsd")] +const OPENBSD_UTMP_FILE: &str = "/var/run/utmp"; + static ARG_FILES: &str = "files"; +fn get_long_usage() -> String { + #[cfg(not(target_os = "openbsd"))] + let default_path: &str = utmpx::DEFAULT_FILE; + #[cfg(target_os = "openbsd")] + let default_path: &str = OPENBSD_UTMP_FILE; + format!( + "Output who is currently logged in according to FILE. +If FILE is not specified, use {}. /var/log/wtmp as FILE is common.", + default_path + ) +} + #[uucore::main] -use platform::uumain; +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches = uu_app() + .after_help(get_long_usage()) + .try_get_matches_from(args)?; + + let files: Vec<&Path> = matches + .get_many::(ARG_FILES) + .map(|v| v.map(AsRef::as_ref).collect()) + .unwrap_or_default(); + + let mut users: Vec; + + // OpenBSD uses the Unix version 1 UTMP, all other Unixes use the newer UTMPX + #[cfg(target_os = "openbsd")] + { + let filename = if files.is_empty() { + Path::new(OPENBSD_UTMP_FILE) + } else { + files[0] + }; + let entries = parse_from_path(&filename).unwrap_or(Vec::new()); + users = Vec::new(); + for entry in entries { + if let UtmpEntry::UTMP { + line: _, + user, + host: _, + time: _, + } = entry + { + if !user.is_empty() { + users.push(user); + } + } + } + }; + #[cfg(not(target_os = "openbsd"))] + { + let filename = if files.is_empty() { + utmpx::DEFAULT_FILE.as_ref() + } else { + files[0] + }; + + users = Utmpx::iter_all_records_from(filename) + .filter(Utmpx::is_user_process) + .map(|ut| ut.user()) + .collect::>(); + }; + + if !users.is_empty() { + users.sort(); + println!("{}", users.join(" ")); + } + + Ok(()) +} pub fn uu_app() -> Command { Command::new(uucore::util_name()) diff --git a/tests/by-util/test_users.rs b/tests/by-util/test_users.rs index 3d87aa9d0..9ca548fb9 100644 --- a/tests/by-util/test_users.rs +++ b/tests/by-util/test_users.rs @@ -31,3 +31,12 @@ fn test_users_check_name() { new_ucmd!().succeeds().stdout_is(&expected); } + +#[test] +#[cfg(target_os = "openbsd")] +fn test_users_check_name_openbsd() { + new_ucmd!() + .args(&["openbsd_utmp"]) + .run() + .stdout_contains("test"); +} diff --git a/tests/fixtures/users/openbsd_utmp b/tests/fixtures/users/openbsd_utmp new file mode 100644 index 0000000000000000000000000000000000000000..958d7510c380ac9faed61f2898d65bdb83192be1 GIT binary patch literal 9728 zcmZP=1*0J_8UlkR1WHOOoedcn7)nx$O9qXj2BAZm-nyiLoCOLmBL)VBqWt{P@B#%0 z4lMS?1Rh?-IMj>^BSPR3vnx2f5F(?j(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc2c z4S~@R7!85Z5Eu=C(GVC7fsq~pB_)*wpz-_C;?yF1VPR-#q-SVmp=V^IXJ}-APv!8G z%bD!~9$y887ij!`c>0ohz7pUwg@+et{GQPKkfD*eo`If$9w;qR&lN+*q~BV^pu2<{xIF;?tcxoT literal 0 HcmV?d00001