Last active
September 25, 2018 05:04
-
-
Save FreeMasen/909f2ed04cab2bd960ea68714e9199b6 to your computer and use it in GitHub Desktop.
Revisions
-
FreeMasen revised this gist
Sep 21, 2018 . No changes.There are no files selected for viewing
-
FreeMasen created this gist
Sep 21, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,7 @@ [package] name = "getpid" version = "0.1.0" [dependencies] walkdir = "1" docopt = "2" This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,80 @@ extern crate docopt; #[cfg(not(target_os = "macos"))] extern crate walkdir; #[cfg(not(target_os = "macos"))] use walkdir::Walkdir; #[cfg(not(target_os = "macos"))] use docopt::DocOpt; #[cfg(target_os = "macos")] mod bindings; #[cfg(target_os = "macos")] mod sysctl; #[cfg(target_os = "macos")] use sysctl::get_processes; static HELP: &str = " GET PID a tool for getting a pid for a running process.DocError Usage: getpid <name> getpid [--help|-h] Options: name The name of the executable running --help -h print this message "; #[derive(Deserialize)] struct Args { arg_name: String, } fn main() -> Result<(), Error> { //parse the command line arguments //and exit with help text if fails let args: Args = Docopt::new(HELP) .and_then(|d| d.deserialize()) .unwrap_or_else(|e| e.exit()); //if the arg is an empty string //show the help text and exit if args.arg_name == String::new() { println!("{}", HELP); ::std::process::exit(0); } //get the matches and keep only those //with a matching name let matches = get_processes().filter(|p| p.1 == args.arg_name); if matches.len() < 1 { //if no matches were found //print this message to stderr eprintln!("No process found") } else if matches.len() > 1 { //if more than one match was found //print this message to stderr eprintln!("More than one process with that name"); } else { println!("{}", matches[0].0) } } #[cfg(not(target_os = "macos"))] fn get_processes() -> Vec<(String, String)> { WalkDir::new("/proc").min_depth(1).max_depth(1).filter_map(process_entry).collect() } #[cfg(not(target_os = "macos"))] fn process_entry(entry: Result<Entry, walkdir::Error>) -> Option<(String, String)> { //pull the actual entry out of the result //returning None if it fails let entry = entry.ok()?; //if the entry isn't a directory, skip it if !entry.file_type().is_dir() { return None; } //try and convert the file name from an OsStr into an &str //returning None if it fails let pid = entry.file_name().to_str().ok()?.to_string(); //read the contents of the comm file to a string //returning None if it fails let comm = ::std::io::read_to_string(entry.path().join("comm")).ok()?; Some((pid, comm)) } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,85 @@ #![cfg(target_os = "macos")] use bindings::{kinfo_proc, sysctl}; pub fn get_processes() -> Vec<(String, String)> { // this resolves in sysctl to kern.procs.all let mut name: [i32; 4] = [1, 14, 0, 0]; // We will need this a few times to into a variable let name_len: u32 = 4; // This will be the length of bytes returned //for our Vec let mut len = 0; let mut err: i32 = unsafe { sysctl( //First argument is the name as a pointer name.as_mut_ptr(), //Next is the length of that name name_len, //Here we are sending a pointer to NULL ::std::ptr::null_mut(), //This value will hold our return value &mut len, //Here we are again sending a pointer to NULL ::std::ptr::null_mut(), //The last argument is 0 0 ) }; //if this is > 0 we have encountered an error if err > 0 { eprintln!("Error getting length of list: {}", err); return vec![]; } //This should be the number of elements returned let expecting = len / ::std::mem::size_of::<kinfo_proc>(); //This is the shape our vec let layout = ::std::alloc::Layout::new::<Vec<kinfo_proc>>(); //Allocate the raw memory for our vec let ptr = unsafe { ::std::alloc::alloc_zeroed(layout) }; let mut list: Vec<kinfo_proc> = unsafe { //Now create the vec with our length and capacity both set to the //calculation we did before Vec::from_raw_parts(ptr as *mut kinfo_proc, expecting, expecting) }; err = unsafe { sysctl( //the same name name.as_mut_ptr(), //the same length name_len, //We swapped a null pointer for a pointer to our // Vec, cast as void * list.as_mut_ptr() as *mut ::std::os::raw::c_void, // This will get repopulated &mut len, //the same null pointer ::std::ptr::null_mut(), //again 0 0, ) }; if err != 0 { eprintln!("Error getting kinfo_proc list: {}", err); return vec![]; } list.iter().map(|p| { let name = parse_c_str(&p.kp_proc.p_comm); let pid = format!("{}", p.kp_proc.p_pid); (pid, name) }).collect() } fn parse_c_str(c_str: &[i8]) -> String { let mut bytes = vec![]; for byte in c_str { if *byte as u8 == '\u{0}' as u8 { break; } else { bytes.push(*byte as u8); } } String::from_utf8_lossy(&bytes).to_string() } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ #include <sys/sysctl>