Skip to content

Commit ea1e43f

Browse files
skill: refactor util with pgrep's process and add tests
1 parent 27ea243 commit ea1e43f

File tree

7 files changed

+175
-161
lines changed

7 files changed

+175
-161
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/pgrep/src/process.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ pub enum Teletype {
2626
impl Display for Teletype {
2727
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2828
match self {
29-
Self::Tty(id) => write!(f, "/dev/pts/{}", id),
30-
Self::TtyS(id) => write!(f, "/dev/tty{}", id),
31-
Self::Pts(id) => write!(f, "/dev/ttyS{}", id),
29+
Self::Tty(id) => write!(f, "/dev/tty{}", id),
30+
Self::TtyS(id) => write!(f, "/dev/ttyS{}", id),
31+
Self::Pts(id) => write!(f, "/dev/pts/{}", id),
3232
Self::Unknown => write!(f, "?"),
3333
}
3434
}

src/uu/skill/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ categories = ["command-line-utilities"]
1515
uucore = { workspace = true , features = ["signals"]}
1616
clap = { workspace = true }
1717
nix = { workspace = true }
18+
uu_pgrep = { path = "../pgrep" }
1819

1920
[lib]
2021
path = "src/skill.rs"

src/uu/skill/src/command.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::collections::HashSet;
88
use uucore::signals::{ALL_SIGNALS, DEFAULT_SIGNAL};
99

1010
#[derive(Debug, Clone)]
11-
pub struct Cli {
11+
pub struct Settings {
1212
// Arguments
1313
pub signal: String,
1414
pub expression: Expr,
@@ -31,7 +31,7 @@ pub enum Expr {
3131
Raw(Vec<String>),
3232
}
3333

34-
impl Cli {
34+
impl Settings {
3535
pub fn new(args: ArgMatches) -> Self {
3636
let mut signal = args.get_one::<String>("signal").unwrap().to_string();
3737
if signal.starts_with("-") {
@@ -69,6 +69,7 @@ impl Cli {
6969
}
7070

7171
// Pre-parses the command line arguments and returns a vector of OsString
72+
7273
// Mainly used to parse the signal to make sure it is valid
7374
// and insert the default signal if it's not present
7475
pub fn parse_command(args: &mut impl uucore::Args) -> Vec<String> {

src/uu/skill/src/skill.rs

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
mod command;
77
mod util;
88

9-
use crate::command::{parse_command, Cli, Expr};
9+
use crate::command::{parse_command, Expr, Settings};
1010
use clap::{crate_version, Arg, ArgAction, Command};
1111
use nix::{
1212
sys::signal::{self, Signal},
1313
unistd::Pid,
1414
};
15+
use uu_pgrep::process::ProcessInformation;
1516
use uucore::signals::ALL_SIGNALS;
1617
use uucore::{error::UResult, format_usage, help_about, help_usage};
1718

@@ -23,7 +24,7 @@ const SIGNALS_PER_ROW: usize = 7; // Be consistent with procps-ng
2324
pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
2425
let new = parse_command(&mut args);
2526
let matches = uu_app().try_get_matches_from(new)?;
26-
let mut cli = Cli::new(matches);
27+
let mut cli = Settings::new(matches);
2728

2829
// If list or table is specified, print the list of signals and return
2930
if cli.list || cli.table {
@@ -40,43 +41,47 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
4041
// parse the expression if not specify its type
4142
parse_expression(&mut cli);
4243

43-
let matching_pids = find_matching_pids(&cli.expression);
44+
let matching_processes = find_matching_processes(&cli.expression);
4445

45-
if matching_pids.is_empty() {
46+
if matching_processes.is_empty() {
4647
eprintln!("No matching processes found");
4748
return Ok(());
4849
}
4950

5051
if cli.verbose || cli.no_action {
51-
for pid in &matching_pids {
52-
println!("Would send signal {} to process {}", &cli.signal, pid);
52+
for process in &matching_processes {
53+
println!(
54+
"Would send signal {} to process {} with cmd {}",
55+
&cli.signal, process.pid, process.cmdline
56+
);
5357
}
5458
if cli.no_action {
5559
return Ok(());
5660
}
5761
}
5862

5963
if cli.interactive {
60-
for pid in matching_pids {
61-
let cmd =
62-
util::get_process_command_name(pid).unwrap_or_else(|| "<unknown>".to_string());
63-
let owner = util::get_process_owner(pid).unwrap_or_else(|| "<unknown>".to_string());
64-
let tty = util::get_process_terminal(pid).unwrap_or_else(|| "<unknown>".to_string());
65-
if confirm_action(&tty, &owner, pid, &cmd) {
66-
if let Err(e) = send_signal(pid, signal) {
64+
for mut process in matching_processes {
65+
let cmd = process.cmdline.clone();
66+
let owner =
67+
util::get_process_owner(&mut process).unwrap_or_else(|| "<unknown>".to_string());
68+
let tty =
69+
util::get_process_terminal(&process).unwrap_or_else(|| "<unknown>".to_string());
70+
if confirm_action(&tty, &owner, process.pid as i32, &cmd) {
71+
if let Err(e) = send_signal(process.pid as i32, signal) {
6772
if cli.warnings {
68-
eprintln!("Failed to send signal to process {}: {}", pid, e);
73+
eprintln!("Failed to send signal to process {}: {}", process.pid, e);
6974
}
7075
}
7176
} else {
72-
println!("Skipping process {}", pid);
77+
println!("Skipping process {}", process.pid);
7378
}
7479
}
7580
} else {
76-
for pid in matching_pids {
77-
if let Err(e) = send_signal(pid, signal) {
81+
for process in matching_processes {
82+
if let Err(e) = send_signal(process.pid as i32, signal) {
7883
if cli.warnings {
79-
eprintln!("Failed to send signal to process {}: {}", pid, e);
84+
eprintln!("Failed to send signal to process {}: {}", process.pid, e);
8085
}
8186
}
8287
}
@@ -86,22 +91,23 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
8691
}
8792

8893
// TODO: add more strict check according to the usage
89-
fn parse_expression(cli: &mut Cli) {
94+
fn parse_expression(cli: &mut Settings) {
9095
if let Expr::Raw(raw_expr) = &cli.expression {
9196
// Check if any strings in the raw expression match active users, commands, or terminals
9297
if raw_expr.iter().all(|s| s.parse::<i32>().is_ok()) {
9398
cli.expression =
9499
Expr::Pid(raw_expr.iter().map(|s| s.parse::<i32>().unwrap()).collect());
95100
} else {
101+
let mut processes = util::get_all_processes();
96102
let is_user_expr = raw_expr
97103
.iter()
98-
.any(|s| util::get_active_users().contains(s));
104+
.any(|s| util::get_active_users(&mut processes).contains(s));
99105
let is_command_expr = raw_expr
100106
.iter()
101-
.any(|s| util::get_active_commands().contains(s));
107+
.any(|s| util::get_active_commands(&processes).contains(s));
102108
let is_terminal_expr = raw_expr
103109
.iter()
104-
.any(|s| util::get_active_terminals().contains(s));
110+
.any(|s| util::get_active_terminals(&processes).contains(s));
105111
// Only perform the replacement if we found matching users
106112
let raw_clone = raw_expr.clone();
107113
if is_user_expr {
@@ -122,28 +128,27 @@ fn send_signal(pid: i32, signal: Signal) -> UResult<()> {
122128
}
123129
}
124130

125-
fn find_matching_pids(expression: &Expr) -> Vec<i32> {
126-
let mut pids = Vec::new();
131+
fn find_matching_processes(expression: &Expr) -> Vec<ProcessInformation> {
132+
let mut processes = Vec::new();
127133

128134
match expression {
129135
Expr::Pid(p) => {
130-
pids.extend_from_slice(p);
136+
processes.extend(util::filter_processes_by_pid(p));
131137
}
132138
Expr::User(u) => {
133-
pids.extend_from_slice(&util::filter_processes_by_user(u));
139+
processes.extend(util::filter_processes_by_user(u));
134140
}
135141
Expr::Command(c) => {
136-
pids.extend_from_slice(&util::filter_processes_by_command(c));
142+
processes.extend(util::filter_processes_by_command(c));
137143
}
138144
Expr::Terminal(t) => {
139-
pids.extend_from_slice(&util::filter_processes_by_terminal(t));
145+
processes.extend(util::filter_processes_by_terminal(t));
140146
}
141147
_ => {
142-
eprintln!("Invalid expression");
143148
return Vec::new();
144149
}
145150
}
146-
pids
151+
processes
147152
}
148153

149154
fn confirm_action(tty: &str, owner: &str, pid: i32, cmd: &str) -> bool {
@@ -161,7 +166,7 @@ fn confirm_action(tty: &str, owner: &str, pid: i32, cmd: &str) -> bool {
161166
input == "y" || input == "yes"
162167
}
163168

164-
fn list_signals(cli: &Cli) {
169+
fn list_signals(cli: &Settings) {
165170
if cli.list {
166171
for signal in ALL_SIGNALS[1..].iter() {
167172
print!("{} ", signal);

0 commit comments

Comments
 (0)