Skip to content

Commit d9506f6

Browse files
authored
Add new module, processes, to enumerate pids (#86)
This re-works the proc_listpids and proc_listpidspath API wrappers to pass along the correct typeinfo value for each proc type, and to use io::Result errors instead of string errors.. This includes a per-os sys module, and a Linux re-implementation of the listpids filters on top of procfs.
1 parent 4e76b9d commit d9506f6

File tree

9 files changed

+960
-123
lines changed

9 files changed

+960
-123
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "libproc"
3-
version = "0.12.0"
3+
version = "0.13.0"
44
description = "A library to get information about running processes - for Mac OS X and Linux"
55
authors = ["Andrew Mackenzie <[email protected]>"]
66
repository = "https://github.com/andrewdavidmackenzie/libproc-rs"
@@ -32,3 +32,7 @@ path = "src/dmesg.rs"
3232

3333
[build-dependencies]
3434
bindgen = { version = "0.64.0", default-features = false, features = ["runtime"] }
35+
36+
[target.'cfg(target_os = "linux")'.dev-dependencies]
37+
procfs = "0.14.1"
38+
tempfile = "3.3.0"

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ extern crate libc;
1010
extern crate errno;
1111

1212
pub mod libproc;
13+
/// List processes by type and / or by path
14+
pub mod processes;
1315

1416
#[cfg(target_os = "macos")]
1517
#[allow(warnings, missing_docs)]

src/libproc/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ pub mod file_info;
3232
pub mod net_info;
3333

3434
mod helpers;
35+
pub(crate) mod sys;

src/libproc/proc_pid.rs

Lines changed: 51 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ use std::fs;
88
#[cfg(target_os = "macos")]
99
use std::mem;
1010
use std::path::PathBuf;
11-
#[cfg(target_os = "macos")]
12-
use std::ptr;
1311

1412
use libc::pid_t;
1513
#[cfg(target_os = "linux")]
@@ -25,17 +23,16 @@ use crate::libproc::thread_info::ThreadInfo;
2523
use crate::libproc::work_queue_info::WorkQueueInfo;
2624
#[cfg(target_os = "macos")]
2725
use crate::osx_libproc_bindings::{
28-
proc_libversion, proc_listpids, proc_listpidspath, proc_name, proc_pidinfo, proc_pidpath,
29-
proc_regionfilename, PROC_PIDPATHINFO_MAXSIZE,
26+
proc_libversion, proc_name, proc_pidinfo, proc_pidpath, proc_regionfilename,
27+
PROC_PIDPATHINFO_MAXSIZE,
3028
};
3129

3230
#[cfg(target_os = "macos")]
33-
use self::libc::{c_char, c_void};
31+
use self::libc::c_void;
3432
#[cfg(target_os = "linux")]
3533
use self::libc::{c_char, readlink};
3634

37-
#[cfg(target_os = "macos")]
38-
use std::ffi::CString;
35+
use crate::processes;
3936

4037
/// The `ProcType` type. Used to specify what type of processes you are interested
4138
/// in in other calls, such as `listpids`.
@@ -143,47 +140,32 @@ impl ListPIDInfo for ListThreads {
143140
}
144141
}
145142

