-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathunix.rs
84 lines (69 loc) · 2.06 KB
/
unix.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#![cfg(unix)]
use crate::{
errors::{Error, ProcessInfoError, Result},
shell::Shell,
};
use std::{
io::{BufRead, BufReader},
process::{self, Command, Stdio},
};
use super::Infer;
const MAX_DEPTH: u8 = 30;
struct ProcessInfo {
ppid: Option<u32>,
command: String,
}
impl Infer {
pub fn infer() -> Result<Shell> {
let mut pid = Some(process::id());
let mut depth = 0;
while let Some(current_pid) = pid {
if depth > MAX_DEPTH {
return Err(Error::NoShellFound);
}
let proc_info = get_process_info(current_pid)?;
let filename = proc_info
.command
.trim_start_matches('-')
.split('/')
.last()
.ok_or_else(|| Error::NoBinary(proc_info.command.clone()))?;
if let Ok(shell) = filename.parse() {
return Ok(shell);
}
pid = proc_info.ppid;
depth += 1;
}
Err(Error::NoShellFound)
}
}
fn get_process_info(pid: u32) -> Result<ProcessInfo, ProcessInfoError> {
let stdout = Command::new("ps")
.args(["-o", "ppid,comm", pid.to_string().as_str()])
.stdout(Stdio::piped())
.spawn()?
.stdout
.ok_or_else(|| ProcessInfoError::UnexpectedEof)?;
let mut stdout_lines = BufReader::new(stdout).lines();
let line = stdout_lines
.nth(1)
.transpose()?
.ok_or_else(|| ProcessInfoError::UnexpectedEof)?;
let mut parts = line.split_whitespace();
let ppid = parts
.next()
.ok_or_else(|| ProcessInfoError::UnexpectedOutput {
msg: "ppid should be the first item in table",
output: line.to_string(),
})?;
let command = parts
.next()
.ok_or_else(|| ProcessInfoError::UnexpectedOutput {
msg: "command should be the second item in table",
output: line.to_string(),
})?;
Ok(ProcessInfo {
ppid: ppid.parse().ok(),
command: command.to_string(),
})
}