Skip to content

Commit 6ce006d

Browse files
Merge branch 'main' into clippy_fix_warnings
2 parents 21ed361 + fb962d0 commit 6ce006d

File tree

16 files changed

+363
-146
lines changed

16 files changed

+363
-146
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ jobs:
5252
- name: build and test all programs separately
5353
shell: bash
5454
run: |
55-
## TODO: add hugetop and skill
56-
programs="free pgrep pidof pidwait pkill pmap ps pwdx slabtop snice sysctl tload top vmstat w watch"
55+
## TODO: add hugetop
56+
programs="free pgrep pidof pidwait pkill pmap ps pwdx skill slabtop snice sysctl tload top vmstat w watch"
5757
for program in $programs; do
5858
echo "Building and testing $program"
5959
cargo test -p "uu_$program" || exit 1

Cargo.lock

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

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ feat_common_core = [
4040
"pmap",
4141
"ps",
4242
"pwdx",
43+
"skill",
4344
"slabtop",
4445
"snice",
4546
"sysctl",
@@ -98,6 +99,7 @@ pkill = { optional = true, version = "0.0.1", package = "uu_pkill", path = "src/
9899
pmap = { optional = true, version = "0.0.1", package = "uu_pmap", path = "src/uu/pmap" }
99100
ps = { optional = true, version = "0.0.1", package = "uu_ps", path = "src/uu/ps" }
100101
pwdx = { optional = true, version = "0.0.1", package = "uu_pwdx", path = "src/uu/pwdx" }
102+
skill = { optional = true, version = "0.0.1", package = "uu_skill", path = "src/uu/skill" }
101103
slabtop = { optional = true, version = "0.0.1", package = "uu_slabtop", path = "src/uu/slabtop" }
102104
snice = { optional = true, version = "0.0.1", package = "uu_snice", path = "src/uu/snice" }
103105
sysctl = { optional = true, version = "0.0.1", package = "uu_sysctl", path = "src/uu/sysctl" }

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Ongoing:
2020
* `pmap`: Displays the memory map of a process.
2121
* `ps`: Displays information about active processes.
2222
* `pwdx`: Shows the current working directory of a process.
23+
* `skill`: Sends a signal to processes based on criteria like user, terminal, etc.
2324
* `slabtop`: Displays detailed kernel slab cache information in real time.
2425
* `snice`: Changes the scheduling priority of a running process.
2526
* `sysctl`: Read or write kernel parameters at run-time.
@@ -31,7 +32,6 @@ Ongoing:
3132

3233
TODO:
3334
* `hugetop`: Report hugepage usage of processes and the system as a whole.
34-
* `skill`: Sends a signal to processes based on criteria like user, terminal, etc.
3535

3636
Elsewhere:
3737

src/uu/pkill/src/pkill.rs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// file that was distributed with this source code.
55

66
// Pid utils
7-
use clap::{arg, crate_version, Command};
7+
use clap::{arg, crate_version, value_parser, Command};
88
#[cfg(unix)]
99
use nix::{
1010
sys::signal::{self, Signal},
@@ -48,19 +48,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
4848
} else {
4949
let sig = (settings.signal as i32)
5050
.try_into()
51-
.map_err(|e| std::io::Error::from_raw_os_error(e as i32))?;
51+
.map_err(|e| Error::from_raw_os_error(e as i32))?;
5252
Some(sig)
5353
};
5454

5555
// Collect pids
5656
let pids = process_matcher::find_matching_pids(&settings)?;
5757

5858
// Send signal
59-
// TODO: Implement -q
6059
#[cfg(unix)]
61-
let echo = matches.get_flag("echo");
62-
#[cfg(unix)]
63-
kill(&pids, sig, echo);
60+
{
61+
let echo = matches.get_flag("echo");
62+
let queue = matches.get_one::<u32>("queue").cloned();
63+
64+
kill(&pids, sig, queue, echo);
65+
}
6466

6567
if matches.get_flag("count") {
6668
println!("{}", pids.len());
@@ -71,25 +73,50 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
7173

7274
#[cfg(unix)]
7375
fn handle_obsolete(args: &mut [String]) {
74-
// Sanity check
75-
if args.len() > 2 {
76-
// Old signal can only be in the first argument position
77-
let slice = args[1].as_str();
78-
if let Some(signal) = slice.strip_prefix('-') {
76+
for arg in &mut args[1..] {
77+
if let Some(signal) = arg.strip_prefix('-') {
7978
// Check if it is a valid signal
8079
let opt_signal = signal_by_name_or_value(signal);
8180
if opt_signal.is_some() {
8281
// Replace with long option that clap can parse
83-
args[1] = format!("--signal={signal}");
82+
*arg = format!("--signal={signal}");
8483
}
8584
}
8685
}
8786
}
8887

88+
// Not contains in libc
89+
#[cfg(target_os = "linux")]
90+
extern "C" {
91+
fn sigqueue(
92+
pid: uucore::libc::pid_t,
93+
sig: uucore::libc::c_int,
94+
val: uucore::libc::sigval,
95+
) -> uucore::libc::c_int;
96+
}
97+
8998
#[cfg(unix)]
90-
fn kill(pids: &Vec<ProcessInformation>, sig: Option<Signal>, echo: bool) {
99+
#[allow(unused_variables)]
100+
fn kill(pids: &Vec<ProcessInformation>, sig: Option<Signal>, queue: Option<u32>, echo: bool) {
91101
for pid in pids {
92-
if let Err(e) = signal::kill(Pid::from_raw(pid.pid as i32), sig) {
102+
#[cfg(target_os = "linux")]
103+
let result = if let Some(queue) = queue {
104+
let v = unsafe {
105+
sigqueue(
106+
pid.pid as i32,
107+
sig.map_or(0, |s| s as uucore::libc::c_int),
108+
uucore::libc::sigval {
109+
sival_ptr: queue as usize as *mut uucore::libc::c_void,
110+
},
111+
)
112+
};
113+
nix::errno::Errno::result(v).map(drop)
114+
} else {
115+
signal::kill(Pid::from_raw(pid.pid as i32), sig)
116+
};
117+
#[cfg(not(target_os = "linux"))]
118+
let result = signal::kill(Pid::from_raw(pid.pid as i32), sig);
119+
if let Err(e) = result {
93120
show!(Error::from_raw_os_error(e as i32)
94121
.map_err_context(|| format!("killing pid {} failed", pid.pid)));
95122
} else if echo {
@@ -111,7 +138,8 @@ pub fn uu_app() -> Command {
111138
.args_override_self(true)
112139
.args([
113140
// arg!(-<sig> "signal to send (either number or name)"),
114-
// arg!(-q --queue <value> "integer value to be sent with the signal"),
141+
arg!(-q --queue <value> "integer value to be sent with the signal")
142+
.value_parser(value_parser!(u32)),
115143
arg!(-e --echo "display what is killed"),
116144
])
117145
.args(process_matcher::clap_args(

src/uu/skill/Cargo.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "uu_skill"
3+
description = "skill - (uutils) send a signal or report process status"
4+
repository = "https://github.com/uutils/procps/tree/main/src/uu/skill"
5+
authors.workspace = true
6+
categories.workspace = true
7+
edition.workspace = true
8+
homepage.workspace = true
9+
keywords.workspace = true
10+
license.workspace = true
11+
version.workspace = true
12+
13+
[dependencies]
14+
uucore = { workspace = true, features = ["signals"] }
15+
clap = { workspace = true }
16+
nix = { workspace = true }
17+
18+
uu_snice = { path = "../snice" }
19+
20+
21+
[lib]
22+
path = "src/skill.rs"
23+
24+
[[bin]]
25+
name = "skill"
26+
path = "src/main.rs"

src/uu/skill/skill.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# skill
2+
3+
```
4+
skill [signal] [options] <expression>
5+
```
6+
7+
Report processes matching an expression and send a signal to them.

src/uu/skill/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uucore::bin!(uu_skill);

src/uu/skill/src/skill.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// This file is part of the uutils procps package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
use clap::{arg, crate_version, value_parser, Arg, Command};
7+
#[cfg(unix)]
8+
use nix::{sys::signal, sys::signal::Signal, unistd::Pid};
9+
use uu_snice::{
10+
collect_pids, construct_verbose_result, print_signals, process_matcher, ActionResult,
11+
};
12+
use uucore::error::USimpleError;
13+
#[cfg(unix)]
14+
use uucore::signals::signal_by_name_or_value;
15+
use uucore::{error::UResult, format_usage, help_about, help_usage};
16+
17+
const ABOUT: &str = help_about!("skill.md");
18+
const USAGE: &str = help_usage!("skill.md");
19+
20+
#[uucore::main]
21+
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
22+
let matches = uu_app().try_get_matches_from(args)?;
23+
let settings = process_matcher::Settings::try_new(&matches)?;
24+
25+
// Case0: Print SIGNALS
26+
if let Some(display) = &settings.display {
27+
print_signals(display);
28+
return Ok(());
29+
}
30+
31+
// Case1: Send signal
32+
if let Some(targets) = settings.expressions {
33+
let pids = collect_pids(&targets);
34+
35+
#[cfg(unix)]
36+
let signal_str = matches.get_one::<String>("signal").cloned();
37+
38+
#[cfg(unix)]
39+
let signal = if let Some(sig) = signal_str {
40+
(signal_by_name_or_value(sig.strip_prefix('-').unwrap()).unwrap() as i32).try_into()?
41+
} else {
42+
Signal::SIGTERM
43+
};
44+
45+
#[cfg(unix)]
46+
let results = perform_action(&pids, &signal);
47+
#[cfg(not(unix))]
48+
let results: Vec<Option<ActionResult>> = Vec::new();
49+
50+
if results.iter().all(|it| it.is_none()) || results.is_empty() {
51+
return Err(USimpleError::new(1, "no process selection criteria"));
52+
}
53+
54+
if settings.verbose {
55+
let output = construct_verbose_result(&pids, &results).trim().to_owned();
56+
println!("{output}");
57+
}
58+
}
59+
60+
Ok(())
61+
}
62+
63+
#[cfg(unix)]
64+
fn perform_action(pids: &[u32], signal: &Signal) -> Vec<Option<ActionResult>> {
65+
pids.iter()
66+
.map(|pid| {
67+
{
68+
Some(match signal::kill(Pid::from_raw(*pid as i32), *signal) {
69+
Ok(_) => ActionResult::Success,
70+
71+
Err(_) => ActionResult::PermissionDenied,
72+
})
73+
}
74+
})
75+
.collect()
76+
}
77+
78+
#[allow(clippy::cognitive_complexity)]
79+
pub fn uu_app() -> Command {
80+
Command::new(uucore::util_name())
81+
.version(crate_version!())
82+
.about(ABOUT)
83+
.override_usage(format_usage(USAGE))
84+
.infer_long_args(true)
85+
.arg_required_else_help(true)
86+
.arg(Arg::new("signal"))
87+
.args([
88+
// arg!(-f --fast "fast mode (not implemented)"),
89+
// arg!(-i --interactive "interactive"),
90+
arg!(-l --list "list all signal names"),
91+
arg!(-L --table "list all signal names in a nice table"),
92+
// arg!(-n --"no-action" "do not actually kill processes; just print what would happen"),
93+
arg!(-v --verbose "explain what is being done"),
94+
// arg!(-w --warnings "enable warnings (not implemented)"),
95+
// Expressions
96+
arg!(-c --command <command> ... "expression is a command name"),
97+
arg!(-p --pid <pid> ... "expression is a process id number")
98+
.value_parser(value_parser!(u32)),
99+
arg!(-t --tty <tty> ... "expression is a terminal"),
100+
arg!(-u --user <username> ... "expression is a username"),
101+
// arg!(--ns <PID> "match the processes that belong to the same namespace as <pid>"),
102+
// arg!(--nslist <ns> "list which namespaces will be considered for the --ns option.")
103+
// .value_delimiter(',')
104+
// .value_parser(["ipc", "mnt", "net", "pid", "user", "uts"]),
105+
])
106+
}

src/uu/snice/src/action.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub(crate) fn users() -> &'static Users {
2424
}
2525

2626
#[derive(Debug)]
27-
pub(crate) enum SelectedTarget {
27+
pub enum SelectedTarget {
2828
Command(String),
2929
Pid(u32),
3030
Tty(Teletype),
@@ -93,7 +93,7 @@ impl SelectedTarget {
9393

9494
#[allow(unused)]
9595
#[derive(Debug, Clone)]
96-
pub(crate) enum ActionResult {
96+
pub enum ActionResult {
9797
PermissionDenied,
9898
Success,
9999
}

0 commit comments

Comments
 (0)