146-
/// Returns the PIDs of the active processes that match the ProcType passed in
147-
///
148-
/// # Examples
149-
///
150-
/// Get the list of running process IDs using `listpids`
151-
///
152-
/// ```
153-
/// use std::io::Write;
154-
/// use libproc::libproc::proc_pid;
155-
///
156-
/// if let Ok(pids) = proc_pid::listpids(proc_pid::ProcType::ProcAllPIDS) {
157-
/// println!("Found {} processes using listpids()", pids.len());
158-
/// }
159-
/// ```
160-
#[cfg(target_os = "macos")]
161-
pub fn listpids(proc_types: ProcType) -> Result<Vec<u32>, String> {
162-
let buffer_size = unsafe { proc_listpids(proc_types as u32, 0, ptr::null_mut(), 0) };
163-
if buffer_size <= 0 {
164-
return Err(helpers::get_errno_with_message(buffer_size));
165-
}
166-
167-
let capacity = buffer_size as usize / mem::size_of::<u32>();
168-
let mut pids: Vec<u32> = Vec::with_capacity(capacity);
169-
let buffer_ptr = pids.as_mut_ptr() as *mut c_void;
170-
171-
let ret = unsafe { proc_listpids(proc_types as u32, 0, buffer_ptr, buffer_size) };
172-
173-
if ret <= 0 {
174-
Err(helpers::get_errno_with_message(ret))
175-
} else {
176-
let items_count = ret as usize / mem::size_of::<u32>() - 1;
177-
unsafe {
178-
pids.set_len(items_count);
143+
/// Map `ProcType` to the new `ProcFilter` enum; the values match the now
144+
/// deprecated implementation of `listpids`
145+
impl From<ProcType> for processes::ProcFilter {
146+
fn from(proc_type: ProcType) -> Self {
147+
use processes::ProcFilter;
148+
149+
match proc_type {
150+
ProcType::ProcAllPIDS => ProcFilter::All,
151+
ProcType::ProcPGRPOnly => ProcFilter::ByProgramGroup { pgrpid: 0 },
152+
ProcType::ProcTTYOnly => ProcFilter::ByTTY { tty: 0 },
153+
ProcType::ProcUIDOnly => ProcFilter::ByUID { uid: 0 },
154+
ProcType::ProcRUIDOnly => ProcFilter::ByRealUID { ruid: 0 },
155+
ProcType::ProcPPIDOnly => ProcFilter::ByParentProcess { ppid: 0 },
179156
}
180-
181-
Ok(pids)
182157
}
183158
}
184159

185160
/// Returns the PIDs of the active processes that match the ProcType passed in
186161
///
162+
/// # Note
163+
///
164+
/// This function is deprecated in favor of
165+
/// [`libproc::processes::pids_by_type()`][crate::processes::pids_by_type],
166+
/// which lets you specify what PGRP / TTY / UID / RUID / PPID you want to
167+
/// filter by.
168+
///
187169
/// # Examples
188170
///
189171
/// Get the list of running process IDs using `listpids`
@@ -196,70 +178,39 @@ pub fn listpids(proc_types: ProcType) -> Result<Vec<u32>, String> {
196178
/// println!("Found {} processes using listpids()", pids.len());
197179
/// }
198180
/// ```
199-
#[cfg(target_os = "linux")]
181+
#[deprecated(
182+
since = "0.13.0",
183+
note = "Please use `libproc::processes::pids_by_type()` instead."
184+
)]
200185
pub fn listpids(proc_types: ProcType) -> Result<Vec<u32>, String> {
201-
match proc_types {
202-
ProcType::ProcAllPIDS => {
203-
let mut pids = Vec::<u32>::new();
204-
205-
let proc_dir = fs::read_dir("/proc").map_err(|e| format!("Could not read '/proc': {e}"))?;
206-
207-
for entry in proc_dir {
208-
let path = entry.map_err(|_| "Couldn't get /proc/ filename")?.path();
209-
let filename = path.file_name();
210-
if let Some(name) = filename {
211-
if let Some(n) = name.to_str() {
212-
if let Ok(pid) = n.parse::<u32>() {
213-
pids.push(pid);
214-
}
215-
}
216-
}
217-
}
218-
219-
Ok(pids)
220-
}
221-
_ => Err("Unsupported ProcType".to_owned())
222-
}
186+
processes::pids_by_type(proc_types.into()).map_err(|e| {
187+
e.raw_os_error()
188+
.map_or_else(|| e.to_string(), helpers::get_errno_with_message)
189+
})
223190
}
224191

225192
/// Search through the current processes looking for open file references which match
226193
/// a specified path or volume.
194+
///
195+
/// # Note
196+
///
197+
/// This function is deprecated in favor of
198+
/// [`libproc::processes::pids_by_type_and_path()`][crate::processes::pids_by_type_and_path],
199+
/// which lets you specify what PGRP / TTY / UID / RUID / PPID you want to
200+
/// filter by.
201+
///
227202
#[cfg(target_os = "macos")]
203+
#[deprecated(
204+
since = "0.13.0",
205+
note = "Please use `libproc::processes::pids_by_type_and_path()` instead."
206+
)]
228207
pub fn listpidspath(proc_types: ProcType, path: &str) -> Result<Vec<u32>, String> {
229-
let c_path = CString::new(path).map_err(|_| "CString::new failed".to_string())?;
230-
231-
let buffer_size = unsafe {
232-
proc_listpidspath(proc_types as u32, 0, c_path.as_ptr() as * const c_char, 0, ptr::null_mut(), 0)
233-
};
234-
if buffer_size <= 0 {
235-
return Err(helpers::get_errno_with_message(buffer_size));
236-
}
237-
238-
let capacity = buffer_size as usize / mem::size_of::<u32>();
239-
let mut pids: Vec<u32> = Vec::with_capacity(capacity);
240-
let buffer_ptr = pids.as_mut_ptr() as *mut c_void;
241-
242-
let ret = unsafe {
243-
proc_listpidspath(
244-
proc_types as u32,
245-
0,
246-
c_path.as_ptr() as *const c_char,
247-
0,
248-
buffer_ptr,
249-
buffer_size,
250-
)
251-
};
252-
253-
if ret <= 0 {
254-
Err(helpers::get_errno_with_message(ret))
255-
} else {
256-
let items_count = ret as usize / mem::size_of::<u32>() - 1;
257-
unsafe {
258-
pids.set_len(items_count);
259-
}
260-
261-
Ok(pids)
262-
}
208+
processes::pids_by_type_and_path(proc_types.into(), &PathBuf::from(path), false, false).map_err(
209+
|e| {
210+
e.raw_os_error()
211+
.map_or_else(|| e.to_string(), helpers::get_errno_with_message)
212+
},
213+
)
263214
}
264215

