]>
Commit | Line | Data |
---|---|---|
923072b8 FG |
1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | ||
3 | use crate::{Pid, Process}; | |
4 | use libc::{c_char, c_int, timeval}; | |
5 | use std::cell::UnsafeCell; | |
6 | use std::collections::HashMap; | |
7 | use std::ffi::CStr; | |
8 | use std::mem; | |
9 | use std::time::SystemTime; | |
10 | ||
11 | /// This struct is used to switch between the "old" and "new" every time you use "get_mut". | |
12 | #[derive(Debug)] | |
13 | pub(crate) struct VecSwitcher<T> { | |
14 | v1: Vec<T>, | |
15 | v2: Vec<T>, | |
16 | first: bool, | |
17 | } | |
18 | ||
19 | impl<T: Clone> VecSwitcher<T> { | |
20 | pub fn new(v1: Vec<T>) -> Self { | |
21 | let v2 = v1.clone(); | |
22 | ||
23 | Self { | |
24 | v1, | |
25 | v2, | |
26 | first: true, | |
27 | } | |
28 | } | |
29 | ||
30 | pub fn get_mut(&mut self) -> &mut [T] { | |
31 | self.first = !self.first; | |
32 | if self.first { | |
33 | // It means that `v2` will be the "new". | |
34 | &mut self.v2 | |
35 | } else { | |
36 | // It means that `v1` will be the "new". | |
37 | &mut self.v1 | |
38 | } | |
39 | } | |
40 | ||
41 | pub fn get_old(&self) -> &[T] { | |
42 | if self.first { | |
43 | &self.v1 | |
44 | } else { | |
45 | &self.v2 | |
46 | } | |
47 | } | |
48 | ||
49 | pub fn get_new(&self) -> &[T] { | |
50 | if self.first { | |
51 | &self.v2 | |
52 | } else { | |
53 | &self.v1 | |
54 | } | |
55 | } | |
56 | } | |
57 | ||
58 | #[inline] | |
59 | pub unsafe fn init_mib(name: &[u8], mib: &mut [c_int]) { | |
60 | let mut len = mib.len(); | |
61 | libc::sysctlnametomib(name.as_ptr() as _, mib.as_mut_ptr(), &mut len); | |
62 | } | |
63 | ||
64 | pub(crate) fn boot_time() -> u64 { | |
65 | let mut boot_time = timeval { | |
66 | tv_sec: 0, | |
67 | tv_usec: 0, | |
68 | }; | |
69 | let mut len = std::mem::size_of::<timeval>(); | |
70 | let mut mib: [c_int; 2] = [libc::CTL_KERN, libc::KERN_BOOTTIME]; | |
71 | unsafe { | |
72 | if libc::sysctl( | |
73 | mib.as_mut_ptr(), | |
74 | mib.len() as _, | |
75 | &mut boot_time as *mut timeval as *mut _, | |
76 | &mut len, | |
77 | std::ptr::null_mut(), | |
78 | 0, | |
79 | ) < 0 | |
80 | { | |
81 | 0 | |
82 | } else { | |
83 | boot_time.tv_sec as _ | |
84 | } | |
85 | } | |
86 | } | |
87 | ||
88 | pub(crate) unsafe fn get_sys_value<T: Sized>(mib: &[c_int], value: &mut T) -> bool { | |
89 | let mut len = mem::size_of::<T>() as libc::size_t; | |
90 | libc::sysctl( | |
91 | mib.as_ptr(), | |
92 | mib.len() as _, | |
93 | value as *mut _ as *mut _, | |
94 | &mut len, | |
95 | std::ptr::null_mut(), | |
96 | 0, | |
97 | ) == 0 | |
98 | } | |
99 | ||
100 | pub(crate) unsafe fn get_sys_value_array<T: Sized>(mib: &[c_int], value: &mut [T]) -> bool { | |
add651ee | 101 | let mut len = mem::size_of_val(value) as libc::size_t; |
923072b8 FG |
102 | libc::sysctl( |
103 | mib.as_ptr(), | |
104 | mib.len() as _, | |
105 | value.as_mut_ptr() as *mut _, | |
106 | &mut len as *mut _, | |
107 | std::ptr::null_mut(), | |
108 | 0, | |
109 | ) == 0 | |
110 | } | |
111 | ||
112 | pub(crate) fn c_buf_to_str(buf: &[libc::c_char]) -> Option<&str> { | |
113 | unsafe { | |
114 | let buf: &[u8] = std::slice::from_raw_parts(buf.as_ptr() as _, buf.len()); | |
115 | if let Some(pos) = buf.iter().position(|x| *x == 0) { | |
116 | // Shrink buffer to terminate the null bytes | |
117 | std::str::from_utf8(&buf[..pos]).ok() | |
118 | } else { | |
119 | std::str::from_utf8(buf).ok() | |
120 | } | |
121 | } | |
122 | } | |
123 | ||
124 | pub(crate) fn c_buf_to_string(buf: &[libc::c_char]) -> Option<String> { | |
125 | c_buf_to_str(buf).map(|s| s.to_owned()) | |
126 | } | |
127 | ||
128 | pub(crate) unsafe fn get_sys_value_str(mib: &[c_int], buf: &mut [libc::c_char]) -> Option<String> { | |
add651ee | 129 | let mut len = mem::size_of_val(buf) as libc::size_t; |
923072b8 FG |
130 | if libc::sysctl( |
131 | mib.as_ptr(), | |
132 | mib.len() as _, | |
133 | buf.as_mut_ptr() as *mut _, | |
134 | &mut len, | |
135 | std::ptr::null_mut(), | |
136 | 0, | |
137 | ) != 0 | |
138 | { | |
139 | return None; | |
140 | } | |
141 | c_buf_to_string(&buf[..len / mem::size_of::<libc::c_char>()]) | |
142 | } | |
143 | ||
144 | pub(crate) unsafe fn get_sys_value_by_name<T: Sized>(name: &[u8], value: &mut T) -> bool { | |
145 | let mut len = mem::size_of::<T>() as libc::size_t; | |
146 | let original = len; | |
147 | ||
148 | libc::sysctlbyname( | |
149 | name.as_ptr() as *const c_char, | |
150 | value as *mut _ as *mut _, | |
151 | &mut len, | |
152 | std::ptr::null_mut(), | |
153 | 0, | |
154 | ) == 0 | |
155 | && original == len | |
156 | } | |
157 | ||
158 | pub(crate) fn get_sys_value_str_by_name(name: &[u8]) -> Option<String> { | |
159 | let mut size = 0; | |
160 | ||
161 | unsafe { | |
162 | if libc::sysctlbyname( | |
163 | name.as_ptr() as *const c_char, | |
164 | std::ptr::null_mut(), | |
165 | &mut size, | |
166 | std::ptr::null_mut(), | |
167 | 0, | |
168 | ) == 0 | |
169 | && size > 0 | |
170 | { | |
171 | // now create a buffer with the size and get the real value | |
487cf647 | 172 | let mut buf: Vec<libc::c_char> = vec![0; size as _]; |
923072b8 FG |
173 | |
174 | if libc::sysctlbyname( | |
175 | name.as_ptr() as *const c_char, | |
176 | buf.as_mut_ptr() as *mut _, | |
177 | &mut size, | |
178 | std::ptr::null_mut(), | |
179 | 0, | |
180 | ) == 0 | |
181 | && size > 0 | |
182 | { | |
183 | c_buf_to_string(&buf) | |
184 | } else { | |
185 | // getting the system value failed | |
186 | None | |
187 | } | |
188 | } else { | |
189 | None | |
190 | } | |
191 | } | |
192 | } | |
193 | ||
194 | pub(crate) fn get_system_info(mib: &[c_int], default: Option<&str>) -> Option<String> { | |
195 | let mut size = 0; | |
196 | ||
197 | unsafe { | |
198 | // Call first to get size | |
199 | libc::sysctl( | |
200 | mib.as_ptr(), | |
201 | mib.len() as _, | |
202 | std::ptr::null_mut(), | |
203 | &mut size, | |
204 | std::ptr::null_mut(), | |
205 | 0, | |
206 | ); | |
207 | ||
208 | // exit early if we did not update the size | |
209 | if size == 0 { | |
210 | default.map(|s| s.to_owned()) | |
211 | } else { | |
212 | // set the buffer to the correct size | |
487cf647 | 213 | let mut buf: Vec<libc::c_char> = vec![0; size as _]; |
923072b8 FG |
214 | |
215 | if libc::sysctl( | |
216 | mib.as_ptr(), | |
217 | mib.len() as _, | |
218 | buf.as_mut_ptr() as _, | |
219 | &mut size, | |
220 | std::ptr::null_mut(), | |
221 | 0, | |
222 | ) == -1 | |
223 | { | |
224 | // If command fails return default | |
225 | default.map(|s| s.to_owned()) | |
226 | } else { | |
227 | c_buf_to_string(&buf) | |
228 | } | |
229 | } | |
230 | } | |
231 | } | |
232 | ||
233 | pub(crate) unsafe fn from_cstr_array(ptr: *const *const c_char) -> Vec<String> { | |
234 | if ptr.is_null() { | |
235 | return Vec::new(); | |
236 | } | |
237 | let mut max = 0; | |
238 | loop { | |
239 | let ptr = ptr.add(max); | |
240 | if (*ptr).is_null() { | |
241 | break; | |
242 | } | |
243 | max += 1; | |
244 | } | |
245 | if max == 0 { | |
246 | return Vec::new(); | |
247 | } | |
248 | let mut ret = Vec::with_capacity(max); | |
249 | ||
250 | for pos in 0..max { | |
251 | let p = ptr.add(pos); | |
252 | if let Ok(s) = CStr::from_ptr(*p).to_str() { | |
253 | ret.push(s.to_owned()); | |
254 | } | |
255 | } | |
256 | ret | |
257 | } | |
258 | ||
259 | pub(crate) fn get_now() -> u64 { | |
260 | SystemTime::now() | |
261 | .duration_since(SystemTime::UNIX_EPOCH) | |
262 | .map(|n| n.as_secs()) | |
263 | .unwrap_or(0) | |
264 | } | |
265 | ||
266 | // All this is needed because `kinfo_proc` doesn't implement `Send` (because it contains pointers). | |
267 | pub(crate) struct WrapMap<'a>(pub UnsafeCell<&'a mut HashMap<Pid, Process>>); | |
268 | ||
269 | unsafe impl<'a> Send for WrapMap<'a> {} | |
270 | unsafe impl<'a> Sync for WrapMap<'a> {} | |
271 | ||
272 | #[repr(transparent)] | |
273 | pub(crate) struct KInfoProc(libc::kinfo_proc); | |
274 | unsafe impl Send for KInfoProc {} | |
275 | unsafe impl Sync for KInfoProc {} | |
276 | ||
277 | impl std::ops::Deref for KInfoProc { | |
278 | type Target = libc::kinfo_proc; | |
279 | ||
280 | fn deref(&self) -> &Self::Target { | |
281 | &self.0 | |
282 | } | |
283 | } | |
284 | ||
285 | pub(crate) unsafe fn get_frequency_for_cpu(cpu_nb: c_int) -> u64 { | |
286 | let mut frequency = 0; | |
287 | ||
288 | // The information can be missing if it's running inside a VM. | |
289 | if !get_sys_value_by_name( | |
487cf647 | 290 | format!("dev.cpu.{cpu_nb}.freq\0").as_bytes(), |
923072b8 FG |
291 | &mut frequency, |
292 | ) { | |
293 | frequency = 0; | |
294 | } | |
295 | frequency as _ | |
296 | } |