Skip to content

Commit 65bab88

Browse files
authored
Merge pull request #385 from dezgeg/pidof-c
pidof: Support --check-root option
2 parents f34d697 + e8f49f5 commit 65bab88

File tree

4 files changed

+77
-46
lines changed

4 files changed

+77
-46
lines changed

src/uu/pgrep/src/process.rs

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// file that was distributed with this source code.
55

66
use regex::Regex;
7+
use std::fs::read_link;
78
use std::hash::Hash;
89
use std::sync::LazyLock;
910
use std::{
@@ -250,6 +251,17 @@ impl ProcessInformation {
250251
})
251252
}
252253

254+
pub fn current_process_info() -> Result<ProcessInformation, io::Error> {
255+
use std::str::FromStr;
256+
257+
#[cfg(target_os = "linux")]
258+
let pid = uucore::process::getpid();
259+
#[cfg(not(target_os = "linux"))]
260+
let pid = 0; // dummy
261+
262+
ProcessInformation::try_new(PathBuf::from_str(&format!("/proc/{}", pid)).unwrap())
263+
}
264+
253265
pub fn proc_status(&self) -> &str {
254266
&self.inner_status
255267
}
@@ -366,6 +378,11 @@ impl ProcessInformation {
366378
self.get_uid_or_gid_field("Gid", 1)
367379
}
368380

