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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
//! Shared process data harvesting code from macOS and FreeBSD via sysinfo.
use std::collections::HashMap;
use std::io;
use sysinfo::{CpuExt, PidExt, ProcessExt, ProcessStatus, System, SystemExt};
use super::ProcessHarvest;
use crate::{data_harvester::processes::UserTable, utils::error::Result, Pid};
pub fn get_process_data<F>(
sys: &System, use_current_cpu_total: bool, mem_total_kb: u64, user_table: &mut UserTable,
get_process_cpu_usage: F,
) -> Result<Vec<ProcessHarvest>>
where
F: Fn(&[Pid]) -> io::Result<HashMap<Pid, f64>>,
{
let mut process_vector: Vec<ProcessHarvest> = Vec::new();
let process_hashmap = sys.processes();
let cpu_usage = sys.global_cpu_info().cpu_usage() as f64 / 100.0;
let num_processors = sys.cpus().len() as f64;
for process_val in process_hashmap.values() {
let name = if process_val.name().is_empty() {
let process_cmd = process_val.cmd();
if process_cmd.len() > 1 {
process_cmd[0].clone()
} else {
let process_exe = process_val.exe().file_stem();
if let Some(exe) = process_exe {
let process_exe_opt = exe.to_str();
if let Some(exe_name) = process_exe_opt {
exe_name.to_string()
} else {
"".to_string()
}
} else {
"".to_string()
}
}
} else {
process_val.name().to_string()
};
let command = {
let command = process_val.cmd().join(" ");
if command.is_empty() {
name.to_string()
} else {
command
}
};
let pcu = {
let p = process_val.cpu_usage() as f64 / num_processors;
if p.is_nan() {
process_val.cpu_usage() as f64
} else {
p
}
};
let process_cpu_usage = if use_current_cpu_total && cpu_usage > 0.0 {
pcu / cpu_usage
} else {
pcu
};
let disk_usage = process_val.disk_usage();
let process_state = {
let ps = process_val.status();
(ps.to_string(), convert_process_status_to_char(ps))
};
let uid = process_val.user_id().map(|u| **u);
let pid = process_val.pid().as_u32() as Pid;
process_vector.push(ProcessHarvest {
pid,
parent_pid: {
#[cfg(target_os = "macos")]
{
process_val
.parent()
.map(|p| p.as_u32() as _)
.or_else(|| super::fallback_macos_ppid(pid))
}
#[cfg(not(target_os = "macos"))]
{
process_val.parent().map(|p| p.as_u32() as _)
}
},
name,
command,
mem_usage_percent: if mem_total_kb > 0 {
process_val.memory() as f64 * 100.0 / mem_total_kb as f64
} else {
0.0
},
mem_usage_bytes: process_val.memory(),
cpu_usage_percent: process_cpu_usage,
read_bytes_per_sec: disk_usage.read_bytes,
write_bytes_per_sec: disk_usage.written_bytes,
total_read_bytes: disk_usage.total_read_bytes,
total_write_bytes: disk_usage.total_written_bytes,
process_state,
uid,
user: uid
.and_then(|uid| {
user_table
.get_uid_to_username_mapping(uid)
.map(Into::into)
.ok()
})
.unwrap_or_else(|| "N/A".into()),
});
}
let unknown_state = ProcessStatus::Unknown(0).to_string();
let cpu_usage_unknown_pids: Vec<Pid> = process_vector
.iter()
.filter(|process| process.process_state.0 == unknown_state)
.map(|process| process.pid)
.collect();
let cpu_usages = get_process_cpu_usage(&cpu_usage_unknown_pids)?;
for process in &mut process_vector {
if cpu_usages.contains_key(&process.pid) {
process.cpu_usage_percent = if num_processors == 0.0 {
*cpu_usages.get(&process.pid).unwrap()
} else {
*cpu_usages.get(&process.pid).unwrap() / num_processors
};
}
}
Ok(process_vector)
}
fn convert_process_status_to_char(status: ProcessStatus) -> char {
match status {
ProcessStatus::Run => 'R',
ProcessStatus::Sleep => 'S',
ProcessStatus::Idle => 'D',
ProcessStatus::Zombie => 'Z',
_ => '?',
}
}
|