Skip to content

Commit 854000e

Browse files
authored
Merge pull request #7351 from dezgeg/process-sync
uucore: Sync proc_info methods from procps
2 parents 0c50271 + 88b93a6 commit 854000e

File tree

1 file changed

+103
-1
lines changed

1 file changed

+103
-1
lines changed

src/uucore/src/lib/features/proc_info.rs

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

66
// spell-checker:ignore exitstatus cmdline kworker pgrep pwait snice procps
7+
// spell-checker:ignore egid euid gettid ppid
78

89
//! Set of functions to manage IDs
910
//!
@@ -129,6 +130,14 @@ pub struct ProcessInformation {
129130
cached_stat: Option<Rc<Vec<String>>>,
130131

131132
cached_start_time: Option<u64>,
133+
134+
cached_thread_ids: Option<Rc<Vec<usize>>>,
135+
}
136+
137+
#[derive(Clone, Copy, Debug)]
138+
enum UidGid {
139+
Uid,
140+
Gid,
132141
}
133142

134143
impl ProcessInformation {
@@ -237,6 +246,43 @@ impl ProcessInformation {
237246
Ok(time)
238247
}
239248

249+
pub fn ppid(&mut self) -> Result<u64, io::Error> {
250+
// the PPID is the fourth field in /proc/<PID>/stat
251+
// (https://www.kernel.org/doc/html/latest/filesystems/proc.html#id10)
252+
self.stat()
253+
.get(3)
254+
.ok_or(io::ErrorKind::InvalidData)?
255+
.parse::<u64>()
256+
.map_err(|_| io::ErrorKind::InvalidData.into())
257+
}
258+
259+
fn get_uid_or_gid_field(&mut self, field: UidGid, index: usize) -> Result<u32, io::Error> {
260+
self.status()
261+
.get(&format!("{:?}", field))
262+
.ok_or(io::ErrorKind::InvalidData)?
263+
.split_whitespace()
264+
.nth(index)
265+
.ok_or(io::ErrorKind::InvalidData)?
266+
.parse::<u32>()
267+
.map_err(|_| io::ErrorKind::InvalidData.into())
268+
}
269+
270+
pub fn uid(&mut self) -> Result<u32, io::Error> {
271+
self.get_uid_or_gid_field(UidGid::Uid, 0)
272+
}
273+
274+
pub fn euid(&mut self) -> Result<u32, io::Error> {
275+
self.get_uid_or_gid_field(UidGid::Uid, 1)
276+
}
277+
278+
pub fn gid(&mut self) -> Result<u32, io::Error> {
279+
self.get_uid_or_gid_field(UidGid::Gid, 0)
280+
}
281+
282+
pub fn egid(&mut self) -> Result<u32, io::Error> {
283+
self.get_uid_or_gid_field(UidGid::Gid, 1)
284+
}
285+
240286
/// Fetch run state from [ProcessInformation::cached_stat]
241287
///
242288
/// - [The /proc Filesystem: Table 1-4](https://docs.kernel.org/filesystems/proc.html#id10)
@@ -271,8 +317,33 @@ impl ProcessInformation {
271317

272318
Teletype::Unknown
273319
}
274-
}
275320

321+
pub fn thread_ids(&mut self) -> Rc<Vec<usize>> {
322+
if let Some(c) = &self.cached_thread_ids {
323+
return Rc::clone(c);
324+
}
325+
326+
let thread_ids_dir = format!("/proc/{}/task", self.pid);
327+
let result = Rc::new(
328+
WalkDir::new(thread_ids_dir)
329+
.min_depth(1)
330+
.max_depth(1)
331+
.follow_links(false)
332+
.into_iter()
333+
.flatten()
334+
.flat_map(|it| {
335+
it.path()
336+
.file_name()
337+
.and_then(|it| it.to_str())
338+
.and_then(|it| it.parse::<usize>().ok())
339+
})
340+
.collect::<Vec<_>>(),
341+
);
342+
343+
self.cached_thread_ids = Some(Rc::clone(&result));
344+
Rc::clone(&result)
345+
}
346+
}
276347
impl TryFrom<DirEntry> for ProcessInformation {
277348
type Error = io::Error;
278349

@@ -399,6 +470,25 @@ mod tests {
399470
);
400471
}
401472

473+
#[test]
474+
fn test_thread_ids() {
475+
let main_tid = unsafe { uucore::libc::gettid() };
476+
std::thread::spawn(move || {
477+
let mut pid_entry = ProcessInformation::try_new(
478+
PathBuf::from_str(&format!("/proc/{}", current_pid())).unwrap(),
479+
)
480+
.unwrap();
481+
let thread_ids = pid_entry.thread_ids();
482+
483+
assert!(thread_ids.contains(&(main_tid as usize)));
484+
485+
let new_thread_tid = unsafe { uucore::libc::gettid() };
486+
assert!(thread_ids.contains(&(new_thread_tid as usize)));
487+
})
488+
.join()
489+
.unwrap();
490+
}
491+
402492
#[test]
403493
fn test_stat_split() {
404494
let case = "32 (idle_inject/3) S 2 0 0 0 -1 69238848 0 0 0 0 0 0 0 0 -51 0 1 0 34 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 3 50 1 0 0 0 0 0 0 0 0 0 0 0";
@@ -410,4 +500,16 @@ mod tests {
410500
let case = "47246 (kworker /10:1-events) I 2 0 0 0 -1 69238880 0 0 0 0 17 29 0 0 20 0 1 0 1396260 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 10 0 0 0 0 0 0 0 0 0 0 0 0 0";
411501
assert!(stat_split(case)[1] == "kworker /10:1-events");
412502
}
503+
504+
#[test]
505+
fn test_uid_gid() {
506+
let mut pid_entry = ProcessInformation::try_new(
507+
PathBuf::from_str(&format!("/proc/{}", current_pid())).unwrap(),
508+
)
509+
.unwrap();
510+
assert_eq!(pid_entry.uid().unwrap(), uucore::process::getuid());
511+
assert_eq!(pid_entry.euid().unwrap(), uucore::process::geteuid());
512+
assert_eq!(pid_entry.gid().unwrap(), uucore::process::getgid());
513+
assert_eq!(pid_entry.egid().unwrap(), uucore::process::getegid());
514+
}
413515
}

0 commit comments

Comments
 (0)