381+
// Root directory of the process (which can be changed by chroot)
382+
pub fn root(&mut self) -> Result<PathBuf, io::Error> {
383+
read_link(format!("/proc/{}/root", self.pid))
384+
}
385+
369386
/// Fetch run state from [ProcessInformation::cached_stat]
370387
///
371388
/// - [The /proc Filesystem: Table 1-4](https://docs.kernel.org/filesystems/proc.html#id10)
@@ -495,7 +512,9 @@ pub fn walk_threads() -> impl Iterator<Item = ProcessInformation> {
495512
mod tests {
496513
use super::*;
497514
#[cfg(target_os = "linux")]
498-
use std::{collections::HashSet, str::FromStr};
515+
use std::collections::HashSet;
516+
#[cfg(target_os = "linux")]
517+
use uucore::process::getpid;
499518

500519
#[test]
501520
fn test_run_state_conversion() {
@@ -515,41 +534,19 @@ mod tests {
515534
assert!(RunState::try_from("Rg").is_err());
516535
}
517536

518-
#[cfg(target_os = "linux")]
519-
fn current_pid() -> usize {
520-
// Direct read link of /proc/self.
521-
// It's result must be current programs pid.
522-
fs::read_link("/proc/self")
523-
.unwrap()
524-
.to_str()
525-
.unwrap()
526-
.parse::<usize>()
527-
.unwrap()
528-
}
529-
530-
#[cfg(target_os = "linux")]
531-
fn current_process_info() -> ProcessInformation {
532-
ProcessInformation::try_new(PathBuf::from_str(&format!("/proc/{}", current_pid())).unwrap())
533-
.unwrap()
534-
}
535-
536537
#[test]
537538
#[cfg(target_os = "linux")]
538539
fn test_walk_pid() {
539-
let current_pid = current_pid();
540-
541-
let find = walk_process().find(|it| it.pid == current_pid);
540+
let find = walk_process().find(|it| it.pid == getpid() as usize);
542541

543542
assert!(find.is_some());
544543
}
545544

546545
#[test]
547546
#[cfg(target_os = "linux")]
548547
fn test_pid_entry() {
549-
let current_pid = current_pid();
550-
551-
let pid_entry = current_process_info();
552-
let mut result = WalkDir::new(format!("/proc/{}/fd", current_pid))
548+
let pid_entry = ProcessInformation::current_process_info().unwrap();
549+
let mut result = WalkDir::new(format!("/proc/{}/fd", getpid()))
553550
.into_iter()
554551
.flatten()
555552
.map(DirEntry::into_path)
@@ -569,7 +566,7 @@ mod tests {
569566
fn test_thread_ids() {
570567
let main_tid = unsafe { uucore::libc::gettid() };
571568
std::thread::spawn(move || {
572-
let mut pid_entry = current_process_info();
569+
let mut pid_entry = ProcessInformation::current_process_info().unwrap();
573570
let thread_ids = pid_entry.thread_ids();
574571

575572
assert!(thread_ids.contains(&(main_tid as usize)));
@@ -599,7 +596,7 @@ mod tests {
599596
#[test]
600597
#[cfg(target_os = "linux")]
601598
fn test_ids() {
602-
let mut pid_entry = current_process_info();
599+
let mut pid_entry = ProcessInformation::current_process_info().unwrap();
603600
assert_eq!(
604601
pid_entry.ppid().unwrap(),
605602
unsafe { uucore::libc::getppid() } as u64
@@ -615,10 +612,17 @@ mod tests {
615612
#[test]
616613
#[cfg(target_os = "linux")]
617614
fn test_uid_gid() {
618-
let mut pid_entry = current_process_info();
615+
let mut pid_entry = ProcessInformation::current_process_info().unwrap();
619616
assert_eq!(pid_entry.uid().unwrap(), uucore::process::getuid());
620617
assert_eq!(pid_entry.euid().unwrap(), uucore::process::geteuid());
621618
assert_eq!(pid_entry.gid().unwrap(), uucore::process::getgid());
622619
assert_eq!(pid_entry.egid().unwrap(), uucore::process::getegid());
623620
}
621+
622+
#[test]
623+
#[cfg(target_os = "linux")]
624+
fn test_root() {
625+
let mut pid_entry = ProcessInformation::current_process_info().unwrap();
626+
assert_eq!(pid_entry.root().unwrap(), PathBuf::from("/"));
627+
}
624628
}

src/uu/pidof/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ categories = ["command-line-utilities"]
1313

1414

1515
[dependencies]
16-
uucore = { workspace = true }
16+
uucore = { workspace = true, features = ["process"] }
1717
clap = { workspace = true }
1818
uu_pgrep = { path = "../pgrep" }
1919

src/uu/pidof/src/pidof.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use std::path::PathBuf;
77

88
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
99
use uu_pgrep::process::{walk_process, ProcessInformation};
10+
#[cfg(unix)]
11+
use uucore::process::geteuid;
1012
use uucore::{error::UResult, format_usage, help_about, help_usage};
1113

1214
const ABOUT: &str = help_about!("pidof.md");
@@ -94,21 +96,35 @@ fn collect_matched_pids(matches: &ArgMatches) -> Vec<usize> {
9496
.copied()
9597
.collect::<Vec<_>>();
9698

99+
// Original pidof silently ignores the check-root option if the user is not root.
100+
#[cfg(unix)]
101+
let check_root = matches.get_flag("check-root") && geteuid() == 0;
102+
#[cfg(not(unix))]
103+
let check_root = false;
104+
let our_root = ProcessInformation::current_process_info()
105+
.unwrap()
106+
.root()
107+
.unwrap();
108+
97109
program_names
98110
.into_iter()
99111
.flat_map(|program| {
100112
let mut processed = Vec::new();
101113
for mut process in collected.clone() {
102-
let contains =
103-
match_process_name(&mut process, &program, with_workers, match_scripts);
104-
let should_omit = arg_omit_pid.contains(&process.pid);
105-
106-
if contains && !should_omit {
107-
if matches.get_flag("t") {
108-
processed.extend_from_slice(&process.thread_ids());
109-
} else {
110-
processed.push(process.pid);
111-
}
114+
if !match_process_name(&mut process, &program, with_workers, match_scripts) {
115+
continue;
116+
}
117+
if arg_omit_pid.contains(&process.pid) {
118+
continue;
119+
}
120+
if check_root && process.root().unwrap() != our_root {
121+
continue;
122+
}
123+
124+
if matches.get_flag("t") {
125+
processed.extend_from_slice(&process.thread_ids());
126+
} else {
127+
processed.push(process.pid);
112128
}
113129
}
114130

@@ -140,12 +156,13 @@ pub fn uu_app() -> Command {
140156
.index(1)
141157
.action(ArgAction::Append),
142158
)
143-
// .arg(
144-
// Arg::new("c")
145-
// .short('c')
146-
// .help("Return PIDs with the same root directory")
147-
// .action(ArgAction::SetTrue),
148-
// )
159+
.arg(
160+
Arg::new("check-root")
161+
.short('c')
162+
.long("check-root")
163+
.help("Only return PIDs with the same root directory")
164+
.action(ArgAction::SetTrue),
165+
)
149166
.arg(
150167
Arg::new("S")
151168
.short('S')

tests/by-util/test_pidof.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ fn test_quiet() {
4646
.no_output();
4747
}
4848

49+
#[test]
50+
#[cfg(target_os = "linux")]
51+
fn test_check_root_accepted() {
52+
new_ucmd!()
53+
.arg("-w")
54+
.arg("--check-root")
55+
.arg("kthreadd")
56+
.succeeds();
57+
}
58+
4959
#[test]
5060
#[cfg(target_os = "linux")]
5161
fn test_single_shot() {

0 commit comments

Comments
 (0)