Skip to content

Commit 9518c42

Browse files
committed
ps: Implement bunch of field selection flags
1 parent 38c49c9 commit 9518c42

File tree

4 files changed

+199
-3
lines changed

4 files changed

+199
-3
lines changed

src/uu/ps/src/mapping.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,65 @@ pub(crate) fn default_codes() -> Vec<String> {
2626
["pid", "tname", "time", "ucmd"].map(Into::into).to_vec()
2727
}
2828

29+
/// Returns the full format codes (for -f flag).
30+
pub(crate) fn full_format_codes() -> Vec<String> {
31+
[
32+
"uid_hack", "pid", "ppid", "c", "stime", "tname", "time", "cmd",
33+
]
34+
.map(Into::into)
35+
.to_vec()
36+
}
37+
38+
/// Returns the extra full format codes (for -F flag).
39+
pub(crate) fn extra_full_format_codes() -> Vec<String> {
40+
[
41+
"uid", "pid", "ppid", "c", "sz", "rss", "psr", "stime", "tname", "time", "ucmd",
42+
]
43+
.map(Into::into)
44+
.to_vec()
45+
}
46+
47+
/// Returns the job format codes (for -j flag).
48+
pub(crate) fn job_format_codes() -> Vec<String> {
49+
["pid", "pgid", "sid", "tname", "time", "ucmd"]
50+
.map(Into::into)
51+
.to_vec()
52+
}
53+
54+
/// Returns the default codes with PSR column (for -P flag).
55+
pub(crate) fn default_with_psr_codes() -> Vec<String> {
56+
["pid", "psr", "tname", "time", "ucmd"]
57+
.map(Into::into)
58+
.to_vec()
59+
}
60+
61+
/// Returns the signal format codes (for -s flag).
62+
pub(crate) fn signal_format_codes() -> Vec<String> {
63+
[
64+
"uid", "pid", "pending", "blocked", "ignored", "caught", "stat", "tname", "time", "command",
65+
]
66+
.map(Into::into)
67+
.to_vec()
68+
}
69+
70+
/// Returns the user format codes (for -u flag).
71+
pub(crate) fn user_format_codes() -> Vec<String> {
72+
[
73+
"user", "pid", "%cpu", "%mem", "vsz", "rss", "tname", "stat", "bsdstart", "time", "command",
74+
]
75+
.map(Into::into)
76+
.to_vec()
77+
}
78+
79+
/// Returns the virtual memory format codes (for -v flag).
80+
pub(crate) fn vm_format_codes() -> Vec<String> {
81+
[
82+
"pid", "tname", "stat", "time", "maj_flt", "trs", "drs", "rss", "%mem", "command",
83+
]
84+
.map(Into::into)
85+
.to_vec()
86+
}
87+
2988
/// Collect mapping from argument
3089
pub(crate) fn default_mapping() -> HashMap<String, String> {
3190
let mut mapping = HashMap::new();

src/uu/ps/src/picker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub(crate) fn collect_pickers(
3131
"uid" | "euid" => pickers.push(helper(euid)),
3232
"ruid" => pickers.push(helper(ruid)),
3333
"suid" => pickers.push(helper(suid)),
34-
"user" | "euser" => pickers.push(helper(euser)),
34+
"uid_hack" | "user" | "euser" => pickers.push(helper(euser)),
3535
"ruser" => pickers.push(helper(ruser)),
3636
"suser" => pickers.push(helper(suser)),
3737
"pgid" => pickers.push(helper(pgid)),

src/uu/ps/src/ps.rs

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ mod sorting;
1111

1212
use clap::crate_version;
1313
use clap::{Arg, ArgAction, ArgMatches, Command};
14-
use mapping::{collect_code_mapping, default_codes, default_mapping};
14+
use mapping::{
15+
collect_code_mapping, default_codes, default_mapping, default_with_psr_codes,
16+
extra_full_format_codes, full_format_codes, job_format_codes, signal_format_codes,
17+
user_format_codes, vm_format_codes,
18+
};
1519
use parser::{parser, OptionalKeyValue};
1620
use prettytable::{format::consts::FORMAT_CLEAN, Row, Table};
1721
use std::{cell::RefCell, rc::Rc};
@@ -47,7 +51,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
4751
};
4852

4953
// Collect codes with order
50-
let codes = if arg_formats.is_empty() {
54+
let codes = if matches.get_flag("f") {
55+
full_format_codes()
56+
} else if matches.get_flag("F") {
57+
extra_full_format_codes()
58+
} else if matches.get_flag("j") {
59+
job_format_codes()
60+
} else if matches.get_flag("P") {
61+
default_with_psr_codes()
62+
} else if matches.get_flag("s") {
63+
signal_format_codes()
64+
} else if matches.get_flag("u") {
65+
user_format_codes()
66+
} else if matches.get_flag("v") {
67+
vm_format_codes()
68+
} else if arg_formats.is_empty() {
5169
default_codes()
5270
} else {
5371
arg_formats.iter().map(|it| it.key().to_owned()).collect()
@@ -164,6 +182,49 @@ pub fn uu_app() -> Command {
164182
// .help("processes without controlling ttys")
165183
// .allow_hyphen_values(true),
166184
])
185+
.arg(
186+
Arg::new("f")
187+
.short('f')
188+
.action(ArgAction::SetTrue)
189+
.help("full format listing"),
190+
)
191+
.arg(
192+
Arg::new("F")
193+
.short('F')
194+
.action(ArgAction::SetTrue)
195+
.help("extra full format listing"),
196+
)
197+
.arg(
198+
Arg::new("j")
199+
.short('j')
200+
.action(ArgAction::SetTrue)
201+
.help("job format"),
202+
)
203+
.arg(
204+
Arg::new("P")
205+
.short('P')
206+
.action(ArgAction::SetTrue)
207+
.help("add psr column"),
208+
)
209+
.arg(
210+
Arg::new("s")
211+
.short('s')
212+
.action(ArgAction::SetTrue)
213+
.help("signal format"),
214+
)
215+
// TODO: this can also be used with argument to filter by uid
216+
.arg(
217+
Arg::new("u")
218+
.short('u')
219+
.action(ArgAction::SetTrue)
220+
.help("user format"),
221+
)
222+
.arg(
223+
Arg::new("v")
224+
.short('v')
225+
.action(ArgAction::SetTrue)
226+
.help("virtual memory format"),
227+
)
167228
.arg(
168229
Arg::new("format")
169230
.short('o')

tests/by-util/test_ps.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,82 @@ fn test_invalid_arg() {
2121
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
2222
}
2323

24+
/// Helper function to check that ps output has the correct headers in the correct order
25+
#[cfg(target_os = "linux")]
26+
fn check_header(flag: &str, expected_headers: &[&str]) {
27+
let result = new_ucmd!().arg(flag).succeeds();
28+
let lines: Vec<&str> = result.stdout_str().lines().collect();
29+
let headers: Vec<&str> = lines[0].split_whitespace().collect();
30+
31+
assert_eq!(headers, expected_headers);
32+
}
33+
34+
#[test]
35+
#[cfg(target_os = "linux")]
36+
fn test_full_format_listing() {
37+
check_header(
38+
"-f",
39+
&["UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"],
40+
);
41+
}
42+
43+
#[test]
44+
#[cfg(target_os = "linux")]
45+
fn test_extra_full_format() {
46+
check_header(
47+
"-F",
48+
&[
49+
"UID", "PID", "PPID", "C", "SZ", "RSS", "PSR", "STIME", "TTY", "TIME", "CMD",
50+
],
51+
);
52+
}
53+
54+
#[test]
55+
#[cfg(target_os = "linux")]
56+
fn test_job_format() {
57+
check_header("-j", &["PID", "PGID", "SID", "TTY", "TIME", "CMD"]);
58+
}
59+
60+
#[test]
61+
#[cfg(target_os = "linux")]
62+
fn test_psr_format() {
63+
check_header("-P", &["PID", "PSR", "TTY", "TIME", "CMD"]);
64+
}
65+
66+
#[test]
67+
#[cfg(target_os = "linux")]
68+
fn test_signal_format() {
69+
check_header(
70+
"-s",
71+
&[
72+
"UID", "PID", "PENDING", "BLOCKED", "IGNORED", "CAUGHT", "STAT", "TTY", "TIME",
73+
"COMMAND",
74+
],
75+
);
76+
}
77+
78+
#[test]
79+
#[cfg(target_os = "linux")]
80+
fn test_user_format() {
81+
check_header(
82+
"-u",
83+
&[
84+
"USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY", "STAT", "START", "TIME", "COMMAND",
85+
],
86+
);
87+
}
88+
89+
#[test]
90+
#[cfg(target_os = "linux")]
91+
fn test_virtual_memory_format() {
92+
check_header(
93+
"-v",
94+
&[
95+
"PID", "TTY", "STAT", "TIME", "MAJFL", "TRS", "DRS", "RSS", "%MEM", "COMMAND",
96+
],
97+
);
98+
}
99+
24100
#[test]
25101
#[cfg(target_os = "linux")]
26102
fn test_code_mapping() {

0 commit comments

Comments
 (0)