From 024bdf1bdc8ed88f45e6524f3314cfef1936f940 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:33:37 +0800 Subject: [PATCH 01/38] pidwait: Add command `pidwait` And also introduce dependency `polling` for polling `waitpid` syscall --- Cargo.lock | 68 ++++++++++++++++- Cargo.toml | 3 + src/uu/pgrep/src/process.rs | 2 +- src/uu/pidwait/Cargo.toml | 27 +++++++ src/uu/pidwait/pidwait.md | 7 ++ src/uu/pidwait/src/main.rs | 1 + src/uu/pidwait/src/pidwait.rs | 133 ++++++++++++++++++++++++++++++++++ 7 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/uu/pidwait/Cargo.toml create mode 100644 src/uu/pidwait/pidwait.md create mode 100644 src/uu/pidwait/src/main.rs create mode 100644 src/uu/pidwait/src/pidwait.rs diff --git a/Cargo.lock b/Cargo.lock index 2a27b59..96986bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -344,6 +353,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -373,7 +388,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -384,7 +399,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.52.0", ] @@ -566,6 +581,27 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "polling" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.32", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -632,6 +668,7 @@ dependencies = [ "uu_free", "uu_pgrep", "uu_pidof", + "uu_pidwait", "uu_pmap", "uu_ps", "uu_pwdx", @@ -986,6 +1023,22 @@ dependencies = [ "time-core", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -1039,6 +1092,17 @@ dependencies = [ "uucore", ] +[[package]] +name = "uu_pidwait" +version = "0.0.1" +dependencies = [ + "clap", + "polling", + "regex", + "uu_pgrep", + "uucore", +] + [[package]] name = "uu_pmap" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index 06135b2..8a4f5bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ feat_common_core = [ "pgrep", "pidof", "ps", + "pidwait", ] [workspace.dependencies] @@ -57,6 +58,7 @@ chrono = { version = "0.4.38", default-features = false, features = ["clock"] } walkdir = "2.5.0" prettytable-rs = "0.10.0" nix = { version = "0.29", default-features = false } +polling = "3.7.2" [dependencies] clap = { workspace = true } @@ -78,6 +80,7 @@ slabtop = { optional = true, version = "0.0.1", package = "uu_slabtop", path = " pgrep = { optional = true, version = "0.0.1", package = "uu_pgrep", path = "src/uu/pgrep" } pidof = { optional = true, version = "0.0.1", package = "uu_pidof", path = "src/uu/pidof" } ps = { optional = true, version = "0.0.1", package = "uu_ps", path = "src/uu/ps" } +pidwait = { optional = true, version = "0.0.1", package = "uu_pidwait", path = "src/uu/pidwait" } [dev-dependencies] pretty_assertions = "1.4.0" diff --git a/src/uu/pgrep/src/process.rs b/src/uu/pgrep/src/process.rs index 67229f4..d0c63c7 100644 --- a/src/uu/pgrep/src/process.rs +++ b/src/uu/pgrep/src/process.rs @@ -97,7 +97,7 @@ impl TryFrom for Teletype { } /// State or process -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum RunState { ///`R`, running Running, diff --git a/src/uu/pidwait/Cargo.toml b/src/uu/pidwait/Cargo.toml new file mode 100644 index 0000000..14ad159 --- /dev/null +++ b/src/uu/pidwait/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "uu_pidwait" +version = "0.0.1" +edition = "2021" +authors = ["uutils developers"] +license = "MIT" +description = "pidwait ~ (uutils) Wait for processes based on name" + +homepage = "https://github.com/uutils/procps" +repository = "https://github.com/uutils/procps/tree/main/src/uu/pidwait" +keywords = ["acl", "uutils", "cross-platform", "cli", "utility"] +categories = ["command-line-utilities"] + + +[dependencies] +uucore = { workspace = true } +clap = { workspace = true } +polling = { workspace = true } +regex = { workspace = true } +uu_pgrep = { path = "../pgrep" } + +[lib] +path = "src/pidwait.rs" + +[[bin]] +name = "pidwait" +path = "src/main.rs" diff --git a/src/uu/pidwait/pidwait.md b/src/uu/pidwait/pidwait.md new file mode 100644 index 0000000..fb60ef5 --- /dev/null +++ b/src/uu/pidwait/pidwait.md @@ -0,0 +1,7 @@ +# pidwait + +``` +pidwait [options] pattern +``` + +Wait for processes based on name. diff --git a/src/uu/pidwait/src/main.rs b/src/uu/pidwait/src/main.rs new file mode 100644 index 0000000..5a989ee --- /dev/null +++ b/src/uu/pidwait/src/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_pidwait); diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs new file mode 100644 index 0000000..21eeea7 --- /dev/null +++ b/src/uu/pidwait/src/pidwait.rs @@ -0,0 +1,133 @@ +// 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, crate_version, ArgMatches, Command}; +use regex::Regex; +use std::{collections::HashSet, env, sync::OnceLock}; +use uu_pgrep::process::{walk_process, ProcessInformation, RunState, Teletype}; +use uucore::{ + error::{UResult, USimpleError}, + format_usage, help_about, help_usage, +}; + +const ABOUT: &str = help_about!("pidwait.md"); +const USAGE: &str = help_usage!("pidwait.md"); + +static REGEX: OnceLock = OnceLock::new(); + +#[derive(Debug)] +struct Settings { + echo: bool, + count: bool, + full: bool, + ignore_case: bool, + newest: bool, + oldest: bool, + older: usize, + terminal: HashSet, + exact: bool, + runstates: HashSet, +} + +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches = uu_app().try_get_matches_from(args)?; + + let settings = Settings { + echo: matches.get_flag("echo"), + count: matches.get_flag("count"), + full: matches.get_flag("full"), + ignore_case: matches.get_flag("ignore-case"), + newest: matches.get_flag("newest"), + oldest: matches.get_flag("oldest"), + older: matches + .get_one::("older") + .copied() + .unwrap_or_default(), + terminal: matches + .get_many("terminal") + .unwrap_or_default() + .cloned() + .collect(), + exact: matches.get_flag("exact"), + runstates: matches + .get_many("terminal") + .unwrap_or_default() + .cloned() + .collect(), + }; + + let pattern = try_get_pattern_from(&matches, &settings)?; + REGEX + .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) + .unwrap(); + + collect_proc_infos(settings); + + Ok(()) +} + +fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult { + let pattern = match matches.get_many::("pattern") { + Some(patterns) if patterns.len() > 1 => { + return Err(USimpleError::new( + 2, + "only one pattern can be provided\nTry `pidwait --help' for more information.", + )) + } + Some(mut patterns) => patterns.next().unwrap(), + None => return Ok(String::new()), + }; + + let pattern = if settings.ignore_case { + &pattern.to_lowercase() + } else { + pattern + }; + + let pattern = if settings.exact { + &format!("^{}$", pattern) + } else { + pattern + }; + + Ok(pattern.to_string()) +} + +fn collect_proc_infos(settings: Settings) -> Vec { + let proc_infos: Vec<_> = walk_process().collect(); + + proc_infos +} + +#[allow(clippy::cognitive_complexity)] +pub fn uu_app() -> Command { + Command::new(env!("CARGO_PKG_NAME")) + .version(crate_version!()) + .about(ABOUT) + .override_usage(format_usage(USAGE)) + .infer_long_args(true) + .args([ + arg!(-e --echo "display PIDs before waiting"), + arg!(-c --count "count of matching processes"), + arg!(-f --full "use full process name to match"), + // arg!(-g --pgroup "match listed process group IDs"), + // arg!(-G --group "match real group IDs"), + arg!(-i --"ignore-case" "match case insensitively"), + arg!(-n --newest "select most recently started"), + arg!(-o --oldest "select least recently started"), + arg!(-O --older "select where older than seconds"), + // arg!(-P --parent "match only child processes of the given parent"), + // arg!(-s --session "match session IDs"), + arg!(-t --terminal "match by controlling terminal"), + // arg!(-u --euid "match by effective IDs"), + // arg!(-U --uid "match by real IDs"), + arg!(-x --exact "match exactly with the command name"), + // arg!(-F --pidfile "read PIDs from file"), + // arg!(-L --logpidfile "fail if PID file is not locked"), + arg!(-r --runstates "match runstates [D,S,Z,...]"), + // arg!(-A --"ignore-ancestors" "exclude our ancestors from results"), + ]) +} From 8faf849b4287a15f0c06ab58f74d9dc6e10a49fc Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:40:39 +0800 Subject: [PATCH 02/38] pidwait: Add basic test for `pidwait` --- tests/by-util/test_pidwait.rs | 11 +++++++++++ tests/tests.rs | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 tests/by-util/test_pidwait.rs diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs new file mode 100644 index 0000000..85ca6f4 --- /dev/null +++ b/tests/by-util/test_pidwait.rs @@ -0,0 +1,11 @@ +// 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 crate::common::util::TestScenario; + +#[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 d1cb34e..dc69d60 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -40,3 +40,7 @@ mod test_pidof; #[cfg(feature = "ps")] #[path = "by-util/test_ps.rs"] mod test_ps; + +#[cfg(feature = "pidwait")] +#[path = "by-util/test_pidwait.rs"] +mod test_pidwait; From 35f9ddee876f1708b75e6b849fc7f73cf00cdc9f Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:46:59 +0800 Subject: [PATCH 03/38] pidwait: Fix collecting for `runstates` --- src/uu/pidwait/src/pidwait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 21eeea7..8b3eaf5 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -53,7 +53,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .collect(), exact: matches.get_flag("exact"), runstates: matches - .get_many("terminal") + .get_many("runstates") .unwrap_or_default() .cloned() .collect(), From d84d47c1c2ed659da401845951b2e222854275b3 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:48:59 +0800 Subject: [PATCH 04/38] pidwait: Implemented flag `-c` --- src/uu/pidwait/src/pidwait.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 8b3eaf5..baccff8 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -64,7 +64,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) .unwrap(); - collect_proc_infos(settings); + let proc_infos = collect_proc_infos(&settings); + + if settings.count { + println!("{}", proc_infos.len()) + } Ok(()) } @@ -96,7 +100,7 @@ fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult Vec { +fn collect_proc_infos(settings: &Settings) -> Vec { let proc_infos: Vec<_> = walk_process().collect(); proc_infos From 9cd0d930392e3fcd4580262306bbe4fc55cc81f7 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:56:46 +0800 Subject: [PATCH 05/38] pidwait: Implemented flag `-e` --- src/uu/pidwait/src/pidwait.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index baccff8..ab2a8fa 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -64,12 +64,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) .unwrap(); - let proc_infos = collect_proc_infos(&settings); + let mut proc_infos = collect_proc_infos(&settings); + // Process outputting if settings.count { println!("{}", proc_infos.len()) } + if settings.echo { + for ele in proc_infos.iter_mut() { + println!("waiting for {} (pid {})", ele.status()["Name"], ele.pid) + } + } + Ok(()) } From 06906108885cec729795dbad8cef8d131fc216d6 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 00:16:18 +0800 Subject: [PATCH 06/38] pidwait: Handle empty input --- src/uu/pidwait/src/pidwait.rs | 40 +++++++++++++++++++++-------------- tests/by-util/test_pidwait.rs | 9 ++++++++ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index ab2a8fa..fdc65fe 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -25,10 +25,10 @@ struct Settings { ignore_case: bool, newest: bool, oldest: bool, - older: usize, - terminal: HashSet, + older: Option, + terminal: Option>, exact: bool, - runstates: HashSet, + runstates: Option, } #[uucore::main] @@ -42,23 +42,26 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { ignore_case: matches.get_flag("ignore-case"), newest: matches.get_flag("newest"), oldest: matches.get_flag("oldest"), - older: matches - .get_one::("older") - .copied() - .unwrap_or_default(), + older: matches.get_one::("older").copied(), terminal: matches - .get_many("terminal") - .unwrap_or_default() - .cloned() - .collect(), + .get_many::("terminal") + .map(|it| it.cloned().collect()), exact: matches.get_flag("exact"), - runstates: matches - .get_many("runstates") - .unwrap_or_default() - .cloned() - .collect(), + runstates: matches.get_one::("runstates").cloned(), }; + if !settings.newest + && !settings.oldest + && settings.runstates.is_none() + && settings.older.is_none() + && settings.terminal.is_none() + { + return Err(USimpleError::new( + 2, + "no matching criteria specified\nTry `pidwait --help' for more information.", + )); + } + let pattern = try_get_pattern_from(&matches, &settings)?; REGEX .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) @@ -109,6 +112,11 @@ fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult Vec { let proc_infos: Vec<_> = walk_process().collect(); + if settings.oldest || settings.newest { + if settings.oldest { + } else if settings.newest { + } + } proc_infos } diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 85ca6f4..f099971 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -9,3 +9,12 @@ use crate::common::util::TestScenario; fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails().code_is(1); } + +#[test] +fn test_no_args() { + new_ucmd!() + .fails() + .code_is(2) + .no_stdout() + .stderr_contains("no matching criteria specified"); +} From 1f29c74794c16b35462cc2a1fe48253c69312e34 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 00:32:10 +0800 Subject: [PATCH 07/38] pidwait: Implemented pattern initialize --- src/uu/pidwait/src/pidwait.rs | 33 +++++++++++++++++++++++---------- tests/by-util/test_pidwait.rs | 20 ++++++++++++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index fdc65fe..3397b74 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use clap::{arg, crate_version, ArgMatches, Command}; +use clap::{arg, crate_version, Arg, ArgAction, ArgMatches, Command}; use regex::Regex; use std::{collections::HashSet, env, sync::OnceLock}; use uu_pgrep::process::{walk_process, ProcessInformation, RunState, Teletype}; @@ -50,11 +50,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { runstates: matches.get_one::("runstates").cloned(), }; - if !settings.newest + let pattern = pattern_initialize(&matches, &settings)?; + REGEX + .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) + .unwrap(); + + if (!settings.newest && !settings.oldest && settings.runstates.is_none() && settings.older.is_none() - && settings.terminal.is_none() + && settings.terminal.is_none()) + && pattern.is_empty() { return Err(USimpleError::new( 2, @@ -62,14 +68,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )); } - let pattern = try_get_pattern_from(&matches, &settings)?; - REGEX - .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) - .unwrap(); - let mut proc_infos = collect_proc_infos(&settings); - // Process outputting + // Process outputs if settings.count { println!("{}", proc_infos.len()) } @@ -83,7 +84,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult { +fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult { let pattern = match matches.get_many::("pattern") { Some(patterns) if patterns.len() > 1 => { return Err(USimpleError::new( @@ -107,6 +108,12 @@ fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult Command { arg!(-r --runstates "match runstates [D,S,Z,...]"), // arg!(-A --"ignore-ancestors" "exclude our ancestors from results"), ]) + .arg( + Arg::new("pattern") + .help("Name of the program to find the PID of") + .action(ArgAction::Append) + .index(1), + ) } diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index f099971..13b48ba 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -10,6 +10,15 @@ fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails().code_is(1); } +#[test] +fn test_non_matching_pattern() { + new_ucmd!() + .arg("THIS_PATTERN_DOES_NOT_MATCH") + .fails() + .code_is(1) + .stderr_contains("pidwait: pattern that searches for process name longer than 15 characters will result in zero matches"); +} + #[test] fn test_no_args() { new_ucmd!() @@ -18,3 +27,14 @@ fn test_no_args() { .no_stdout() .stderr_contains("no matching criteria specified"); } + +#[test] +fn test_too_many_patterns() { + new_ucmd!() + .arg("sh") + .arg("sh") + .fails() + .code_is(2) + .no_stdout() + .stderr_contains("only one pattern can be provided"); +} From 89e29fed30ba1aa7487290f4d0713524f39c1305 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 02:20:03 +0800 Subject: [PATCH 08/38] pidwait: Handle empty collection for process From manpage: > 1 No processes matched or none of them could be signalled. --- src/uu/pidwait/src/pidwait.rs | 5 +++++ tests/by-util/test_pidwait.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 3397b74..e548920 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -70,6 +70,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let mut proc_infos = collect_proc_infos(&settings); + // For empty result + if proc_infos.is_empty() { + uucore::error::set_exit_code(1); + } + // Process outputs if settings.count { println!("{}", proc_infos.len()) diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 13b48ba..8629cd6 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -17,6 +17,8 @@ fn test_non_matching_pattern() { .fails() .code_is(1) .stderr_contains("pidwait: pattern that searches for process name longer than 15 characters will result in zero matches"); + + new_ucmd!().arg("DOES_NOT_MATCH").fails().code_is(1); } #[test] From ffc933189b42f5ea9d71f057e3bf2b5c7483c145 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 02:45:43 +0800 Subject: [PATCH 09/38] pidwait: Implemented flag `-o`, `-n`, `-O` --- src/uu/pidwait/src/pidwait.rs | 49 ++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index e548920..514eb53 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -123,13 +123,54 @@ fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult Vec { - let proc_infos: Vec<_> = walk_process().collect(); - if settings.oldest || settings.newest { - if settings.oldest { - } else if settings.newest { + // Process `-O` + let mut proc_infos: Vec<_> = { + let mut proc_infos = Vec::new(); + let older = settings.older.unwrap_or_default(); + for mut proc_info in walk_process() { + if proc_info.start_time().unwrap() >= older { + proc_infos.push(proc_info) + } } + proc_infos + }; + + if proc_infos.is_empty() { + return proc_infos; } + // Sorting oldest and newest + let proc_infos = if settings.oldest || settings.newest { + proc_infos.sort_by(|a, b| { + b.clone() + .start_time() + .unwrap() + .cmp(&a.clone().start_time().unwrap()) + }); + + let start_time = if settings.newest { + proc_infos.first().cloned().unwrap().start_time().unwrap() + } else { + proc_infos.last().cloned().unwrap().start_time().unwrap() + }; + + // There might be some process start at same time, so need to be filtered. + let mut filtered = proc_infos + .iter() + .filter(|it| (*it).clone().start_time().unwrap() == start_time) + .collect::>(); + + if settings.newest { + filtered.sort_by(|a, b| b.pid.cmp(&a.pid)) + } else { + filtered.sort_by(|a, b| a.pid.cmp(&b.pid)) + } + + vec![filtered.first().cloned().unwrap().clone()] + } else { + proc_infos + }; + proc_infos } From 63d2b19ccc8cfe180e678abc321e573e94a9b193 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 02:58:06 +0800 Subject: [PATCH 10/38] pidwait: Fix checking the length of pattern --- src/uu/pidwait/src/pidwait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 514eb53..8c741f2 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -113,7 +113,7 @@ fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult= 15 { const MSG_0: &str= "pidwait: pattern that searches for process name longer than 15 characters will result in zero matches"; const MSG_1: &str = "Try `pidwait -f' option to match against the complete command line."; return Err(USimpleError::new(1, format!("{MSG_0}\n{MSG_1}"))); From 1ebb89f61823e58281b69d5d7692c432e595be91 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 03:06:02 +0800 Subject: [PATCH 11/38] pidwait: Implemented filter based regex --- src/uu/pidwait/src/pidwait.rs | 46 +++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 8c741f2..46ac1b2 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -123,16 +123,46 @@ fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult Vec { - // Process `-O` - let mut proc_infos: Vec<_> = { - let mut proc_infos = Vec::new(); - let older = settings.older.unwrap_or_default(); - for mut proc_info in walk_process() { - if proc_info.start_time().unwrap() >= older { - proc_infos.push(proc_info) + // Process pattern + let proc_infos = { + let mut temp = Vec::new(); + for mut it in walk_process() { + let matched = { + let binding = it.status(); + let name = binding.get("Name").unwrap(); + let name = if settings.ignore_case { + name.to_lowercase() + } else { + name.into() + }; + + let want = if settings.exact { + &name + } else if settings.full { + &it.cmdline + } else { + &it.proc_stat()[..15] + }; + + REGEX.get().unwrap().is_match(want) + }; + if matched { + temp.push(it) } } - proc_infos + temp + }; + + // Process `-O` + let mut proc_infos = { + let mut temp: Vec = Vec::new(); + let older = settings.older.unwrap_or_default(); + for mut proc_info in proc_infos { + if proc_info.start_time().unwrap() >= older { + temp.push(proc_info) + } + } + temp }; if proc_infos.is_empty() { From 37da5fb7eb693a904da221b725f3e318b66bb185 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Sat, 10 Aug 2024 03:25:58 +0800 Subject: [PATCH 12/38] pidwait: Implemented waiting on Linux. --- Cargo.lock | 350 +++++++++++++++++++++++++++++++++- Cargo.toml | 5 +- src/uu/pidwait/Cargo.toml | 4 +- src/uu/pidwait/src/pidwait.rs | 5 + src/uu/pidwait/src/wait.rs | 37 ++++ tests/by-util/test_pidwait.rs | 24 +++ 6 files changed, 421 insertions(+), 4 deletions(-) create mode 100644 src/uu/pidwait/src/wait.rs diff --git a/Cargo.lock b/Cargo.lock index 96986bf..742d2b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -74,12 +89,154 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 0.38.32", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 0.38.32", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-signal" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.32", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -92,6 +249,19 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -324,12 +494,58 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "getrandom" version = "0.2.14" @@ -341,6 +557,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "glob" version = "0.3.1" @@ -382,6 +604,28 @@ dependencies = [ "cc", ] +[[package]] +name = "inotify" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" +dependencies = [ + "bitflags 1.3.2", + "futures-core", + "inotify-sys", + "libc", + "tokio", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -465,6 +709,27 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "nix" version = "0.28.0" @@ -528,6 +793,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -543,6 +817,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "phf" version = "0.11.2" @@ -587,6 +867,17 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "piper" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "polling" version = "3.7.2" @@ -793,6 +1084,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustix" version = "0.37.27" @@ -861,18 +1158,53 @@ dependencies = [ "syn", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smawk" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "smol" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", +] + [[package]] name = "socket2" version = "0.5.6" @@ -1023,6 +1355,20 @@ dependencies = [ "time-core", ] +[[package]] +name = "tokio" +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +dependencies = [ + "backtrace", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + [[package]] name = "tracing" version = "0.1.40" @@ -1097,8 +1443,10 @@ name = "uu_pidwait" version = "0.0.1" dependencies = [ "clap", - "polling", + "inotify", + "nix 0.29.0", "regex", + "smol", "uu_pgrep", "uucore", ] diff --git a/Cargo.toml b/Cargo.toml index 8a4f5bc..1ec5964 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,8 +57,9 @@ bytesize = "1.3.0" chrono = { version = "0.4.38", default-features = false, features = ["clock"] } walkdir = "2.5.0" prettytable-rs = "0.10.0" -nix = { version = "0.29", default-features = false } -polling = "3.7.2" +nix = { version = "0.29", default-features = false, features = ["process"] } +smol = "2.0.0" +inotify = "0.10.2" [dependencies] clap = { workspace = true } diff --git a/src/uu/pidwait/Cargo.toml b/src/uu/pidwait/Cargo.toml index 14ad159..b7fc7f5 100644 --- a/src/uu/pidwait/Cargo.toml +++ b/src/uu/pidwait/Cargo.toml @@ -13,9 +13,11 @@ categories = ["command-line-utilities"] [dependencies] +nix = { workspace = true } uucore = { workspace = true } clap = { workspace = true } -polling = { workspace = true } +smol = { workspace = true } +inotify = { workspace = true } regex = { workspace = true } uu_pgrep = { path = "../pgrep" } diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 46ac1b2..d96b62e 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -11,6 +11,9 @@ use uucore::{ error::{UResult, USimpleError}, format_usage, help_about, help_usage, }; +use wait::waiting; + +mod wait; const ABOUT: &str = help_about!("pidwait.md"); const USAGE: &str = help_usage!("pidwait.md"); @@ -86,6 +89,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } + waiting(&proc_infos); + Ok(()) } diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs new file mode 100644 index 0000000..4391a51 --- /dev/null +++ b/src/uu/pidwait/src/wait.rs @@ -0,0 +1,37 @@ +// 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 uu_pgrep::process::ProcessInformation; +use uu_pgrep::process::RunState; + +// Dirty, but it works. +// TODO: Use better implementation instead +#[cfg(target_os = "linux")] +pub(crate) fn waiting(procs: &[ProcessInformation]) { + use std::{path::PathBuf, str::FromStr}; + + let mut list = procs.to_vec(); + + loop { + for proc in procs.iter().cloned() { + let proc_path = PathBuf::from_str(&format!("/proc/{}", proc.pid)).unwrap(); + if !proc_path.exists() { + list.retain(|it| it.pid != proc.pid); + } + + if let Ok(mut proc) = ProcessInformation::try_new(proc_path) { + if proc.run_state().unwrap() == RunState::Stopped { + list.retain(|it| it.pid != proc.pid); + } + } else { + list.retain(|it| it.pid != proc.pid); + }; + } + + if list.is_empty() { + return; + } + } +} diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 8629cd6..d667059 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -4,6 +4,8 @@ // file that was distributed with this source code. use crate::common::util::TestScenario; +use std::process::Command; +use std::{thread, time::Duration}; #[test] fn test_invalid_arg() { @@ -40,3 +42,25 @@ fn test_too_many_patterns() { .no_stdout() .stderr_contains("only one pattern can be provided"); } + +// #[test] +// #[cfg(target_os = "linux")] +// fn test_waiting() { +// for _ in 0..3 { +// let _ = Command::new("sleep").arg("3").spawn().unwrap(); +// } + +// thread::sleep(Duration::from_secs(1)); + +// let binding = new_ucmd!().arg("sleep").arg("-c").succeeds(); +// let output = binding.stdout_str(); + +// let output = dbg!(output); + +// let count = output.lines().collect::>()[0] +// .trim() +// .parse::() +// .unwrap(); + +// assert_eq!(count, 3) +// } From d308aefcf2c707e39632b5c4d01774075fd3d80c Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:33:37 +0800 Subject: [PATCH 13/38] pidwait: Add command `pidwait` And also introduce dependency `polling` for polling `waitpid` syscall --- Cargo.lock | 68 ++++++++++++++++- Cargo.toml | 3 + src/uu/pgrep/src/process.rs | 2 +- src/uu/pidwait/Cargo.toml | 27 +++++++ src/uu/pidwait/pidwait.md | 7 ++ src/uu/pidwait/src/main.rs | 1 + src/uu/pidwait/src/pidwait.rs | 133 ++++++++++++++++++++++++++++++++++ 7 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/uu/pidwait/Cargo.toml create mode 100644 src/uu/pidwait/pidwait.md create mode 100644 src/uu/pidwait/src/main.rs create mode 100644 src/uu/pidwait/src/pidwait.rs diff --git a/Cargo.lock b/Cargo.lock index e2ecf28..b463c54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -344,6 +353,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -373,7 +388,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -384,7 +399,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "windows-sys 0.52.0", ] @@ -566,6 +581,27 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "polling" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.32", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -632,6 +668,7 @@ dependencies = [ "uu_free", "uu_pgrep", "uu_pidof", + "uu_pidwait", "uu_pmap", "uu_ps", "uu_pwdx", @@ -986,6 +1023,22 @@ dependencies = [ "time-core", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -1039,6 +1092,17 @@ dependencies = [ "uucore", ] +[[package]] +name = "uu_pidwait" +version = "0.0.1" +dependencies = [ + "clap", + "polling", + "regex", + "uu_pgrep", + "uucore", +] + [[package]] name = "uu_pmap" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index 06135b2..8a4f5bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ feat_common_core = [ "pgrep", "pidof", "ps", + "pidwait", ] [workspace.dependencies] @@ -57,6 +58,7 @@ chrono = { version = "0.4.38", default-features = false, features = ["clock"] } walkdir = "2.5.0" prettytable-rs = "0.10.0" nix = { version = "0.29", default-features = false } +polling = "3.7.2" [dependencies] clap = { workspace = true } @@ -78,6 +80,7 @@ slabtop = { optional = true, version = "0.0.1", package = "uu_slabtop", path = " pgrep = { optional = true, version = "0.0.1", package = "uu_pgrep", path = "src/uu/pgrep" } pidof = { optional = true, version = "0.0.1", package = "uu_pidof", path = "src/uu/pidof" } ps = { optional = true, version = "0.0.1", package = "uu_ps", path = "src/uu/ps" } +pidwait = { optional = true, version = "0.0.1", package = "uu_pidwait", path = "src/uu/pidwait" } [dev-dependencies] pretty_assertions = "1.4.0" diff --git a/src/uu/pgrep/src/process.rs b/src/uu/pgrep/src/process.rs index 67229f4..d0c63c7 100644 --- a/src/uu/pgrep/src/process.rs +++ b/src/uu/pgrep/src/process.rs @@ -97,7 +97,7 @@ impl TryFrom for Teletype { } /// State or process -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum RunState { ///`R`, running Running, diff --git a/src/uu/pidwait/Cargo.toml b/src/uu/pidwait/Cargo.toml new file mode 100644 index 0000000..14ad159 --- /dev/null +++ b/src/uu/pidwait/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "uu_pidwait" +version = "0.0.1" +edition = "2021" +authors = ["uutils developers"] +license = "MIT" +description = "pidwait ~ (uutils) Wait for processes based on name" + +homepage = "https://github.com/uutils/procps" +repository = "https://github.com/uutils/procps/tree/main/src/uu/pidwait" +keywords = ["acl", "uutils", "cross-platform", "cli", "utility"] +categories = ["command-line-utilities"] + + +[dependencies] +uucore = { workspace = true } +clap = { workspace = true } +polling = { workspace = true } +regex = { workspace = true } +uu_pgrep = { path = "../pgrep" } + +[lib] +path = "src/pidwait.rs" + +[[bin]] +name = "pidwait" +path = "src/main.rs" diff --git a/src/uu/pidwait/pidwait.md b/src/uu/pidwait/pidwait.md new file mode 100644 index 0000000..fb60ef5 --- /dev/null +++ b/src/uu/pidwait/pidwait.md @@ -0,0 +1,7 @@ +# pidwait + +``` +pidwait [options] pattern +``` + +Wait for processes based on name. diff --git a/src/uu/pidwait/src/main.rs b/src/uu/pidwait/src/main.rs new file mode 100644 index 0000000..5a989ee --- /dev/null +++ b/src/uu/pidwait/src/main.rs @@ -0,0 +1 @@ +uucore::bin!(uu_pidwait); diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs new file mode 100644 index 0000000..21eeea7 --- /dev/null +++ b/src/uu/pidwait/src/pidwait.rs @@ -0,0 +1,133 @@ +// 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, crate_version, ArgMatches, Command}; +use regex::Regex; +use std::{collections::HashSet, env, sync::OnceLock}; +use uu_pgrep::process::{walk_process, ProcessInformation, RunState, Teletype}; +use uucore::{ + error::{UResult, USimpleError}, + format_usage, help_about, help_usage, +}; + +const ABOUT: &str = help_about!("pidwait.md"); +const USAGE: &str = help_usage!("pidwait.md"); + +static REGEX: OnceLock = OnceLock::new(); + +#[derive(Debug)] +struct Settings { + echo: bool, + count: bool, + full: bool, + ignore_case: bool, + newest: bool, + oldest: bool, + older: usize, + terminal: HashSet, + exact: bool, + runstates: HashSet, +} + +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches = uu_app().try_get_matches_from(args)?; + + let settings = Settings { + echo: matches.get_flag("echo"), + count: matches.get_flag("count"), + full: matches.get_flag("full"), + ignore_case: matches.get_flag("ignore-case"), + newest: matches.get_flag("newest"), + oldest: matches.get_flag("oldest"), + older: matches + .get_one::("older") + .copied() + .unwrap_or_default(), + terminal: matches + .get_many("terminal") + .unwrap_or_default() + .cloned() + .collect(), + exact: matches.get_flag("exact"), + runstates: matches + .get_many("terminal") + .unwrap_or_default() + .cloned() + .collect(), + }; + + let pattern = try_get_pattern_from(&matches, &settings)?; + REGEX + .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) + .unwrap(); + + collect_proc_infos(settings); + + Ok(()) +} + +fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult { + let pattern = match matches.get_many::("pattern") { + Some(patterns) if patterns.len() > 1 => { + return Err(USimpleError::new( + 2, + "only one pattern can be provided\nTry `pidwait --help' for more information.", + )) + } + Some(mut patterns) => patterns.next().unwrap(), + None => return Ok(String::new()), + }; + + let pattern = if settings.ignore_case { + &pattern.to_lowercase() + } else { + pattern + }; + + let pattern = if settings.exact { + &format!("^{}$", pattern) + } else { + pattern + }; + + Ok(pattern.to_string()) +} + +fn collect_proc_infos(settings: Settings) -> Vec { + let proc_infos: Vec<_> = walk_process().collect(); + + proc_infos +} + +#[allow(clippy::cognitive_complexity)] +pub fn uu_app() -> Command { + Command::new(env!("CARGO_PKG_NAME")) + .version(crate_version!()) + .about(ABOUT) + .override_usage(format_usage(USAGE)) + .infer_long_args(true) + .args([ + arg!(-e --echo "display PIDs before waiting"), + arg!(-c --count "count of matching processes"), + arg!(-f --full "use full process name to match"), + // arg!(-g --pgroup "match listed process group IDs"), + // arg!(-G --group "match real group IDs"), + arg!(-i --"ignore-case" "match case insensitively"), + arg!(-n --newest "select most recently started"), + arg!(-o --oldest "select least recently started"), + arg!(-O --older "select where older than seconds"), + // arg!(-P --parent "match only child processes of the given parent"), + // arg!(-s --session "match session IDs"), + arg!(-t --terminal "match by controlling terminal"), + // arg!(-u --euid "match by effective IDs"), + // arg!(-U --uid "match by real IDs"), + arg!(-x --exact "match exactly with the command name"), + // arg!(-F --pidfile "read PIDs from file"), + // arg!(-L --logpidfile "fail if PID file is not locked"), + arg!(-r --runstates "match runstates [D,S,Z,...]"), + // arg!(-A --"ignore-ancestors" "exclude our ancestors from results"), + ]) +} From 1e7287c91a92012296e2398e49f1bc7f27151198 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:40:39 +0800 Subject: [PATCH 14/38] pidwait: Add basic test for `pidwait` --- tests/by-util/test_pidwait.rs | 11 +++++++++++ tests/tests.rs | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 tests/by-util/test_pidwait.rs diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs new file mode 100644 index 0000000..85ca6f4 --- /dev/null +++ b/tests/by-util/test_pidwait.rs @@ -0,0 +1,11 @@ +// 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 crate::common::util::TestScenario; + +#[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 d1cb34e..dc69d60 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -40,3 +40,7 @@ mod test_pidof; #[cfg(feature = "ps")] #[path = "by-util/test_ps.rs"] mod test_ps; + +#[cfg(feature = "pidwait")] +#[path = "by-util/test_pidwait.rs"] +mod test_pidwait; From 24ab85238b035b59da08f5f66a34872ff0790ead Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:46:59 +0800 Subject: [PATCH 15/38] pidwait: Fix collecting for `runstates` --- src/uu/pidwait/src/pidwait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 21eeea7..8b3eaf5 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -53,7 +53,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .collect(), exact: matches.get_flag("exact"), runstates: matches - .get_many("terminal") + .get_many("runstates") .unwrap_or_default() .cloned() .collect(), From b4e96dd8b16febc677c681bc50e50fe8d41a4eb5 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:48:59 +0800 Subject: [PATCH 16/38] pidwait: Implemented flag `-c` --- src/uu/pidwait/src/pidwait.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 8b3eaf5..baccff8 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -64,7 +64,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) .unwrap(); - collect_proc_infos(settings); + let proc_infos = collect_proc_infos(&settings); + + if settings.count { + println!("{}", proc_infos.len()) + } Ok(()) } @@ -96,7 +100,7 @@ fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult Vec { +fn collect_proc_infos(settings: &Settings) -> Vec { let proc_infos: Vec<_> = walk_process().collect(); proc_infos From 5cba2aa50373931aa32f02d2da4e738d82c12d02 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 7 Aug 2024 23:56:46 +0800 Subject: [PATCH 17/38] pidwait: Implemented flag `-e` --- src/uu/pidwait/src/pidwait.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index baccff8..ab2a8fa 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -64,12 +64,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) .unwrap(); - let proc_infos = collect_proc_infos(&settings); + let mut proc_infos = collect_proc_infos(&settings); + // Process outputting if settings.count { println!("{}", proc_infos.len()) } + if settings.echo { + for ele in proc_infos.iter_mut() { + println!("waiting for {} (pid {})", ele.status()["Name"], ele.pid) + } + } + Ok(()) } From 8b4c0b0564fbdb8283088a9a5364b0aa113f3a9a Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 00:16:18 +0800 Subject: [PATCH 18/38] pidwait: Handle empty input --- src/uu/pidwait/src/pidwait.rs | 40 +++++++++++++++++++++-------------- tests/by-util/test_pidwait.rs | 9 ++++++++ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index ab2a8fa..fdc65fe 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -25,10 +25,10 @@ struct Settings { ignore_case: bool, newest: bool, oldest: bool, - older: usize, - terminal: HashSet, + older: Option, + terminal: Option>, exact: bool, - runstates: HashSet, + runstates: Option, } #[uucore::main] @@ -42,23 +42,26 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { ignore_case: matches.get_flag("ignore-case"), newest: matches.get_flag("newest"), oldest: matches.get_flag("oldest"), - older: matches - .get_one::("older") - .copied() - .unwrap_or_default(), + older: matches.get_one::("older").copied(), terminal: matches - .get_many("terminal") - .unwrap_or_default() - .cloned() - .collect(), + .get_many::("terminal") + .map(|it| it.cloned().collect()), exact: matches.get_flag("exact"), - runstates: matches - .get_many("runstates") - .unwrap_or_default() - .cloned() - .collect(), + runstates: matches.get_one::("runstates").cloned(), }; + if !settings.newest + && !settings.oldest + && settings.runstates.is_none() + && settings.older.is_none() + && settings.terminal.is_none() + { + return Err(USimpleError::new( + 2, + "no matching criteria specified\nTry `pidwait --help' for more information.", + )); + } + let pattern = try_get_pattern_from(&matches, &settings)?; REGEX .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) @@ -109,6 +112,11 @@ fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult Vec { let proc_infos: Vec<_> = walk_process().collect(); + if settings.oldest || settings.newest { + if settings.oldest { + } else if settings.newest { + } + } proc_infos } diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 85ca6f4..f099971 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -9,3 +9,12 @@ use crate::common::util::TestScenario; fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails().code_is(1); } + +#[test] +fn test_no_args() { + new_ucmd!() + .fails() + .code_is(2) + .no_stdout() + .stderr_contains("no matching criteria specified"); +} From 266e05a213bce68b03d2b0760e388a4991e7af22 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 00:32:10 +0800 Subject: [PATCH 19/38] pidwait: Implemented pattern initialize --- src/uu/pidwait/src/pidwait.rs | 33 +++++++++++++++++++++++---------- tests/by-util/test_pidwait.rs | 20 ++++++++++++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index fdc65fe..3397b74 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use clap::{arg, crate_version, ArgMatches, Command}; +use clap::{arg, crate_version, Arg, ArgAction, ArgMatches, Command}; use regex::Regex; use std::{collections::HashSet, env, sync::OnceLock}; use uu_pgrep::process::{walk_process, ProcessInformation, RunState, Teletype}; @@ -50,11 +50,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { runstates: matches.get_one::("runstates").cloned(), }; - if !settings.newest + let pattern = pattern_initialize(&matches, &settings)?; + REGEX + .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) + .unwrap(); + + if (!settings.newest && !settings.oldest && settings.runstates.is_none() && settings.older.is_none() - && settings.terminal.is_none() + && settings.terminal.is_none()) + && pattern.is_empty() { return Err(USimpleError::new( 2, @@ -62,14 +68,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { )); } - let pattern = try_get_pattern_from(&matches, &settings)?; - REGEX - .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) - .unwrap(); - let mut proc_infos = collect_proc_infos(&settings); - // Process outputting + // Process outputs if settings.count { println!("{}", proc_infos.len()) } @@ -83,7 +84,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult { +fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult { let pattern = match matches.get_many::("pattern") { Some(patterns) if patterns.len() > 1 => { return Err(USimpleError::new( @@ -107,6 +108,12 @@ fn try_get_pattern_from(matches: &ArgMatches, settings: &Settings) -> UResult Command { arg!(-r --runstates "match runstates [D,S,Z,...]"), // arg!(-A --"ignore-ancestors" "exclude our ancestors from results"), ]) + .arg( + Arg::new("pattern") + .help("Name of the program to find the PID of") + .action(ArgAction::Append) + .index(1), + ) } diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index f099971..13b48ba 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -10,6 +10,15 @@ fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails().code_is(1); } +#[test] +fn test_non_matching_pattern() { + new_ucmd!() + .arg("THIS_PATTERN_DOES_NOT_MATCH") + .fails() + .code_is(1) + .stderr_contains("pidwait: pattern that searches for process name longer than 15 characters will result in zero matches"); +} + #[test] fn test_no_args() { new_ucmd!() @@ -18,3 +27,14 @@ fn test_no_args() { .no_stdout() .stderr_contains("no matching criteria specified"); } + +#[test] +fn test_too_many_patterns() { + new_ucmd!() + .arg("sh") + .arg("sh") + .fails() + .code_is(2) + .no_stdout() + .stderr_contains("only one pattern can be provided"); +} From ba08895d86d585b150980181bc8993594fa31ae8 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 02:20:03 +0800 Subject: [PATCH 20/38] pidwait: Handle empty collection for process From manpage: > 1 No processes matched or none of them could be signalled. --- src/uu/pidwait/src/pidwait.rs | 5 +++++ tests/by-util/test_pidwait.rs | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 3397b74..e548920 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -70,6 +70,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let mut proc_infos = collect_proc_infos(&settings); + // For empty result + if proc_infos.is_empty() { + uucore::error::set_exit_code(1); + } + // Process outputs if settings.count { println!("{}", proc_infos.len()) diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 13b48ba..8629cd6 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -17,6 +17,8 @@ fn test_non_matching_pattern() { .fails() .code_is(1) .stderr_contains("pidwait: pattern that searches for process name longer than 15 characters will result in zero matches"); + + new_ucmd!().arg("DOES_NOT_MATCH").fails().code_is(1); } #[test] From e5d2e8ac4f7c8071daec63a0c8867435201fbd80 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 02:45:43 +0800 Subject: [PATCH 21/38] pidwait: Implemented flag `-o`, `-n`, `-O` --- src/uu/pidwait/src/pidwait.rs | 49 ++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index e548920..514eb53 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -123,13 +123,54 @@ fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult Vec { - let proc_infos: Vec<_> = walk_process().collect(); - if settings.oldest || settings.newest { - if settings.oldest { - } else if settings.newest { + // Process `-O` + let mut proc_infos: Vec<_> = { + let mut proc_infos = Vec::new(); + let older = settings.older.unwrap_or_default(); + for mut proc_info in walk_process() { + if proc_info.start_time().unwrap() >= older { + proc_infos.push(proc_info) + } } + proc_infos + }; + + if proc_infos.is_empty() { + return proc_infos; } + // Sorting oldest and newest + let proc_infos = if settings.oldest || settings.newest { + proc_infos.sort_by(|a, b| { + b.clone() + .start_time() + .unwrap() + .cmp(&a.clone().start_time().unwrap()) + }); + + let start_time = if settings.newest { + proc_infos.first().cloned().unwrap().start_time().unwrap() + } else { + proc_infos.last().cloned().unwrap().start_time().unwrap() + }; + + // There might be some process start at same time, so need to be filtered. + let mut filtered = proc_infos + .iter() + .filter(|it| (*it).clone().start_time().unwrap() == start_time) + .collect::>(); + + if settings.newest { + filtered.sort_by(|a, b| b.pid.cmp(&a.pid)) + } else { + filtered.sort_by(|a, b| a.pid.cmp(&b.pid)) + } + + vec![filtered.first().cloned().unwrap().clone()] + } else { + proc_infos + }; + proc_infos } From 5ccf40090866b3d6888ec77ac8e7f879f4376460 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 02:58:06 +0800 Subject: [PATCH 22/38] pidwait: Fix checking the length of pattern --- src/uu/pidwait/src/pidwait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 514eb53..8c741f2 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -113,7 +113,7 @@ fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult= 15 { const MSG_0: &str= "pidwait: pattern that searches for process name longer than 15 characters will result in zero matches"; const MSG_1: &str = "Try `pidwait -f' option to match against the complete command line."; return Err(USimpleError::new(1, format!("{MSG_0}\n{MSG_1}"))); From 17c8703fd74bd024925436a19c1d1617b6eba7a1 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Thu, 8 Aug 2024 03:06:02 +0800 Subject: [PATCH 23/38] pidwait: Implemented filter based regex --- src/uu/pidwait/src/pidwait.rs | 46 +++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 8c741f2..46ac1b2 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -123,16 +123,46 @@ fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult Vec { - // Process `-O` - let mut proc_infos: Vec<_> = { - let mut proc_infos = Vec::new(); - let older = settings.older.unwrap_or_default(); - for mut proc_info in walk_process() { - if proc_info.start_time().unwrap() >= older { - proc_infos.push(proc_info) + // Process pattern + let proc_infos = { + let mut temp = Vec::new(); + for mut it in walk_process() { + let matched = { + let binding = it.status(); + let name = binding.get("Name").unwrap(); + let name = if settings.ignore_case { + name.to_lowercase() + } else { + name.into() + }; + + let want = if settings.exact { + &name + } else if settings.full { + &it.cmdline + } else { + &it.proc_stat()[..15] + }; + + REGEX.get().unwrap().is_match(want) + }; + if matched { + temp.push(it) } } - proc_infos + temp + }; + + // Process `-O` + let mut proc_infos = { + let mut temp: Vec = Vec::new(); + let older = settings.older.unwrap_or_default(); + for mut proc_info in proc_infos { + if proc_info.start_time().unwrap() >= older { + temp.push(proc_info) + } + } + temp }; if proc_infos.is_empty() { From 748cfaca54aea34a75463c3254fc2a5d78501102 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Sat, 10 Aug 2024 03:25:58 +0800 Subject: [PATCH 24/38] pidwait: Implemented waiting on Linux. --- Cargo.lock | 350 +++++++++++++++++++++++++++++++++- Cargo.toml | 5 +- src/uu/pidwait/Cargo.toml | 4 +- src/uu/pidwait/src/pidwait.rs | 5 + src/uu/pidwait/src/wait.rs | 37 ++++ tests/by-util/test_pidwait.rs | 24 +++ 6 files changed, 421 insertions(+), 4 deletions(-) create mode 100644 src/uu/pidwait/src/wait.rs diff --git a/Cargo.lock b/Cargo.lock index b463c54..3b70917 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -74,12 +89,154 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 0.38.32", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 0.38.32", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-signal" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.32", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -92,6 +249,19 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -324,12 +494,58 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "getrandom" version = "0.2.14" @@ -341,6 +557,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "glob" version = "0.3.1" @@ -382,6 +604,28 @@ dependencies = [ "cc", ] +[[package]] +name = "inotify" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" +dependencies = [ + "bitflags 1.3.2", + "futures-core", + "inotify-sys", + "libc", + "tokio", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "io-lifetimes" version = "1.0.11" @@ -465,6 +709,27 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "nix" version = "0.28.0" @@ -528,6 +793,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -543,6 +817,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "phf" version = "0.11.2" @@ -587,6 +867,17 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "piper" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "polling" version = "3.7.2" @@ -793,6 +1084,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustix" version = "0.37.27" @@ -861,18 +1158,53 @@ dependencies = [ "syn", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smawk" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "smol" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", +] + [[package]] name = "socket2" version = "0.5.6" @@ -1023,6 +1355,20 @@ dependencies = [ "time-core", ] +[[package]] +name = "tokio" +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +dependencies = [ + "backtrace", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + [[package]] name = "tracing" version = "0.1.40" @@ -1097,8 +1443,10 @@ name = "uu_pidwait" version = "0.0.1" dependencies = [ "clap", - "polling", + "inotify", + "nix 0.29.0", "regex", + "smol", "uu_pgrep", "uucore", ] diff --git a/Cargo.toml b/Cargo.toml index 8a4f5bc..1ec5964 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,8 +57,9 @@ bytesize = "1.3.0" chrono = { version = "0.4.38", default-features = false, features = ["clock"] } walkdir = "2.5.0" prettytable-rs = "0.10.0" -nix = { version = "0.29", default-features = false } -polling = "3.7.2" +nix = { version = "0.29", default-features = false, features = ["process"] } +smol = "2.0.0" +inotify = "0.10.2" [dependencies] clap = { workspace = true } diff --git a/src/uu/pidwait/Cargo.toml b/src/uu/pidwait/Cargo.toml index 14ad159..b7fc7f5 100644 --- a/src/uu/pidwait/Cargo.toml +++ b/src/uu/pidwait/Cargo.toml @@ -13,9 +13,11 @@ categories = ["command-line-utilities"] [dependencies] +nix = { workspace = true } uucore = { workspace = true } clap = { workspace = true } -polling = { workspace = true } +smol = { workspace = true } +inotify = { workspace = true } regex = { workspace = true } uu_pgrep = { path = "../pgrep" } diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 46ac1b2..d96b62e 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -11,6 +11,9 @@ use uucore::{ error::{UResult, USimpleError}, format_usage, help_about, help_usage, }; +use wait::waiting; + +mod wait; const ABOUT: &str = help_about!("pidwait.md"); const USAGE: &str = help_usage!("pidwait.md"); @@ -86,6 +89,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } + waiting(&proc_infos); + Ok(()) } diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs new file mode 100644 index 0000000..4391a51 --- /dev/null +++ b/src/uu/pidwait/src/wait.rs @@ -0,0 +1,37 @@ +// 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 uu_pgrep::process::ProcessInformation; +use uu_pgrep::process::RunState; + +// Dirty, but it works. +// TODO: Use better implementation instead +#[cfg(target_os = "linux")] +pub(crate) fn waiting(procs: &[ProcessInformation]) { + use std::{path::PathBuf, str::FromStr}; + + let mut list = procs.to_vec(); + + loop { + for proc in procs.iter().cloned() { + let proc_path = PathBuf::from_str(&format!("/proc/{}", proc.pid)).unwrap(); + if !proc_path.exists() { + list.retain(|it| it.pid != proc.pid); + } + + if let Ok(mut proc) = ProcessInformation::try_new(proc_path) { + if proc.run_state().unwrap() == RunState::Stopped { + list.retain(|it| it.pid != proc.pid); + } + } else { + list.retain(|it| it.pid != proc.pid); + }; + } + + if list.is_empty() { + return; + } + } +} diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 8629cd6..d667059 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -4,6 +4,8 @@ // file that was distributed with this source code. use crate::common::util::TestScenario; +use std::process::Command; +use std::{thread, time::Duration}; #[test] fn test_invalid_arg() { @@ -40,3 +42,25 @@ fn test_too_many_patterns() { .no_stdout() .stderr_contains("only one pattern can be provided"); } + +// #[test] +// #[cfg(target_os = "linux")] +// fn test_waiting() { +// for _ in 0..3 { +// let _ = Command::new("sleep").arg("3").spawn().unwrap(); +// } + +// thread::sleep(Duration::from_secs(1)); + +// let binding = new_ucmd!().arg("sleep").arg("-c").succeeds(); +// let output = binding.stdout_str(); + +// let output = dbg!(output); + +// let count = output.lines().collect::>()[0] +// .trim() +// .parse::() +// .unwrap(); + +// assert_eq!(count, 3) +// } From 693be14bace09cb37ce348e2a0c214150a7efb3d Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Mon, 12 Aug 2024 18:08:07 +0800 Subject: [PATCH 25/38] pidwait: Implemented `waiting` for Linux --- src/uu/pidwait/src/wait.rs | 32 ++++++++++++++++++-------------- tests/by-util/test_pidwait.rs | 23 +---------------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs index 4391a51..5c0157b 100644 --- a/src/uu/pidwait/src/wait.rs +++ b/src/uu/pidwait/src/wait.rs @@ -3,6 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +use std::{path::PathBuf, str::FromStr}; use uu_pgrep::process::ProcessInformation; use uu_pgrep::process::RunState; @@ -10,24 +11,14 @@ use uu_pgrep::process::RunState; // TODO: Use better implementation instead #[cfg(target_os = "linux")] pub(crate) fn waiting(procs: &[ProcessInformation]) { - use std::{path::PathBuf, str::FromStr}; - let mut list = procs.to_vec(); loop { - for proc in procs.iter().cloned() { - let proc_path = PathBuf::from_str(&format!("/proc/{}", proc.pid)).unwrap(); - if !proc_path.exists() { - list.retain(|it| it.pid != proc.pid); + for proc in &list.clone() { + // Check is running + if !is_running(proc.pid) { + list.retain(|it| it.pid != proc.pid) } - - if let Ok(mut proc) = ProcessInformation::try_new(proc_path) { - if proc.run_state().unwrap() == RunState::Stopped { - list.retain(|it| it.pid != proc.pid); - } - } else { - list.retain(|it| it.pid != proc.pid); - }; } if list.is_empty() { @@ -35,3 +26,16 @@ pub(crate) fn waiting(procs: &[ProcessInformation]) { } } } +#[cfg(target_os = "linux")] +fn is_running(pid: usize) -> bool { + let proc = PathBuf::from_str(&format!("/proc/{}", pid)).unwrap(); + + if !proc.exists() { + return false; + } + + match ProcessInformation::try_new(proc) { + Ok(mut proc) => proc.run_state().unwrap() != RunState::Stopped, + Err(_) => false, + } +} diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index d667059..5c6e95e 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -5,6 +5,7 @@ use crate::common::util::TestScenario; use std::process::Command; +use std::thread::spawn; use std::{thread, time::Duration}; #[test] @@ -42,25 +43,3 @@ fn test_too_many_patterns() { .no_stdout() .stderr_contains("only one pattern can be provided"); } - -// #[test] -// #[cfg(target_os = "linux")] -// fn test_waiting() { -// for _ in 0..3 { -// let _ = Command::new("sleep").arg("3").spawn().unwrap(); -// } - -// thread::sleep(Duration::from_secs(1)); - -// let binding = new_ucmd!().arg("sleep").arg("-c").succeeds(); -// let output = binding.stdout_str(); - -// let output = dbg!(output); - -// let count = output.lines().collect::>()[0] -// .trim() -// .parse::() -// .unwrap(); - -// assert_eq!(count, 3) -// } From ce9e9756157b091ea1848dfe0a5aa463d5140f80 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Mon, 12 Aug 2024 18:10:05 +0800 Subject: [PATCH 26/38] misc: Clean code. --- src/uu/pidwait/src/wait.rs | 10 ++++++++-- tests/by-util/test_pidwait.rs | 3 --- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs index 5c0157b..de55c69 100644 --- a/src/uu/pidwait/src/wait.rs +++ b/src/uu/pidwait/src/wait.rs @@ -3,9 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use std::{path::PathBuf, str::FromStr}; use uu_pgrep::process::ProcessInformation; -use uu_pgrep::process::RunState; // Dirty, but it works. // TODO: Use better implementation instead @@ -28,6 +26,10 @@ pub(crate) fn waiting(procs: &[ProcessInformation]) { } #[cfg(target_os = "linux")] fn is_running(pid: usize) -> bool { + use std::{path::PathBuf, str::FromStr}; + use uu_pgrep::process::ProcessInformation; + use uu_pgrep::process::RunState; + let proc = PathBuf::from_str(&format!("/proc/{}", pid)).unwrap(); if !proc.exists() { @@ -39,3 +41,7 @@ fn is_running(pid: usize) -> bool { Err(_) => false, } } + +// Just for passing compile on other system. +#[cfg(not(target_os = "linux"))] +pub(crate) fn waiting(procs: &[ProcessInformation]) {} diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 5c6e95e..8629cd6 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -4,9 +4,6 @@ // file that was distributed with this source code. use crate::common::util::TestScenario; -use std::process::Command; -use std::thread::spawn; -use std::{thread, time::Duration}; #[test] fn test_invalid_arg() { From b530c04957a407a22fd6265adc56dfcc1831d383 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Mon, 12 Aug 2024 18:20:35 +0800 Subject: [PATCH 27/38] misc: Drop unused dependencies --- Cargo.lock | 404 +------------------------------------- Cargo.toml | 2 - src/uu/pidwait/Cargo.toml | 2 - 3 files changed, 2 insertions(+), 406 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b70917..b0a06d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aho-corasick" version = "1.1.3" @@ -89,154 +74,12 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-io" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 0.38.32", - "slab", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-process" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.38.32", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-signal" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.32", - "signal-hook-registry", - "slab", - "windows-sys 0.52.0", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -249,19 +92,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -363,15 +193,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -494,58 +315,12 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" -dependencies = [ - "event-listener", - "pin-project-lite", -] - [[package]] name = "fastrand" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-lite" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "getrandom" version = "0.2.14" @@ -557,12 +332,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - [[package]] name = "glob" version = "0.3.1" @@ -575,12 +344,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - [[package]] name = "iana-time-zone" version = "0.1.60" @@ -604,35 +367,13 @@ dependencies = [ "cc", ] -[[package]] -name = "inotify" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" -dependencies = [ - "bitflags 1.3.2", - "futures-core", - "inotify-sys", - "libc", - "tokio", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - [[package]] name = "io-lifetimes" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", "windows-sys 0.48.0", ] @@ -643,7 +384,7 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", "windows-sys 0.52.0", ] @@ -709,27 +450,6 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "wasi", - "windows-sys 0.52.0", -] - [[package]] name = "nix" version = "0.28.0" @@ -793,15 +513,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.19.0" @@ -817,12 +528,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "parking" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" - [[package]] name = "phf" version = "0.11.2" @@ -861,38 +566,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "piper" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "polling" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix 0.38.32", - "tracing", - "windows-sys 0.52.0", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1084,12 +757,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustix" version = "0.37.27" @@ -1158,53 +825,18 @@ dependencies = [ "syn", ] -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - [[package]] name = "smawk" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" -[[package]] -name = "smol" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad" -dependencies = [ - "async-channel", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-net", - "async-process", - "blocking", - "futures-lite", -] - [[package]] name = "socket2" version = "0.5.6" @@ -1355,36 +987,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tokio" -version = "1.39.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" -dependencies = [ - "backtrace", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -1443,10 +1045,8 @@ name = "uu_pidwait" version = "0.0.1" dependencies = [ "clap", - "inotify", "nix 0.29.0", "regex", - "smol", "uu_pgrep", "uucore", ] diff --git a/Cargo.toml b/Cargo.toml index 1ec5964..051b7c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,8 +58,6 @@ chrono = { version = "0.4.38", default-features = false, features = ["clock"] } walkdir = "2.5.0" prettytable-rs = "0.10.0" nix = { version = "0.29", default-features = false, features = ["process"] } -smol = "2.0.0" -inotify = "0.10.2" [dependencies] clap = { workspace = true } diff --git a/src/uu/pidwait/Cargo.toml b/src/uu/pidwait/Cargo.toml index b7fc7f5..db8f040 100644 --- a/src/uu/pidwait/Cargo.toml +++ b/src/uu/pidwait/Cargo.toml @@ -16,8 +16,6 @@ categories = ["command-line-utilities"] nix = { workspace = true } uucore = { workspace = true } clap = { workspace = true } -smol = { workspace = true } -inotify = { workspace = true } regex = { workspace = true } uu_pgrep = { path = "../pgrep" } From 1e5cbffab1cda72c6c61c177835d7ae2d90d91e0 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Mon, 12 Aug 2024 18:27:17 +0800 Subject: [PATCH 28/38] pidwait: Reserve a placeholder for other platform implementations --- src/uu/pidwait/src/wait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs index de55c69..c2ec58c 100644 --- a/src/uu/pidwait/src/wait.rs +++ b/src/uu/pidwait/src/wait.rs @@ -44,4 +44,4 @@ fn is_running(pid: usize) -> bool { // Just for passing compile on other system. #[cfg(not(target_os = "linux"))] -pub(crate) fn waiting(procs: &[ProcessInformation]) {} +pub(crate) fn waiting(_procs: &[ProcessInformation]) {} From 3f167f8d19183cee8186a9b6a47ba7b91b43e0cb Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 17:29:49 +0800 Subject: [PATCH 29/38] pidwait: Add `no_output` for tests. --- tests/by-util/test_pidwait.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/by-util/test_pidwait.rs b/tests/by-util/test_pidwait.rs index 8629cd6..6791eda 100644 --- a/tests/by-util/test_pidwait.rs +++ b/tests/by-util/test_pidwait.rs @@ -18,7 +18,11 @@ fn test_non_matching_pattern() { .code_is(1) .stderr_contains("pidwait: pattern that searches for process name longer than 15 characters will result in zero matches"); - new_ucmd!().arg("DOES_NOT_MATCH").fails().code_is(1); + new_ucmd!() + .arg("DOES_NOT_MATCH") + .fails() + .code_is(1) + .no_output(); } #[test] From 7fed5542d53d30b4b6e7c79af6e552503e5b7c97 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 17:31:18 +0800 Subject: [PATCH 30/38] pidwait: Rename `pattern_initialize` to `initialize_pattern` --- src/uu/pidwait/src/pidwait.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index d96b62e..ab4b098 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -53,7 +53,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { runstates: matches.get_one::("runstates").cloned(), }; - let pattern = pattern_initialize(&matches, &settings)?; + let pattern = initialize_pattern(&matches, &settings)?; REGEX .set(Regex::new(&pattern).map_err(|e| USimpleError::new(2, e.to_string()))?) .unwrap(); @@ -94,7 +94,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } -fn pattern_initialize(matches: &ArgMatches, settings: &Settings) -> UResult { +fn initialize_pattern(matches: &ArgMatches, settings: &Settings) -> UResult { let pattern = match matches.get_many::("pattern") { Some(patterns) if patterns.len() > 1 => { return Err(USimpleError::new( From fd06e44f402dbfb6dd11e459c44b622913f62dbb Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 17:32:48 +0800 Subject: [PATCH 31/38] pidwait: Clean imports for `wait.rs` --- src/uu/pidwait/src/wait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs index c2ec58c..6ac59dc 100644 --- a/src/uu/pidwait/src/wait.rs +++ b/src/uu/pidwait/src/wait.rs @@ -3,6 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +#[cfg(target_os = "linux")] use uu_pgrep::process::ProcessInformation; // Dirty, but it works. @@ -27,7 +28,6 @@ pub(crate) fn waiting(procs: &[ProcessInformation]) { #[cfg(target_os = "linux")] fn is_running(pid: usize) -> bool { use std::{path::PathBuf, str::FromStr}; - use uu_pgrep::process::ProcessInformation; use uu_pgrep::process::RunState; let proc = PathBuf::from_str(&format!("/proc/{}", pid)).unwrap(); From 932bd54b2c174aeb8d4a1bd09b959129a28db4b8 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 17:33:21 +0800 Subject: [PATCH 32/38] pidwait: Rename `wait::waiting` to `wait::wait` --- src/uu/pidwait/src/pidwait.rs | 4 ++-- src/uu/pidwait/src/wait.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index ab4b098..dfdf73c 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -11,7 +11,7 @@ use uucore::{ error::{UResult, USimpleError}, format_usage, help_about, help_usage, }; -use wait::waiting; +use wait::wait; mod wait; @@ -89,7 +89,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } } - waiting(&proc_infos); + wait(&proc_infos); Ok(()) } diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs index 6ac59dc..36d82e6 100644 --- a/src/uu/pidwait/src/wait.rs +++ b/src/uu/pidwait/src/wait.rs @@ -9,7 +9,7 @@ use uu_pgrep::process::ProcessInformation; // Dirty, but it works. // TODO: Use better implementation instead #[cfg(target_os = "linux")] -pub(crate) fn waiting(procs: &[ProcessInformation]) { +pub(crate) fn wait(procs: &[ProcessInformation]) { let mut list = procs.to_vec(); loop { @@ -44,4 +44,4 @@ fn is_running(pid: usize) -> bool { // Just for passing compile on other system. #[cfg(not(target_os = "linux"))] -pub(crate) fn waiting(_procs: &[ProcessInformation]) {} +pub(crate) fn wait(_procs: &[ProcessInformation]) {} From 63fc7ae65bfaf2ff08813c6fcc86969c94ca9da6 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 17:49:34 +0800 Subject: [PATCH 33/38] pidwait: Adds a short `sleep` duration to `wait::wait` --- src/uu/pidwait/src/wait.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs index 36d82e6..9df6d5a 100644 --- a/src/uu/pidwait/src/wait.rs +++ b/src/uu/pidwait/src/wait.rs @@ -3,13 +3,14 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -#[cfg(target_os = "linux")] use uu_pgrep::process::ProcessInformation; // Dirty, but it works. // TODO: Use better implementation instead #[cfg(target_os = "linux")] pub(crate) fn wait(procs: &[ProcessInformation]) { + use std::{thread::sleep, time::Duration}; + let mut list = procs.to_vec(); loop { @@ -23,6 +24,8 @@ pub(crate) fn wait(procs: &[ProcessInformation]) { if list.is_empty() { return; } + + sleep(Duration::from_millis(50)); } } #[cfg(target_os = "linux")] From beb4528acb747ccffea1892e7cd2db1e29fdf6b3 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 18:06:43 +0800 Subject: [PATCH 34/38] pidwait: Implement multiple `--runstates` argument --- src/uu/pidwait/src/pidwait.rs | 6 ++++-- src/uu/pidwait/src/wait.rs | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index dfdf73c..662d101 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -31,7 +31,7 @@ struct Settings { older: Option, terminal: Option>, exact: bool, - runstates: Option, + runstates: Option>, } #[uucore::main] @@ -50,7 +50,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .get_many::("terminal") .map(|it| it.cloned().collect()), exact: matches.get_flag("exact"), - runstates: matches.get_one::("runstates").cloned(), + runstates: matches + .get_many::("runstates") + .map(|it| it.cloned().flat_map(RunState::try_from).collect()), }; let pattern = initialize_pattern(&matches, &settings)?; diff --git a/src/uu/pidwait/src/wait.rs b/src/uu/pidwait/src/wait.rs index 9df6d5a..cee49fd 100644 --- a/src/uu/pidwait/src/wait.rs +++ b/src/uu/pidwait/src/wait.rs @@ -40,7 +40,10 @@ fn is_running(pid: usize) -> bool { } match ProcessInformation::try_new(proc) { - Ok(mut proc) => proc.run_state().unwrap() != RunState::Stopped, + Ok(mut proc) => proc + .run_state() + .map(|it| it != RunState::Stopped) + .unwrap_or(false), Err(_) => false, } } From 0f25a4e1ac9f3c8bac993deffcf864dfd89f66c3 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 18:17:23 +0800 Subject: [PATCH 35/38] pidwait: No longer print `Name` for process when (`-o` || `-n`) && `-e` --- src/uu/pidwait/src/pidwait.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 662d101..4c6f815 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -86,8 +86,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } if settings.echo { - for ele in proc_infos.iter_mut() { - println!("waiting for {} (pid {})", ele.status()["Name"], ele.pid) + if settings.newest || settings.oldest { + for ele in proc_infos.iter_mut() { + println!("waiting for (pid {})", ele.pid) + } + } else { + for ele in proc_infos.iter_mut() { + println!("waiting for {} (pid {})", ele.status()["Name"], ele.pid) + } } } From 18e0dabcaf65aa9ab7d813ed0fc7b512e3ab7c41 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 18:37:16 +0800 Subject: [PATCH 36/38] pidwait: Fix value parsing for `--older` `--terminal` --- src/uu/pidwait/src/pidwait.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 4c6f815..6ba603b 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use clap::{arg, crate_version, Arg, ArgAction, ArgMatches, Command}; +use clap::{arg, crate_version, value_parser, Arg, ArgAction, ArgMatches, Command}; use regex::Regex; use std::{collections::HashSet, env, sync::OnceLock}; use uu_pgrep::process::{walk_process, ProcessInformation, RunState, Teletype}; @@ -46,9 +46,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { newest: matches.get_flag("newest"), oldest: matches.get_flag("oldest"), older: matches.get_one::("older").copied(), - terminal: matches - .get_many::("terminal") - .map(|it| it.cloned().collect()), + terminal: matches.get_many::("terminal").map(|ttys| { + ttys.cloned() + .flat_map(Teletype::try_from) + .collect::>() + }), exact: matches.get_flag("exact"), runstates: matches .get_many::("runstates") @@ -233,7 +235,8 @@ pub fn uu_app() -> Command { arg!(-i --"ignore-case" "match case insensitively"), arg!(-n --newest "select most recently started"), arg!(-o --oldest "select least recently started"), - arg!(-O --older "select where older than seconds"), + arg!(-O --older "select where older than seconds") + .value_parser(value_parser!(u64)), // arg!(-P --parent "match only child processes of the given parent"), // arg!(-s --session "match session IDs"), arg!(-t --terminal "match by controlling terminal"), From b9a561a9c4fac096bb2f31ab023273c3f481a5b0 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 18:55:00 +0800 Subject: [PATCH 37/38] pidwait: Implemented filtering by `--terminal` --- src/uu/pidwait/src/pidwait.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 6ba603b..091f041 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -169,7 +169,7 @@ fn collect_proc_infos(settings: &Settings) -> Vec { }; // Process `-O` - let mut proc_infos = { + let proc_infos = { let mut temp: Vec = Vec::new(); let older = settings.older.unwrap_or_default(); for mut proc_info in proc_infos { @@ -180,6 +180,17 @@ fn collect_proc_infos(settings: &Settings) -> Vec { temp }; + let mut proc_infos = { + if let Some(terminals) = &settings.terminal { + proc_infos + .into_iter() + .filter(|it| terminals.contains(&it.tty())) + .collect() + } else { + proc_infos + } + }; + if proc_infos.is_empty() { return proc_infos; } From f41ca7910c6b9300baa61e0d690960970842df60 Mon Sep 17 00:00:00 2001 From: Krysztal Huang Date: Wed, 14 Aug 2024 21:49:20 +0800 Subject: [PATCH 38/38] pidwait: Use reference instead of mutable iterator. --- src/uu/pidwait/src/pidwait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/pidwait/src/pidwait.rs b/src/uu/pidwait/src/pidwait.rs index 091f041..bad2a51 100644 --- a/src/uu/pidwait/src/pidwait.rs +++ b/src/uu/pidwait/src/pidwait.rs @@ -89,7 +89,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if settings.echo { if settings.newest || settings.oldest { - for ele in proc_infos.iter_mut() { + for ele in &proc_infos { println!("waiting for (pid {})", ele.pid) } } else {