265216
/// Get info about a process, task, thread or work queue by specifying the appropriate type for `T`:
@@ -665,10 +616,9 @@ mod test {
665616

666617
#[cfg(target_os = "macos")]
667618
use super::{libversion, listpidinfo, ListThreads, pidinfo};
668-
use super::{name, cwdself, listpids, pidpath};
619+
use super::{name, cwdself, pidpath};
669620
#[cfg(target_os = "linux")]
670621
use super::pidcwd;
671-
use crate::libproc::proc_pid::ProcType;
672622
use super::am_root;
673623
#[cfg(target_os = "linux")]
674624
use crate::libproc::helpers;
@@ -763,18 +713,6 @@ mod test {
763713
libversion().expect("libversion() failed");
764714
}
765715

766-
#[test]
767-
fn listpids_test() {
768-
let pids = listpids(ProcType::ProcAllPIDS).expect("Could not list pids");
769-
assert!(pids.len() > 1);
770-
}
771-
772-
#[test]
773-
#[cfg(target_os = "linux")]
774-
fn listpids_invalid_type_test() {
775-
assert!(listpids(ProcType::ProcPGRPOnly).is_err());
776-
}
777-
778716
#[test]
779717
fn name_test() {
780718
#[cfg(target_os = "linux")]
@@ -844,12 +782,4 @@ mod test {
844782
assert!(helpers::procfile_field("/proc/1/status", "invalid").is_err());
845783
}
846784
}
847-
848-
#[test]
849-
#[cfg(target_os = "macos")]
850-
fn listpidspath_test() {
851-
let pids = super::listpidspath(ProcType::ProcAllPIDS, "/")
852-
.expect("listpidspath() failed");
853-
assert!(pids.len() > 1);
854-
}
855785
}

0 commit comments

Comments
 (0)