]> git.proxmox.com Git - rustc.git/blob - vendor/sysinfo/src/freebsd/utils.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / vendor / sysinfo / src / freebsd / utils.rs
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 {
101 let mut len = (mem::size_of::<T>() * value.len()) as libc::size_t;
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> {
129 let mut len = (mem::size_of::<libc::c_char>() * buf.len()) as libc::size_t;
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
172 let mut buf: Vec<libc::c_char> = vec![0; size as _];
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
213 let mut buf: Vec<libc::c_char> = vec![0; size as _];
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(
290 format!("dev.cpu.{cpu_nb}.freq\0").as_bytes(),
291 &mut frequency,
292 ) {
293 frequency = 0;
294 }
295 frequency as _
296 }