mirror of
https://github.com/uutils/procps.git
synced 2026-06-10 16:14:00 -07:00
Merge pull request #492 from dezgeg/ps-fields
ps: Implement bunch of field selection flags
This commit is contained in:
+119
-4
@@ -26,17 +26,84 @@ pub(crate) fn default_codes() -> Vec<String> {
|
||||
["pid", "tname", "time", "ucmd"].map(Into::into).to_vec()
|
||||
}
|
||||
|
||||
/// Returns the full format codes (for -f flag).
|
||||
pub(crate) fn full_format_codes() -> Vec<String> {
|
||||
[
|
||||
"uid_hack", "pid", "ppid", "c", "stime", "tname", "time", "cmd",
|
||||
]
|
||||
.map(Into::into)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
/// Returns the extra full format codes (for -F flag).
|
||||
pub(crate) fn extra_full_format_codes() -> Vec<String> {
|
||||
[
|
||||
"uid", "pid", "ppid", "c", "sz", "rss", "psr", "stime", "tname", "time", "ucmd",
|
||||
]
|
||||
.map(Into::into)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
/// Returns the job format codes (for -j flag).
|
||||
pub(crate) fn job_format_codes() -> Vec<String> {
|
||||
["pid", "pgid", "sid", "tname", "time", "ucmd"]
|
||||
.map(Into::into)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
/// Returns the default codes with PSR column (for -P flag).
|
||||
pub(crate) fn default_with_psr_codes() -> Vec<String> {
|
||||
["pid", "psr", "tname", "time", "ucmd"]
|
||||
.map(Into::into)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
/// Returns the signal format codes (for -s flag).
|
||||
pub(crate) fn signal_format_codes() -> Vec<String> {
|
||||
[
|
||||
"uid", "pid", "pending", "blocked", "ignored", "caught", "stat", "tname", "time", "command",
|
||||
]
|
||||
.map(Into::into)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
/// Returns the user format codes (for -u flag).
|
||||
pub(crate) fn user_format_codes() -> Vec<String> {
|
||||
[
|
||||
"user", "pid", "%cpu", "%mem", "vsz", "rss", "tname", "stat", "bsdstart", "time", "command",
|
||||
]
|
||||
.map(Into::into)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
/// Returns the virtual memory format codes (for -v flag).
|
||||
pub(crate) fn vm_format_codes() -> Vec<String> {
|
||||
[
|
||||
"pid", "tname", "stat", "time", "maj_flt", "trs", "drs", "rss", "%mem", "command",
|
||||
]
|
||||
.map(Into::into)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
/// Collect mapping from argument
|
||||
pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
let mut mapping = HashMap::new();
|
||||
let mut append = |code: &str, header: &str| mapping.insert(code.into(), header.into());
|
||||
|
||||
// Those mapping generated from manpage
|
||||
// This list is mainly generated from both `ps L` output and manpage,
|
||||
// but some are also apparently undocumented.
|
||||
append("%cpu", "%CPU");
|
||||
append("%mem", "%MEM");
|
||||
append("_left", "LLLLLLLL");
|
||||
append("_left2", "L2L2L2L2");
|
||||
append("_right", "RRRRRRRR");
|
||||
append("_right2", "R2R2R2R2");
|
||||
append("_unlimited", "U");
|
||||
append("_unlimited2", "U2");
|
||||
append("ag_id", "AGID");
|
||||
append("ag_nice", "AGNI");
|
||||
append("args", "COMMAND");
|
||||
append("atime", "TIME");
|
||||
append("blocked", "BLOCKED");
|
||||
append("bsdstart", "START");
|
||||
append("bsdtime", "TIME");
|
||||
@@ -50,15 +117,20 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("cmd", "CMD");
|
||||
append("comm", "COMMAND");
|
||||
append("command", "COMMAND");
|
||||
append("context", "CONTEXT");
|
||||
append("cp", "CP");
|
||||
append("cpuid", "CPUID");
|
||||
append("cputime", "TIME");
|
||||
append("cputimes", "TIME");
|
||||
append("cuc", "%CUC");
|
||||
append("cuu", "%CUU");
|
||||
append("docker", "DOCKER");
|
||||
append("drs", "DRS");
|
||||
append("dsiz", "DSIZ");
|
||||
append("egid", "EGID");
|
||||
append("egroup", "EGROUP");
|
||||
append("eip", "EIP");
|
||||
append("environ", "ENVIRONM");
|
||||
append("esp", "ESP");
|
||||
append("etime", "ELAPSED");
|
||||
append("etimes", "ELAPSED");
|
||||
@@ -66,26 +138,42 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("euser", "EUSER");
|
||||
append("exe", "EXE");
|
||||
append("f", "F");
|
||||
append("fds", "FDS");
|
||||
append("fgid", "FGID");
|
||||
append("fgroup", "FGROUP");
|
||||
append("flag", "F");
|
||||
append("flags", "F");
|
||||
append("fname", "COMMAND");
|
||||
append("fsgid", "FSGID");
|
||||
append("fsgroup", "FSGROUP");
|
||||
append("fsuid", "FSUID");
|
||||
append("fsuser", "FSUSER");
|
||||
append("fuid", "FUID");
|
||||
append("fuser", "FUSER");
|
||||
append("gid", "GID");
|
||||
append("group", "GROUP");
|
||||
append("htprv", "HTPRV");
|
||||
append("htshr", "HTSHR");
|
||||
append("ignored", "IGNORED");
|
||||
append("intpri", "PRI");
|
||||
append("ipcns", "IPCNS");
|
||||
append("label", "LABEL");
|
||||
append("lstart", "STARTED");
|
||||
append("lastcpu", "C");
|
||||
append("lim", "LIM");
|
||||
append("longtname", "TTY");
|
||||
append("lsession", "SESSION");
|
||||
append("lstart", "STARTED");
|
||||
append("luid", "LUID");
|
||||
append("lwp", "LWP");
|
||||
append("lxc", "LXC");
|
||||
append("m_drs", "DRS");
|
||||
append("m_size", "SIZE");
|
||||
append("m_trs", "TRS");
|
||||
append("machine", "MACHINE");
|
||||
append("maj_flt", "MAJFLT");
|
||||
append("min_flt", "MINFLT");
|
||||
append("maj_flt", "MAJFL");
|
||||
append("majflt", "MAJFLT");
|
||||
append("min_flt", "MINFL");
|
||||
append("minflt", "MINFLT");
|
||||
append("mntns", "MNTNS");
|
||||
append("netns", "NETNS");
|
||||
append("ni", "NI");
|
||||
@@ -95,7 +183,11 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("nwchan", "WCHAN");
|
||||
append("oom", "OOM");
|
||||
append("oomadj", "OOMADJ");
|
||||
append("opri", "PRI");
|
||||
append("ouid", "OWNER");
|
||||
append("pagein", "PAGEIN");
|
||||
append("pcap", "PCAP");
|
||||
append("pcaps", "PCAPS");
|
||||
append("pcpu", "%CPU");
|
||||
append("pending", "PENDING");
|
||||
append("pgid", "PGID");
|
||||
@@ -106,6 +198,11 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("policy", "POL");
|
||||
append("ppid", "PPID");
|
||||
append("pri", "PRI");
|
||||
append("pri_api", "API");
|
||||
append("pri_bar", "BAR");
|
||||
append("pri_baz", "BAZ");
|
||||
append("pri_foo", "FOO");
|
||||
append("priority", "PRI");
|
||||
append("psr", "PSR");
|
||||
append("pss", "PSS");
|
||||
append("rbytes", "RBYTES");
|
||||
@@ -123,11 +220,17 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("sched", "SCH");
|
||||
append("seat", "SEAT");
|
||||
append("sess", "SESS");
|
||||
append("session", "SESS");
|
||||
append("sgi_p", "P");
|
||||
append("sgi_rss", "RSS");
|
||||
append("sgid", "SGID");
|
||||
append("sgroup", "SGROUP");
|
||||
append("sid", "SID");
|
||||
append("sig", "PENDING");
|
||||
append("sig_block", "BLOCKED");
|
||||
append("sig_catch", "CATCHED");
|
||||
append("sig_ignore", "IGNORED");
|
||||
append("sig_pend", "SIGNAL");
|
||||
append("sigcatch", "CAUGHT");
|
||||
append("sigignore", "IGNORED");
|
||||
append("sigmask", "BLOCKED");
|
||||
@@ -136,6 +239,7 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("spid", "SPID");
|
||||
append("stackp", "STACKP");
|
||||
append("start", "STARTED");
|
||||
append("start_stack", "STACKP");
|
||||
append("start_time", "START");
|
||||
append("stat", "STAT");
|
||||
append("state", "S");
|
||||
@@ -145,7 +249,9 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("supgrp", "SUPGRP");
|
||||
append("suser", "SUSER");
|
||||
append("svgid", "SVGID");
|
||||
append("svgroup", "SVGROUP");
|
||||
append("svuid", "SVUID");
|
||||
append("svuser", "SVUSER");
|
||||
append("sz", "SZ");
|
||||
append("tgid", "TGID");
|
||||
append("thcount", "THCNT");
|
||||
@@ -156,16 +262,23 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("tname", "TTY");
|
||||
append("tpgid", "TPGID");
|
||||
append("trs", "TRS");
|
||||
append("trss", "TRSS");
|
||||
append("tsig", "PENDING");
|
||||
append("tsiz", "TSIZ");
|
||||
append("tt", "TT");
|
||||
append("tty", "TT");
|
||||
append("tty4", "TTY");
|
||||
append("tty8", "TTY");
|
||||
append("ucmd", "CMD");
|
||||
append("ucomm", "COMMAND");
|
||||
append("uid", "UID");
|
||||
append("uid_hack", "UID");
|
||||
append("uname", "USER");
|
||||
append("unit", "UNIT");
|
||||
append("user", "USER");
|
||||
append("userns", "USERNS");
|
||||
append("uss", "USS");
|
||||
append("util", "C");
|
||||
append("utsns", "UTSNS");
|
||||
append("uunit", "UUNIT");
|
||||
append("vsize", "VSZ");
|
||||
@@ -174,7 +287,9 @@ pub(crate) fn default_mapping() -> HashMap<String, String> {
|
||||
append("wcbytes", "WCBYTES");
|
||||
append("wchan", "WCHAN");
|
||||
append("wchars", "WCHARS");
|
||||
append("wname", "WCHAN");
|
||||
append("wops", "WOPS");
|
||||
append("zone", "ZONE");
|
||||
|
||||
mapping
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub(crate) fn collect_pickers(
|
||||
"uid" | "euid" => pickers.push(helper(euid)),
|
||||
"ruid" => pickers.push(helper(ruid)),
|
||||
"suid" => pickers.push(helper(suid)),
|
||||
"user" | "euser" => pickers.push(helper(euser)),
|
||||
"uid_hack" | "user" | "euser" => pickers.push(helper(euser)),
|
||||
"ruser" => pickers.push(helper(ruser)),
|
||||
"suser" => pickers.push(helper(suser)),
|
||||
"pgid" => pickers.push(helper(pgid)),
|
||||
|
||||
+63
-2
@@ -11,7 +11,11 @@ mod sorting;
|
||||
|
||||
use clap::crate_version;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use mapping::{collect_code_mapping, default_codes, default_mapping};
|
||||
use mapping::{
|
||||
collect_code_mapping, default_codes, default_mapping, default_with_psr_codes,
|
||||
extra_full_format_codes, full_format_codes, job_format_codes, signal_format_codes,
|
||||
user_format_codes, vm_format_codes,
|
||||
};
|
||||
use parser::{parser, OptionalKeyValue};
|
||||
use prettytable::{format::consts::FORMAT_CLEAN, Row, Table};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
@@ -47,7 +51,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
};
|
||||
|
||||
// Collect codes with order
|
||||
let codes = if arg_formats.is_empty() {
|
||||
let codes = if matches.get_flag("f") {
|
||||
full_format_codes()
|
||||
} else if matches.get_flag("F") {
|
||||
extra_full_format_codes()
|
||||
} else if matches.get_flag("j") {
|
||||
job_format_codes()
|
||||
} else if matches.get_flag("P") {
|
||||
default_with_psr_codes()
|
||||
} else if matches.get_flag("s") {
|
||||
signal_format_codes()
|
||||
} else if matches.get_flag("u") {
|
||||
user_format_codes()
|
||||
} else if matches.get_flag("v") {
|
||||
vm_format_codes()
|
||||
} else if arg_formats.is_empty() {
|
||||
default_codes()
|
||||
} else {
|
||||
arg_formats.iter().map(|it| it.key().to_owned()).collect()
|
||||
@@ -164,6 +182,49 @@ pub fn uu_app() -> Command {
|
||||
// .help("processes without controlling ttys")
|
||||
// .allow_hyphen_values(true),
|
||||
])
|
||||
.arg(
|
||||
Arg::new("f")
|
||||
.short('f')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("full format listing"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("F")
|
||||
.short('F')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("extra full format listing"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("j")
|
||||
.short('j')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("job format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("P")
|
||||
.short('P')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("add psr column"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("s")
|
||||
.short('s')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("signal format"),
|
||||
)
|
||||
// TODO: this can also be used with argument to filter by uid
|
||||
.arg(
|
||||
Arg::new("u")
|
||||
.short('u')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("user format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("v")
|
||||
.short('v')
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("virtual memory format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("format")
|
||||
.short('o')
|
||||
|
||||
@@ -21,6 +21,82 @@ fn test_invalid_arg() {
|
||||
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
|
||||
}
|
||||
|
||||
/// Helper function to check that ps output has the correct headers in the correct order
|
||||
#[cfg(target_os = "linux")]
|
||||
fn check_header(flag: &str, expected_headers: &[&str]) {
|
||||
let result = new_ucmd!().arg(flag).succeeds();
|
||||
let lines: Vec<&str> = result.stdout_str().lines().collect();
|
||||
let headers: Vec<&str> = lines[0].split_whitespace().collect();
|
||||
|
||||
assert_eq!(headers, expected_headers);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_full_format_listing() {
|
||||
check_header(
|
||||
"-f",
|
||||
&["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_extra_full_format() {
|
||||
check_header(
|
||||
"-F",
|
||||
&[
|
||||
"UID", "PID", "PPID", "C", "SZ", "RSS", "PSR", "STIME", "TTY", "TIME", "CMD",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_job_format() {
|
||||
check_header("-j", &["PID", "PGID", "SID", "TTY", "TIME", "CMD"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_psr_format() {
|
||||
check_header("-P", &["PID", "PSR", "TTY", "TIME", "CMD"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_signal_format() {
|
||||
check_header(
|
||||
"-s",
|
||||
&[
|
||||
"UID", "PID", "PENDING", "BLOCKED", "IGNORED", "CAUGHT", "STAT", "TTY", "TIME",
|
||||
"COMMAND",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_user_format() {
|
||||
check_header(
|
||||
"-u",
|
||||
&[
|
||||
"USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "STAT", "START", "TIME", "COMMAND",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_virtual_memory_format() {
|
||||
check_header(
|
||||
"-v",
|
||||
&[
|
||||
"PID", "TTY", "STAT", "TIME", "MAJFL", "TRS", "DRS", "RSS", "%MEM", "COMMAND",
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_code_mapping() {
|
||||
|
||||
Reference in New Issue
Block a user