diff --git a/Cargo.lock b/Cargo.lock index e9fdd91..65c12e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -130,12 +130,70 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "dns-lookup" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5766087c2235fec47fafa4cfecc81e494ee679d0fd4a59887ea0919bfb0e4fc" +dependencies = [ + "cfg-if", + "libc", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "errno" version = "0.3.8" @@ -192,6 +250,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + [[package]] name = "lazy_static" version = "1.4.0" @@ -233,6 +297,24 @@ dependencies = [ "libc", ] +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -286,6 +368,12 @@ dependencies = [ "siphasher", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -353,6 +441,7 @@ dependencies = [ "textwrap", "uu_free", "uu_pwdx", + "uu_w", "uucore", "xattr", ] @@ -396,6 +485,26 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -476,6 +585,26 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -488,12 +617,48 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sysinfo" +version = "0.30.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "windows", +] + [[package]] name = "tempfile" version = "3.9.0" @@ -539,6 +704,37 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "time" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +dependencies = [ + "deranged", + "itoa", + "libc", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +dependencies = [ + "time-core", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -563,6 +759,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "utmpx" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41adce4fa88980ec51d3fb705065deebb7ad27106d58772bdde6c34d74dc582b" +dependencies = [ + "libc", +] + [[package]] name = "uu_free" version = "0.0.1" @@ -579,6 +784,16 @@ dependencies = [ "uucore", ] +[[package]] +name = "uu_w" +version = "0.0.1" +dependencies = [ + "clap", + "sysinfo", + "utmpx", + "uucore", +] + [[package]] name = "uucore" version = "0.0.24" @@ -586,11 +801,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5de2eba1364f6274f35f121eb8671b98ac5fa8fe1271694721e17034e85e8bc" dependencies = [ "clap", + "dns-lookup", "glob", "libc", "nix", "once_cell", "os_display", + "time", "uucore_procs", "wild", ] @@ -627,6 +844,47 @@ dependencies = [ "glob", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index a6825af..1cddd63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ default = ["feat_common_core"] feat_common_core = [ "pwdx", "free", + "w", ] [workspace.dependencies] @@ -43,6 +44,7 @@ textwrap = { version = "0.16.0", features = ["terminal_size"] } xattr = "1.3.1" tempfile = "3.9.0" rand = { version = "0.8", features = ["small_rng"] } +utmpx = "0.1" [dependencies] clap = { workspace = true } @@ -56,6 +58,7 @@ textwrap = { workspace = true } # pwdx = { optional = true, version = "0.0.1", package = "uu_pwdx", path = "src/uu/pwdx" } free = { optional = true, version = "0.0.1", package = "uu_free", path = "src/uu/free" } +w = { optional = true, version = "0.0.1", package = "uu_w", path = "src/uu/w" } [dev-dependencies] pretty_assertions = "1" diff --git a/README.md b/README.md index e81938b..f27a62a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Provides command line and full screen utilities for browsing procfs, a "pseudo" Ongoing: * `pwdx`: Shows the current working directory of a process. * `free`: Shows the amount of free and used memory in the system. - +* `w`: Shows who is logged on and what they are doing. TODO: * `ps`: Displays information about active processes. @@ -18,7 +18,6 @@ TODO: * `tload`: Prints a graphical representation of system load average to the terminal. * `top`: Displays real-time information about system processes. * `vmstat`: Reports information about processes, memory, paging, block IO, traps, and CPU activity. -* `w`: Shows who is logged on and what they are doing. * `watch`: Executes a program periodically, showing output fullscreen. * `pkill`: Kills processes based on name and other attributes. * `snice`: Changes the scheduling priority of a running process. diff --git a/src/uu/w/Cargo.toml b/src/uu/w/Cargo.toml new file mode 100644 index 0000000..3abb9f3 --- /dev/null +++ b/src/uu/w/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "uu_w" +version = "0.0.1" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +uucore = { workspace = true, features = ["utmpx"] } +clap = { workspace = true } +utmpx = { workspace = true } +sysinfo = { workspace = true } + +[lib] +path = "src/w.rs" + +[[bin]] +name = "w" +path = "src/main.rs" diff --git a/src/uu/w/main.rs b/src/uu/w/main.rs new file mode 100644 index 0000000..b721b7d --- /dev/null +++ b/src/uu/w/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_w); diff --git a/src/uu/w/src/w.rs b/src/uu/w/src/w.rs new file mode 100644 index 0000000..fdb0e19 --- /dev/null +++ b/src/uu/w/src/w.rs @@ -0,0 +1,128 @@ +// This file is part of the uutils procps package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use clap::{Arg, ArgAction, Command}; +use clap::{crate_version}; +use std::process; +use uucore::{error::UResult, format_usage, help_about, help_usage}; +use uucore::utmpx::Utmpx; + +const ABOUT: &str = help_about!("w.md"); +const USAGE: &str = help_usage!("w.md"); + +struct UserInfo { + user: String, + terminal: String, + login_time: String, + idle_time: String, + jcpu: String, + pcpu: String, + command: String, +} + +fn fetch_user_info() -> Result, std::io::Error> { + let mut user_info_list = Vec::new(); + for entry in Utmpx::iter_all_records() { + if entry.is_user_process() { + let user_info = UserInfo { + user: entry.user(), + terminal: entry.tty_device(), + login_time: format!("{}", entry.login_time()), // Needs formatting + idle_time: String::new(), // Placeholder, needs actual implementation + jcpu: String::new(), // Placeholder, needs actual implementation + pcpu: String::new(), // Placeholder, needs actual implementation + command: String::new(), // Placeholder, needs actual implementation + }; + user_info_list.push(user_info); + } + } + + Ok(user_info_list) +} +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches = uu_app().try_get_matches_from(args)?; + + match fetch_user_info() { + Ok(user_info) => { + println!("USER\tTTY\t\tLOGIN@\t\tIDLE\tJCPU\tPCPU\tWHAT"); + for user in user_info { + println!("{}\t{}\t{}\t{}\t{}\t{}\t{}", + user.user, + user.terminal, + user.login_time, + user.idle_time, + user.jcpu, + user.pcpu, + user.command + ); + } + } + Err(e) => { + eprintln!("w: failed to fetch user info: {}", e); + process::exit(1); + } + } + + Ok(()) +} + +pub fn uu_app() -> Command { + Command::new(uucore::util_name()) + .version(crate_version!()) + .about(ABOUT) + .override_usage(format_usage(USAGE)) + .infer_long_args(true) + .disable_help_flag(true) + .arg( + Arg::new("no-header") + .short('h') + .long("no-header") + .help("do not print header") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("no-current") + .short('u') + .long("no-current") + .help("ignore current process username") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("short") + .short('s') + .long("short") + .help("short format") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("from") + .short('f') + .long("from") + .help("show remote hostname field") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("old-style") + .short('o') + .long("old-style") + .help("old style output") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("ip-addr") + .short('i') + .long("ip-addr") + .help("display IP address instead of hostname (if possible)") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("pids") + .short('p') + .long("pids") + .help("show the PID(s) of processes in WHAT") + .action(ArgAction::SetTrue), + ) +} diff --git a/src/uu/w/w.md b/src/uu/w/w.md new file mode 100644 index 0000000..35ac3ab --- /dev/null +++ b/src/uu/w/w.md @@ -0,0 +1,7 @@ +# w + +``` +w [options] [user] +``` + +Show who is logged on and what they are doing diff --git a/tests/by-util/test_w.rs b/tests/by-util/test_w.rs new file mode 100644 index 0000000..9a74a89 --- /dev/null +++ b/tests/by-util/test_w.rs @@ -0,0 +1,14 @@ +// This file is part of the uutils procps package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. +// spell-checker:ignore (words) symdir somefakedir + +use std::path::PathBuf; + +use crate::common::util::{TestScenario, UCommand}; + +#[test] +fn test_invalid_arg() { + new_ucmd!().arg("--definitely-invalid").fails().code_is(1); +} diff --git a/tests/tests.rs b/tests/tests.rs index 33ffec0..1b78033 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -12,3 +12,7 @@ mod test_pwdx; #[cfg(feature = "free")] #[path = "by-util/test_free.rs"] mod test_free; + +#[cfg(feature = "w")] +#[path = "by-util/test_w.rs"] +mod test_w;