pidwait: Add command pidwait

And also introduce dependency `polling` for polling `waitpid` syscall
This commit is contained in:
Krysztal Huang
2024-08-07 23:33:37 +08:00
parent 066c71d5bd
commit 024bdf1bdc
7 changed files with 238 additions and 3 deletions
Generated
+66 -2
View File
@@ -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"
+3
View File
@@ -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"
+1 -1
View File
@@ -97,7 +97,7 @@ impl TryFrom<PathBuf> for Teletype {
}
/// State or process
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum RunState {
///`R`, running
Running,
+27
View File
@@ -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"
+7
View File
@@ -0,0 +1,7 @@
# pidwait
```
pidwait [options] pattern
```
Wait for processes based on name.
+1
View File
@@ -0,0 +1 @@
uucore::bin!(uu_pidwait);
+133
View File
@@ -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<Regex> = OnceLock::new();
#[derive(Debug)]
struct Settings {
echo: bool,
count: bool,
full: bool,
ignore_case: bool,
newest: bool,
oldest: bool,
older: usize,
terminal: HashSet<Teletype>,
exact: bool,
runstates: HashSet<RunState>,
}
#[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::<usize>("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<String> {
let pattern = match matches.get_many::<String>("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<ProcessInformation> {
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 <PGID> "match listed process group IDs"),
// arg!(-G --group <GID> "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 <seconds> "select where older than seconds"),
// arg!(-P --parent <PPID> "match only child processes of the given parent"),
// arg!(-s --session <SID> "match session IDs"),
arg!(-t --terminal <tty> "match by controlling terminal"),
// arg!(-u --euid <ID> "match by effective IDs"),
// arg!(-U --uid <ID> "match by real IDs"),
arg!(-x --exact "match exactly with the command name"),
// arg!(-F --pidfile <file> "read PIDs from file"),
// arg!(-L --logpidfile "fail if PID file is not locked"),
arg!(-r --runstates <state> "match runstates [D,S,Z,...]"),
// arg!(-A --"ignore-ancestors" "exclude our ancestors from results"),
])
}