Skip to content

Commit 2bbf963

Browse files
committed
Merge origin/main: resolve conflict in basic_collector
Merge latest changes from origin/main which added euid check to basic_collector for better process filtering. Kept mutable borrow for tty() method as required by PR uutils#533.
2 parents b8004a9 + f636cb9 commit 2bbf963

File tree

12 files changed

+738
-208
lines changed

12 files changed

+738
-208
lines changed

Cargo.lock

Lines changed: 214 additions & 117 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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ clap = { version = "4.5.4", features = ["wrap_help", "cargo", "env"] }
5858
clap_complete = "4.5.2"
5959
clap_mangen = "0.2.20"
6060
crossterm = "0.29.0"
61-
ctor = "0.5.0"
61+
ctor = "0.6.0"
6262
dirs = "6.0.0"
6363
jiff = "0.2.15"
6464
libc = "0.2.154"
@@ -75,7 +75,7 @@ terminal_size = "0.4.2"
7575
textwrap = { version = "0.16.1", features = ["terminal_size"] }
7676
thiserror = "2.0.4"
7777
uucore = "0.2.2"
78-
uutests = "0.2.0"
78+
uutests = "0.3.0"
7979
walkdir = "2.5.0"
8080
windows = { version = "0.62.0" }
8181
windows-sys = { version = "0.61.0", default-features = false }

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/uutils/procps/blob/main/LICENSE)
44
[![dependency status](https://deps.rs/repo/github/uutils/procps/status.svg)](https://deps.rs/repo/github/uutils/procps)
55

6-
[![CodeCov](https://codecov.io/gh/uutils/procps/branch/master/graph/badge.svg)](https://codecov.io/gh/uutils/procps)
6+
[![CodeCov](https://codecov.io/gh/uutils/procps/branch/main/graph/badge.svg)](https://codecov.io/gh/uutils/procps)
77

88
# procps
99

src/uu/ps/src/collector.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,12 @@ pub(crate) fn basic_collector(
3535
) -> Vec<Rc<RefCell<ProcessInformation>>> {
3636
let mut result = Vec::new();
3737

38-
let current_tty = {
39-
// SAFETY: The `libc::getpid` always return i32
40-
let proc_path =
41-
PathBuf::from_str(&format!("/proc/{}/", unsafe { libc::getpid() })).unwrap();
42-
let mut current_proc_info = ProcessInformation::try_new(proc_path).unwrap();
43-
44-
current_proc_info.tty()
45-
};
38+
let mut cur = ProcessInformation::current_process_info().unwrap();
39+
let tty = cur.tty();
40+
let euid = cur.euid().unwrap();
4641

4742
for proc_info in proc_snapshot {
48-
let proc_ttys = proc_info.borrow_mut().tty();
49-
50-
if proc_ttys == current_tty {
43+
if proc_info.borrow_mut().tty() == tty && proc_info.borrow_mut().euid().unwrap() == euid {
5144
result.push(proc_info.clone());
5245
}
5346
}

src/uu/ps/src/ps.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
3838
.collect::<Vec<_>>();
3939
let mut proc_infos = Vec::new();
4040

41-
proc_infos.extend(collector::basic_collector(&snapshot));
42-
proc_infos.extend(collector::process_collector(&matches, &snapshot));
43-
proc_infos.extend(collector::session_collector(&matches, &snapshot));
41+
if !matches.get_flag("A") && !matches.get_flag("a") && !matches.get_flag("d") {
42+
proc_infos.extend(collector::basic_collector(&snapshot));
43+
} else {
44+
proc_infos.extend(collector::process_collector(&matches, &snapshot));
45+
proc_infos.extend(collector::session_collector(&matches, &snapshot));
46+
}
4447

48+
proc_infos.sort_by(|a, b| a.borrow().pid.cmp(&b.borrow().pid));
4549
proc_infos.dedup_by(|a, b| a.borrow().pid == b.borrow().pid);
4650

4751
sorting::sort(&mut proc_infos, &matches);

src/uu/top/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ license.workspace = true
1111
version.workspace = true
1212

1313
[dependencies]
14-
uucore = { workspace = true, features = ["utmpx", "uptime"] }
14+
uucore = { workspace = true, features = ["utmpx", "uptime", "signals"] }
1515
clap = { workspace = true }
1616
crossterm = { workspace = true }
1717
libc = { workspace = true }

src/uu/top/src/action.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
#[cfg(target_os = "linux")]
7+
pub(crate) fn renice(pid: u32, nice_value: i32) -> uucore::error::UResult<()> {
8+
use libc::{setpriority, PRIO_PROCESS};
9+
use uucore::error::USimpleError;
10+
11+
let result = unsafe { setpriority(PRIO_PROCESS, pid, nice_value) };
12+
if result == -1 {
13+
Err(USimpleError::new(0, "Permission Denied"))
14+
} else {
15+
Ok(())
16+
}
17+
}
18+
19+
#[cfg(unix)]
20+
pub(crate) fn kill_process(pid: u32, sig: usize) -> uucore::error::UResult<()> {
21+
use nix::sys::signal;
22+
use nix::sys::signal::Signal;
23+
use nix::unistd::Pid;
24+
use uucore::error::USimpleError;
25+
26+
signal::kill(Pid::from_raw(pid as i32), Signal::try_from(sig as i32)?)
27+
.map_err(|_| USimpleError::new(0, "Permission Denied"))
28+
}

src/uu/top/src/picker.rs

Lines changed: 113 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6-
use crate::tui::stat::TuiStat;
6+
use crate::tui::stat::{TimeScale, TuiStat};
77
use crate::Settings;
88
use std::any::Any;
99
use std::cmp::Ordering;
@@ -24,13 +24,13 @@ pub fn sysinfo() -> &'static RwLock<System> {
2424
}
2525

2626
pub trait Column {
27-
fn as_string(&self, show_zeros: bool) -> String;
27+
fn as_string(&self, tui_stat: &TuiStat) -> String;
2828
fn cmp_dyn(&self, other: &dyn Column) -> Ordering;
2929
fn as_any(&self) -> &dyn Any;
3030
}
3131

3232
impl Column for String {
33-
fn as_string(&self, _show_zeros: bool) -> String {
33+
fn as_string(&self, _tui_stat: &TuiStat) -> String {
3434
self.clone()
3535
}
3636

@@ -47,8 +47,8 @@ impl Column for String {
4747
}
4848

4949
impl Column for u32 {
50-
fn as_string(&self, show_zeros: bool) -> String {
51-
if !show_zeros && self == &0 {
50+
fn as_string(&self, tui_stat: &TuiStat) -> String {
51+
if !tui_stat.show_zeros && self == &0 {
5252
return String::new();
5353
}
5454
self.to_string()
@@ -67,8 +67,8 @@ impl Column for u32 {
6767
}
6868

6969
impl Column for Option<i32> {
70-
fn as_string(&self, show_zeros: bool) -> String {
71-
if !show_zeros && self == &Some(0) {
70+
fn as_string(&self, tui_stat: &TuiStat) -> String {
71+
if !tui_stat.show_zeros && self == &Some(0) {
7272
return String::new();
7373
}
7474
self.map(|v| v.to_string()).unwrap_or_default()
@@ -102,8 +102,8 @@ impl PercentValue {
102102
}
103103

104104
impl Column for PercentValue {
105-
fn as_string(&self, show_zeros: bool) -> String {
106-
if !show_zeros && self.value == 0.0 {
105+
fn as_string(&self, tui_stat: &TuiStat) -> String {
106+
if !tui_stat.show_zeros && self.value == 0.0 {
107107
return String::new();
108108
}
109109
format!("{:.1}", self.value)
@@ -132,8 +132,8 @@ impl MemValue {
132132
}
133133

134134
impl Column for MemValue {
135-
fn as_string(&self, show_zeros: bool) -> String {
136-
if !show_zeros && self.value == 0 {
135+
fn as_string(&self, tui_stat: &TuiStat) -> String {
136+
if !tui_stat.show_zeros && self.value == 0 {
137137
return String::new();
138138
}
139139
let mem_mb = self.value as f64 / bytesize::MIB as f64;
@@ -156,33 +156,63 @@ impl Column for MemValue {
156156
}
157157
}
158158

159-
struct TimeMSValue {
160-
min: u64,
159+
struct TimeValue {
161160
sec: f64,
162161
}
163162

164-
impl TimeMSValue {
165-
fn new_boxed(min: u64, sec: f64) -> Box<Self> {
166-
Box::new(Self { min, sec })
163+
impl TimeValue {
164+
fn new_boxed(sec: f64) -> Box<Self> {
165+
Box::new(Self { sec })
167166
}
168167
}
169168

170-
impl Column for TimeMSValue {
171-
fn as_string(&self, show_zeros: bool) -> String {
172-
if !show_zeros && self.min == 0 && self.sec < 0.01 {
169+
impl Column for TimeValue {
170+
fn as_string(&self, tui_stat: &TuiStat) -> String {
171+
if !tui_stat.show_zeros && self.sec < 0.01 {
173172
return String::new();
174173
}
175-
format!("{}:{:0>5.2}", self.min, self.sec)
174+
match tui_stat.time_scale {
175+
TimeScale::MinSecondCent => {
176+
let min = (self.sec / 60.0).floor() as u32;
177+
let sec = self.sec - (min * 60) as f64;
178+
format!("{}:{:0>5.2}", min, sec)
179+
}
180+
TimeScale::MinSecond => {
181+
let min = (self.sec / 60.0).floor() as u32;
182+
let sec = (self.sec - (min * 60) as f64).floor() as u32;
183+
format!("{}:{:0>2}", min, sec)
184+
}
185+
TimeScale::HourMin => {
186+
let hour = (self.sec / 3600.0).floor() as u32;
187+
let min = ((self.sec - (hour * 3600) as f64) / 60.0).floor() as u32;
188+
format!("{},{:0>2}", hour, min)
189+
}
190+
TimeScale::DayHour => {
191+
let day = (self.sec / 86400.0).floor() as u32;
192+
let hour = ((self.sec - (day * 86400) as f64) / 3600.0).floor() as u32;
193+
format!("{}d+{}h", day, hour)
194+
}
195+
TimeScale::Day => {
196+
let day = (self.sec / 86400.0).floor() as u32;
197+
format!("{}d", day)
198+
}
199+
TimeScale::WeekDay => {
200+
let week = (self.sec / 604800.0).floor() as u32;
201+
let day = ((self.sec - (week * 604800) as f64) / 86400.0).floor() as u32;
202+
format!("{}w+{}d", week, day)
203+
}
204+
TimeScale::Week => {
205+
let week = (self.sec / 604800.0).floor() as u32;
206+
format!("{}w", week)
207+
}
208+
}
176209
}
177210

178211
fn cmp_dyn(&self, other: &dyn Column) -> Ordering {
179212
other
180213
.as_any()
181-
.downcast_ref::<TimeMSValue>()
182-
.map(|o| match self.min.cmp(&o.min) {
183-
Ordering::Equal => self.sec.partial_cmp(&o.sec).unwrap_or(Ordering::Equal),
184-
ord => ord,
185-
})
214+
.downcast_ref::<TimeValue>()
215+
.map(|o| self.sec.partial_cmp(&o.sec).unwrap_or(Ordering::Equal))
186216
.unwrap_or(Ordering::Equal)
187217
}
188218
fn as_any(&self) -> &dyn Any {
@@ -383,18 +413,12 @@ fn s(pid: u32, _stat: Stat) -> Box<dyn Column> {
383413
fn time_plus(pid: u32, _stat: Stat) -> Box<dyn Column> {
384414
let binding = sysinfo().read().unwrap();
385415
let Some(proc) = binding.process(Pid::from_u32(pid)) else {
386-
return TimeMSValue::new_boxed(0, 0.0);
416+
return TimeValue::new_boxed(0.0);
387417
};
388418

389-
let (min, sec) = {
390-
let total = proc.accumulated_cpu_time();
391-
let minute = total / (60 * 1000);
392-
let second = (total % (60 * 1000)) as f64 / 1000.0;
419+
let second = proc.accumulated_cpu_time() as f64 / 1000.0;
393420

394-
(minute, second)
395-
};
396-
397-
TimeMSValue::new_boxed(min, sec)
421+
TimeValue::new_boxed(second)
398422
}
399423

400424
fn mem(pid: u32, _stat: Stat) -> Box<dyn Column> {
@@ -408,8 +432,42 @@ fn mem(pid: u32, _stat: Stat) -> Box<dyn Column> {
408432
)
409433
}
410434

411-
fn command(pid: u32, stat: Stat) -> Box<dyn Column> {
412-
let full_command_line = stat.1.full_command_line;
435+
#[cfg(target_os = "linux")]
436+
pub(crate) fn get_supplementary_groups(pid: u32) -> String {
437+
use sysinfo::{Gid, Groups};
438+
439+
let groups = Groups::new_with_refreshed_list();
440+
let path = PathBuf::from_str(&format!("/proc/{pid}/status")).unwrap();
441+
if let Ok(file) = File::open(path) {
442+
let content = read_to_string(file).unwrap();
443+
for line in content.lines() {
444+
if line.starts_with("Groups:") {
445+
let groups = line
446+
.split_whitespace()
447+
.skip(1)
448+
.filter_map(|s| Gid::from_str(s).ok())
449+
.filter_map(|gid| groups.iter().find(|g| g.id() == &gid))
450+
.map(|group| group.name())
451+
.collect::<Vec<_>>()
452+
.join(",");
453+
return groups;
454+
}
455+
}
456+
}
457+
String::new()
458+
}
459+
460+
#[cfg(target_os = "linux")]
461+
pub(crate) fn get_cgroup(pid: u32) -> String {
462+
let path = PathBuf::from_str(&format!("/proc/{pid}/cgroup")).unwrap();
463+
if let Ok(file) = File::open(path) {
464+
read_to_string(file).unwrap()
465+
} else {
466+
String::new()
467+
}
468+
}
469+
470+
pub(crate) fn get_command(pid: u32, full_command_line: bool) -> String {
413471
let f = |cmd: &[OsString]| -> String {
414472
let binding = cmd
415473
.iter()
@@ -444,23 +502,26 @@ fn command(pid: u32, stat: Stat) -> Box<dyn Column> {
444502

445503
let binding = sysinfo().read().unwrap();
446504
let Some(proc) = binding.process(Pid::from_u32(pid)) else {
447-
return Box::new("?".to_string());
505+
return "?".to_string();
448506
};
449507

450-
Box::new(
451-
proc.exe()
452-
.and_then(|it| {
453-
if full_command_line {
454-
it.iter().next_back()
455-
} else {
456-
it.file_name()
457-
}
458-
})
459-
.map(|it| it.to_str().unwrap().to_string())
460-
.unwrap_or(if full_command_line {
461-
f(proc.cmd())
508+
proc.exe()
509+
.and_then(|it| {
510+
if full_command_line {
511+
it.iter().next_back()
462512
} else {
463-
proc.name().to_str().unwrap().to_string()
464-
}),
465-
)
513+
it.file_name()
514+
}
515+
})
516+
.map(|it| it.to_str().unwrap().to_string())
517+
.unwrap_or(if full_command_line {
518+
f(proc.cmd())
519+
} else {
520+
proc.name().to_str().unwrap().to_string()
521+
})
522+
}
523+
524+
fn command(pid: u32, stat: Stat) -> Box<dyn Column> {
525+
let full_command_line = stat.1.full_command_line;
526+
Box::new(get_command(pid, full_command_line))
466527
}

0 commit comments

Comments
 (0)