mirror of
https://github.com/uutils/procps.git
synced 2026-06-10 16:14:00 -07:00
snice&skill: implement interactive
This commit is contained in:
@@ -44,7 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let results = perform_action(&pids, &signal, take_action);
|
||||
let results = perform_action(&pids, &signal, take_action, settings.interactive);
|
||||
#[cfg(not(unix))]
|
||||
let results: Vec<Option<ActionResult>> = Vec::new();
|
||||
|
||||
@@ -67,15 +67,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn perform_action(pids: &[u32], signal: &Signal, take_action: bool) -> Vec<Option<ActionResult>> {
|
||||
fn perform_action(
|
||||
pids: &[u32],
|
||||
signal: &Signal,
|
||||
take_action: bool,
|
||||
ask: bool,
|
||||
) -> Vec<Option<ActionResult>> {
|
||||
let sig = if take_action { Some(*signal) } else { None };
|
||||
pids.iter()
|
||||
.map(|pid| {
|
||||
{
|
||||
if !ask || uu_snice::ask_user(*pid) {
|
||||
Some(match signal::kill(Pid::from_raw(*pid as i32), sig) {
|
||||
Ok(_) => ActionResult::Success,
|
||||
Err(_) => ActionResult::PermissionDenied,
|
||||
})
|
||||
} else {
|
||||
// won't be used, but we need to return (not None)
|
||||
Some(ActionResult::Success)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use crate::ask_user;
|
||||
use crate::priority::Priority;
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
@@ -171,7 +172,15 @@ pub(crate) fn perform_action(
|
||||
pids: &[u32],
|
||||
prio: &Priority,
|
||||
take_action: bool,
|
||||
ask: bool,
|
||||
) -> Vec<Option<ActionResult>> {
|
||||
let f = |pid: &u32| set_priority(*pid, prio, take_action);
|
||||
let f = |pid: &u32| {
|
||||
if !ask || ask_user(*pid) {
|
||||
set_priority(*pid, prio, take_action)
|
||||
} else {
|
||||
// won't be used, but we need to return (not None)
|
||||
Some(ActionResult::Success)
|
||||
}
|
||||
};
|
||||
pids.iter().map(f).collect()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ pub struct Settings {
|
||||
pub expressions: Option<Vec<SelectedTarget>>,
|
||||
pub verbose: bool,
|
||||
pub warnings: bool,
|
||||
pub interactive: bool,
|
||||
pub no_action: bool,
|
||||
}
|
||||
|
||||
@@ -33,6 +34,7 @@ impl Settings {
|
||||
expressions: Self::targets(matches),
|
||||
verbose: matches.get_flag("verbose"),
|
||||
warnings: matches.get_flag("warnings"),
|
||||
interactive: matches.get_flag("interactive"),
|
||||
no_action: matches.get_flag("no-action"),
|
||||
})
|
||||
}
|
||||
@@ -85,7 +87,7 @@ impl Settings {
|
||||
pub fn clap_args() -> Vec<Arg> {
|
||||
vec![
|
||||
// arg!(-f --fast "fast mode (not implemented)"),
|
||||
// arg!(-i --interactive "interactive"),
|
||||
arg!(-i --interactive "interactive").conflicts_with_all(["verbose", "no-action"]),
|
||||
arg!(-l --list "list all signal names"),
|
||||
arg!(-L --table "list all signal names in a nice table"),
|
||||
arg!(-n --"no-action" "do not actually kill processes; just print what would happen"),
|
||||
|
||||
@@ -10,6 +10,7 @@ use clap::{crate_version, Arg, Command};
|
||||
use prettytable::{format::consts::FORMAT_CLEAN, row, Table};
|
||||
pub use process_matcher::clap_args;
|
||||
use process_matcher::*;
|
||||
use std::io::Write;
|
||||
use std::{collections::HashSet, path::PathBuf, str::FromStr};
|
||||
use sysinfo::Pid;
|
||||
use uu_pgrep::process::ProcessInformation;
|
||||
@@ -104,7 +105,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
};
|
||||
|
||||
let pids = collect_pids(&targets);
|
||||
let results = perform_action(&pids, &priority, take_action);
|
||||
let results = perform_action(&pids, &priority, take_action, settings.interactive);
|
||||
|
||||
if results.iter().all(|it| it.is_none()) || results.is_empty() {
|
||||
return Err(USimpleError::new(1, "no process selection criteria"));
|
||||
@@ -124,6 +125,41 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ask_user(pid: u32) -> bool {
|
||||
let process = process_snapshot().process(Pid::from_u32(pid)).unwrap();
|
||||
|
||||
let tty = ProcessInformation::try_new(PathBuf::from_str(&format!("/proc/{pid}")).unwrap())
|
||||
.map(|v| v.tty().to_string())
|
||||
.unwrap_or(String::from("?"));
|
||||
|
||||
let user = process
|
||||
.user_id()
|
||||
.and_then(|uid| users().iter().find(|it| it.id() == uid))
|
||||
.map(|it| it.name())
|
||||
.unwrap_or("?")
|
||||
.to_owned();
|
||||
|
||||
let cmd = process
|
||||
.exe()
|
||||
.and_then(|it| it.iter().next_back())
|
||||
.unwrap_or("?".as_ref());
|
||||
let cmd = cmd.to_str().unwrap();
|
||||
|
||||
// no newline at the end
|
||||
print!("{tty:<8} {user:<8} {pid:<5} {cmd:<18} ? ");
|
||||
std::io::stdout().flush().unwrap();
|
||||
let mut input = String::new();
|
||||
if std::io::stdin().read_line(&mut input).is_err() {
|
||||
return false;
|
||||
}
|
||||
let input = input.trim();
|
||||
if input.eq_ignore_ascii_case("y") || input.eq_ignore_ascii_case("yes") {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn construct_verbose_result(
|
||||
pids: &[u32],
|
||||
|
||||
@@ -16,3 +16,9 @@ fn test_no_args() {
|
||||
fn test_no_process_selected() {
|
||||
new_ucmd!().arg("-u=invalid_user").fails().code_is(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_interactive_conflict_args() {
|
||||
new_ucmd!().args(&["-i", "-v"]).fails().code_is(1);
|
||||
new_ucmd!().args(&["-i", "-n"]).fails().code_is(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user