Skip to content

Commit 7c928a3

Browse files
authored
Merge pull request #216 from rustcoreutils/ps
ps: support -a, -e, -d options
2 parents d52f83b + d9e6fb1 commit 7c928a3

File tree

3 files changed

+127
-26
lines changed

3 files changed

+127
-26
lines changed

sys/ps.rs

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
//
2+
// Copyright (c) 2024 Hemi Labs, Inc.
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
110
#[cfg(target_os = "macos")]
211
mod psmacos;
312

@@ -23,26 +32,62 @@ struct Args {
2332
/// List all processes
2433
#[arg(short = 'A', long)]
2534
all: bool,
35+
36+
/// List all processes (alias for -A)
37+
#[arg(short = 'e')]
38+
all2: bool,
39+
40+
/// List all processes associated with terminals
41+
#[arg(short = 'a', long)]
42+
terminal_processes: bool,
43+
44+
/// Exclude session leaders
45+
#[arg(short = 'd', long)]
46+
exclude_session_leaders: bool,
2647
}
2748

2849
fn main() {
29-
let args = Args::parse();
30-
31-
if args.all {
32-
match platform::list_processes() {
33-
Ok(processes) => {
34-
println!(
35-
"{:<5} {:<5} {:<5} {:<5} {}",
36-
"PID", "PPID", "UID", "GID", "COMMAND"
37-
);
38-
for proc in processes {
39-
println!(
40-
"{:<5} {:<5} {:<5} {:<5} {}",
41-
proc.pid, proc.ppid, proc.uid, proc.gid, proc.path
42-
);
43-
}
44-
}
45-
Err(e) => eprintln!("Error: {}", e),
50+
let mut args = Args::parse();
51+
if args.all2 {
52+
args.all = true;
53+
}
54+
55+
let processes = match platform::list_processes() {
56+
Ok(processes) => processes,
57+
Err(e) => {
58+
eprintln!("Error: {}", e);
59+
return;
4660
}
61+
};
62+
63+
// Filter processes based on arguments
64+
let filtered_processes = if args.terminal_processes && args.exclude_session_leaders {
65+
processes
66+
.into_iter()
67+
.filter(|p| p.tty.is_some() && p.pid != p.sid) // -a and -d logic
68+
.collect::<Vec<_>>()
69+
} else if args.terminal_processes {
70+
processes
71+
.into_iter()
72+
.filter(|p| p.tty.is_some()) // -a logic
73+
.collect::<Vec<_>>()
74+
} else if args.exclude_session_leaders {
75+
processes
76+
.into_iter()
77+
.filter(|p| p.pid != p.sid) // -d logic
78+
.collect::<Vec<_>>()
79+
} else {
80+
processes
81+
};
82+
83+
println!(
84+
"{:<5} {:<5} {:<5} {:<5} {}",
85+
"PID", "PPID", "UID", "GID", "COMMAND"
86+
);
87+
for proc in filtered_processes {
88+
println!(
89+
"{:<5} {:<5} {:<5} {:<5} {}",
90+
proc.pid, proc.ppid, proc.uid, proc.gid, proc.path
91+
);
4792
}
4893
}

sys/pslinux.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
//
2+
// Copyright (c) 2024 Hemi Labs, Inc.
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
110
use std::fs;
211
use std::fs::read_to_string;
312
use std::io::Error;
@@ -9,6 +18,8 @@ pub struct ProcessInfo {
918
pub uid: u32,
1019
pub gid: u32,
1120
pub path: String,
21+
pub tty: Option<String>, // Add TTY field for -a option
22+
pub sid: i32, // Add session ID (SID) for -d option
1223
}
1324

1425
pub fn list_processes() -> Result<Vec<ProcessInfo>, Error> {
@@ -36,15 +47,19 @@ fn get_process_info(pid: i32, proc_path: &Path) -> Option<ProcessInfo> {
3647
let status = read_to_string(status_path).ok()?;
3748
let cmdline = read_to_string(cmdline_path).unwrap_or_default();
3849
let exe = fs::read_link(exe_path).unwrap_or_else(|_| PathBuf::from("[Permission denied]"));
39-
let mut comm = String::new();
50+
let comm = String::new();
4051

41-
if let Ok(stat) = read_to_string(stat_path) {
42-
if let Some(start) = stat.find('(') {
43-
if let Some(end) = stat.find(')') {
44-
comm = stat[start + 1..end].to_string();
45-
}
46-
}
47-
}
52+
// Read from /proc/<pid>/stat to get the session ID and TTY number
53+
let stat = read_to_string(stat_path).ok()?;
54+
let stat_fields: Vec<&str> = stat.split_whitespace().collect();
55+
let sid = stat_fields[5].parse().unwrap_or(0); // Session ID (SID)
56+
let tty_nr = stat_fields[6].parse::<i32>().unwrap_or(0);
57+
58+
let tty = if tty_nr > 0 {
59+
Some(format!("tty{}", tty_nr)) // Simplified TTY representation
60+
} else {
61+
None
62+
};
4863

4964
let mut ppid = 0;
5065
let mut uid = 0;
@@ -80,5 +95,7 @@ fn get_process_info(pid: i32, proc_path: &Path) -> Option<ProcessInfo> {
8095
uid,
8196
gid,
8297
path,
98+
tty,
99+
sid, // Return the session ID (SID)
83100
})
84101
}

sys/psmacos.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
use libc::{c_int, c_void, pid_t, proc_listallpids, proc_pidinfo, proc_pidpath};
1+
//
2+
// Copyright (c) 2024 Hemi Labs, Inc.
3+
//
4+
// This file is part of the posixutils-rs project covered under
5+
// the MIT License. For the full license text, please see the LICENSE
6+
// file in the root directory of this project.
7+
// SPDX-License-Identifier: MIT
8+
//
9+
10+
use libc::{c_int, c_void, getsid, pid_t, proc_listallpids, proc_pidinfo, proc_pidpath};
211
use std::ffi::CStr;
12+
use std::fs;
313
use std::io::Error;
14+
use std::os::unix::fs::MetadataExt;
415

516
const PROC_PIDPATHINFO_MAXSIZE: usize = 4096;
617

@@ -10,6 +21,8 @@ pub struct ProcessInfo {
1021
pub uid: u32,
1122
pub gid: u32,
1223
pub path: String,
24+
pub tty: Option<String>, // Add TTY field for -a option
25+
pub sid: pid_t, // Session ID (SID) for -d option
1326
}
1427

1528
pub fn list_processes() -> Result<Vec<ProcessInfo>, Error> {
@@ -75,11 +88,37 @@ fn get_process_info(pid: pid_t) -> Option<ProcessInfo> {
7588
String::new()
7689
};
7790

91+
// Retrieve the terminal device ID (TTY)
92+
let tty_dev = proc_info.e_tdev;
93+
94+
// Map the terminal device ID to the TTY name
95+
let tty = get_tty_name(tty_dev);
96+
7897
Some(ProcessInfo {
7998
pid: proc_info.pbi_pid as pid_t,
8099
ppid: proc_info.pbi_ppid as pid_t,
81100
uid: proc_info.pbi_uid,
82101
gid: proc_info.pbi_gid,
83102
path,
103+
tty, // Add the terminal (TTY) name
104+
sid: unsafe { getsid(pid) }, // Add session ID (SID)
84105
})
85106
}
107+
108+
// Function to map a device ID to a TTY name
109+
fn get_tty_name(tty_dev: u32) -> Option<String> {
110+
let dev_dir = "/dev/";
111+
if let Ok(entries) = fs::read_dir(dev_dir) {
112+
for entry in entries {
113+
if let Ok(entry) = entry {
114+
let path = entry.path();
115+
if let Ok(metadata) = fs::metadata(&path) {
116+
if metadata.rdev() == tty_dev as u64 {
117+
return Some(path.file_name()?.to_string_lossy().into_owned());
118+
}
119+
}
120+
}
121+
}
122+
}
123+
None
124+
}

0 commit comments

Comments
 (0)