summaryrefslogtreecommitdiffstats
path: root/vendor/sysinfo/src/apple
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/sysinfo/src/apple
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/sysinfo/src/apple')
-rw-r--r--vendor/sysinfo/src/apple/app_store/component.rs26
-rw-r--r--vendor/sysinfo/src/apple/app_store/mod.rs4
-rw-r--r--vendor/sysinfo/src/apple/app_store/process.rs82
-rw-r--r--vendor/sysinfo/src/apple/component.rs3
-rw-r--r--vendor/sysinfo/src/apple/cpu.rs331
-rw-r--r--vendor/sysinfo/src/apple/disk.rs66
-rw-r--r--vendor/sysinfo/src/apple/ffi.rs28
-rw-r--r--vendor/sysinfo/src/apple/ios.rs5
-rw-r--r--vendor/sysinfo/src/apple/macos/component.rs221
-rw-r--r--vendor/sysinfo/src/apple/macos/disk.rs199
-rw-r--r--vendor/sysinfo/src/apple/macos/ffi.rs156
-rw-r--r--vendor/sysinfo/src/apple/macos/mod.rs17
-rw-r--r--vendor/sysinfo/src/apple/macos/process.rs643
-rw-r--r--vendor/sysinfo/src/apple/macos/system.rs136
-rw-r--r--vendor/sysinfo/src/apple/mod.rs31
-rw-r--r--vendor/sysinfo/src/apple/network.rs239
-rw-r--r--vendor/sysinfo/src/apple/process.rs83
-rw-r--r--vendor/sysinfo/src/apple/system.rs763
-rw-r--r--vendor/sysinfo/src/apple/users.rs178
-rw-r--r--vendor/sysinfo/src/apple/utils.rs39
20 files changed, 3250 insertions, 0 deletions
diff --git a/vendor/sysinfo/src/apple/app_store/component.rs b/vendor/sysinfo/src/apple/app_store/component.rs
new file mode 100644
index 000000000..914fc9406
--- /dev/null
+++ b/vendor/sysinfo/src/apple/app_store/component.rs
@@ -0,0 +1,26 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::ComponentExt;
+
+#[doc = include_str!("../../../md_doc/component.md")]
+pub struct Component {}
+
+impl ComponentExt for Component {
+ fn temperature(&self) -> f32 {
+ 0.0
+ }
+
+ fn max(&self) -> f32 {
+ 0.0
+ }
+
+ fn critical(&self) -> Option<f32> {
+ None
+ }
+
+ fn label(&self) -> &str {
+ ""
+ }
+
+ fn refresh(&mut self) {}
+}
diff --git a/vendor/sysinfo/src/apple/app_store/mod.rs b/vendor/sysinfo/src/apple/app_store/mod.rs
new file mode 100644
index 000000000..0df24cabf
--- /dev/null
+++ b/vendor/sysinfo/src/apple/app_store/mod.rs
@@ -0,0 +1,4 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+pub mod component;
+pub mod process;
diff --git a/vendor/sysinfo/src/apple/app_store/process.rs b/vendor/sysinfo/src/apple/app_store/process.rs
new file mode 100644
index 000000000..8c3348ee9
--- /dev/null
+++ b/vendor/sysinfo/src/apple/app_store/process.rs
@@ -0,0 +1,82 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use std::path::Path;
+
+use crate::{DiskUsage, Gid, Pid, ProcessExt, ProcessStatus, Signal, Uid};
+
+#[doc = include_str!("../../../md_doc/process.md")]
+pub struct Process;
+
+impl ProcessExt for Process {
+ fn kill_with(&self, _signal: Signal) -> Option<bool> {
+ None
+ }
+
+ fn name(&self) -> &str {
+ ""
+ }
+
+ fn cmd(&self) -> &[String] {
+ &[]
+ }
+
+ fn exe(&self) -> &Path {
+ Path::new("/")
+ }
+
+ fn pid(&self) -> Pid {
+ Pid(0)
+ }
+
+ fn environ(&self) -> &[String] {
+ &[]
+ }
+
+ fn cwd(&self) -> &Path {
+ Path::new("/")
+ }
+
+ fn root(&self) -> &Path {
+ Path::new("/")
+ }
+
+ fn memory(&self) -> u64 {
+ 0
+ }
+
+ fn virtual_memory(&self) -> u64 {
+ 0
+ }
+
+ fn parent(&self) -> Option<Pid> {
+ None
+ }
+
+ fn status(&self) -> ProcessStatus {
+ ProcessStatus::Unknown(0)
+ }
+
+ fn start_time(&self) -> u64 {
+ 0
+ }
+
+ fn run_time(&self) -> u64 {
+ 0
+ }
+
+ fn cpu_usage(&self) -> f32 {
+ 0.0
+ }
+
+ fn disk_usage(&self) -> DiskUsage {
+ DiskUsage::default()
+ }
+
+ fn user_id(&self) -> Option<&Uid> {
+ None
+ }
+
+ fn group_id(&self) -> Option<Gid> {
+ None
+ }
+}
diff --git a/vendor/sysinfo/src/apple/component.rs b/vendor/sysinfo/src/apple/component.rs
new file mode 100644
index 000000000..7c4196e72
--- /dev/null
+++ b/vendor/sysinfo/src/apple/component.rs
@@ -0,0 +1,3 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+pub use crate::sys::inner::component::*;
diff --git a/vendor/sysinfo/src/apple/cpu.rs b/vendor/sysinfo/src/apple/cpu.rs
new file mode 100644
index 000000000..b1068e971
--- /dev/null
+++ b/vendor/sysinfo/src/apple/cpu.rs
@@ -0,0 +1,331 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::sys::system::get_sys_value;
+
+use crate::{CpuExt, CpuRefreshKind};
+
+use libc::{c_char, host_processor_info, mach_task_self};
+use std::mem;
+use std::ops::Deref;
+use std::sync::Arc;
+
+pub(crate) struct UnsafePtr<T>(*mut T);
+
+unsafe impl<T> Send for UnsafePtr<T> {}
+unsafe impl<T> Sync for UnsafePtr<T> {}
+
+impl<T> Deref for UnsafePtr<T> {
+ type Target = *mut T;
+
+ fn deref(&self) -> &*mut T {
+ &self.0
+ }
+}
+
+pub(crate) struct CpuData {
+ pub cpu_info: UnsafePtr<i32>,
+ pub num_cpu_info: u32,
+}
+
+impl CpuData {
+ pub fn new(cpu_info: *mut i32, num_cpu_info: u32) -> CpuData {
+ CpuData {
+ cpu_info: UnsafePtr(cpu_info),
+ num_cpu_info,
+ }
+ }
+}
+
+impl Drop for CpuData {
+ fn drop(&mut self) {
+ if !self.cpu_info.0.is_null() {
+ let prev_cpu_info_size = std::mem::size_of::<i32>() as u32 * self.num_cpu_info;
+ unsafe {
+ libc::vm_deallocate(
+ mach_task_self(),
+ self.cpu_info.0 as _,
+ prev_cpu_info_size as _,
+ );
+ }
+ self.cpu_info.0 = std::ptr::null_mut();
+ }
+ }
+}
+
+#[doc = include_str!("../../md_doc/cpu.md")]
+pub struct Cpu {
+ name: String,
+ cpu_usage: f32,
+ cpu_data: Arc<CpuData>,
+ frequency: u64,
+ vendor_id: String,
+ brand: String,
+}
+
+impl Cpu {
+ pub(crate) fn new(
+ name: String,
+ cpu_data: Arc<CpuData>,
+ frequency: u64,
+ vendor_id: String,
+ brand: String,
+ ) -> Cpu {
+ Cpu {
+ name,
+ cpu_usage: 0f32,
+ cpu_data,
+ frequency,
+ vendor_id,
+ brand,
+ }
+ }
+
+ pub(crate) fn set_cpu_usage(&mut self, cpu_usage: f32) {
+ self.cpu_usage = cpu_usage;
+ }
+
+ pub(crate) fn update(&mut self, cpu_usage: f32, cpu_data: Arc<CpuData>) {
+ self.cpu_usage = cpu_usage;
+ self.cpu_data = cpu_data;
+ }
+
+ pub(crate) fn data(&self) -> Arc<CpuData> {
+ Arc::clone(&self.cpu_data)
+ }
+
+ pub(crate) fn set_frequency(&mut self, frequency: u64) {
+ self.frequency = frequency;
+ }
+}
+
+impl CpuExt for Cpu {
+ fn cpu_usage(&self) -> f32 {
+ self.cpu_usage
+ }
+
+ fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Returns the CPU frequency in MHz.
+ fn frequency(&self) -> u64 {
+ self.frequency
+ }
+
+ fn vendor_id(&self) -> &str {
+ &self.vendor_id
+ }
+
+ fn brand(&self) -> &str {
+ &self.brand
+ }
+}
+
+pub(crate) fn get_cpu_frequency() -> u64 {
+ let mut speed: u64 = 0;
+ let mut len = std::mem::size_of::<u64>();
+ unsafe {
+ libc::sysctlbyname(
+ b"hw.cpufrequency\0".as_ptr() as *const c_char,
+ &mut speed as *mut _ as _,
+ &mut len,
+ std::ptr::null_mut(),
+ 0,
+ );
+ speed / 1_000_000
+ }
+}
+
+#[inline]
+fn get_in_use(cpu_info: *mut i32, offset: isize) -> i32 {
+ unsafe {
+ *cpu_info.offset(offset + libc::CPU_STATE_USER as isize)
+ + *cpu_info.offset(offset + libc::CPU_STATE_SYSTEM as isize)
+ + *cpu_info.offset(offset + libc::CPU_STATE_NICE as isize)
+ }
+}
+
+#[inline]
+fn get_idle(cpu_info: *mut i32, offset: isize) -> i32 {
+ unsafe { *cpu_info.offset(offset + libc::CPU_STATE_IDLE as isize) }
+}
+
+pub(crate) fn compute_usage_of_cpu(proc_: &Cpu, cpu_info: *mut i32, offset: isize) -> f32 {
+ let old_cpu_info = proc_.data().cpu_info.0;
+ let in_use;
+ let total;
+
+ // In case we are initializing cpus, there is no "old value" yet.
+ if old_cpu_info == cpu_info {
+ in_use = get_in_use(cpu_info, offset);
+ total = in_use + get_idle(cpu_info, offset);
+ } else {
+ in_use = get_in_use(cpu_info, offset) - get_in_use(old_cpu_info, offset);
+ total = in_use + (get_idle(cpu_info, offset) - get_idle(old_cpu_info, offset));
+ }
+ in_use as f32 / total as f32 * 100.
+}
+
+pub(crate) fn update_cpu_usage<F: FnOnce(Arc<CpuData>, *mut i32) -> (f32, usize)>(
+ port: libc::mach_port_t,
+ global_cpu: &mut Cpu,
+ f: F,
+) {
+ let mut num_cpu_u = 0u32;
+ let mut cpu_info: *mut i32 = std::ptr::null_mut();
+ let mut num_cpu_info = 0u32;
+
+ let mut total_cpu_usage = 0f32;
+
+ unsafe {
+ if host_processor_info(
+ port,
+ libc::PROCESSOR_CPU_LOAD_INFO,
+ &mut num_cpu_u as *mut u32,
+ &mut cpu_info as *mut *mut i32,
+ &mut num_cpu_info as *mut u32,
+ ) == libc::KERN_SUCCESS
+ {
+ let (total_percentage, len) =
+ f(Arc::new(CpuData::new(cpu_info, num_cpu_info)), cpu_info);
+ total_cpu_usage = total_percentage / len as f32;
+ }
+ global_cpu.set_cpu_usage(total_cpu_usage);
+ }
+}
+
+pub(crate) fn init_cpus(
+ port: libc::mach_port_t,
+ cpus: &mut Vec<Cpu>,
+ global_cpu: &mut Cpu,
+ refresh_kind: CpuRefreshKind,
+) {
+ let mut num_cpu = 0;
+ let mut mib = [0, 0];
+
+ let (vendor_id, brand) = get_vendor_id_and_brand();
+ let frequency = if refresh_kind.frequency() {
+ get_cpu_frequency()
+ } else {
+ 0
+ };
+
+ unsafe {
+ if !get_sys_value(
+ libc::CTL_HW as _,
+ libc::HW_NCPU as _,
+ mem::size_of::<u32>(),
+ &mut num_cpu as *mut _ as *mut _,
+ &mut mib,
+ ) {
+ num_cpu = 1;
+ }
+ }
+ update_cpu_usage(port, global_cpu, |proc_data, cpu_info| {
+ let mut percentage = 0f32;
+ let mut offset = 0;
+ for i in 0..num_cpu {
+ let mut p = Cpu::new(
+ format!("{}", i + 1),
+ Arc::clone(&proc_data),
+ frequency,
+ vendor_id.clone(),
+ brand.clone(),
+ );
+ if refresh_kind.cpu_usage() {
+ let cpu_usage = compute_usage_of_cpu(&p, cpu_info, offset);
+ p.set_cpu_usage(cpu_usage);
+ percentage += p.cpu_usage();
+ }
+ cpus.push(p);
+
+ offset += libc::CPU_STATE_MAX as isize;
+ }
+ (percentage, cpus.len())
+ });
+
+ // We didn't set them above to avoid cloning them unnecessarily.
+ global_cpu.brand = brand;
+ global_cpu.vendor_id = vendor_id;
+ global_cpu.frequency = frequency;
+}
+
+fn get_sysctl_str(s: &[u8]) -> String {
+ let mut len = 0;
+
+ unsafe {
+ libc::sysctlbyname(
+ s.as_ptr() as *const c_char,
+ std::ptr::null_mut(),
+ &mut len,
+ std::ptr::null_mut(),
+ 0,
+ );
+ if len < 1 {
+ return String::new();
+ }
+
+ let mut buf = Vec::with_capacity(len);
+ libc::sysctlbyname(
+ s.as_ptr() as *const c_char,
+ buf.as_mut_ptr() as _,
+ &mut len,
+ std::ptr::null_mut(),
+ 0,
+ );
+ if len > 0 {
+ buf.set_len(len);
+ while buf.last() == Some(&b'\0') {
+ buf.pop();
+ }
+ String::from_utf8(buf).unwrap_or_else(|_| String::new())
+ } else {
+ String::new()
+ }
+ }
+}
+
+pub(crate) fn get_vendor_id_and_brand() -> (String, String) {
+ // On apple M1, `sysctl machdep.cpu.vendor` returns "", so fallback to "Apple" if the result
+ // is empty.
+ let mut vendor = get_sysctl_str(b"machdep.cpu.vendor\0");
+ if vendor.is_empty() {
+ vendor = "Apple".to_string();
+ }
+
+ (vendor, get_sysctl_str(b"machdep.cpu.brand_string\0"))
+}
+
+#[cfg(test)]
+mod test {
+ use crate::*;
+ use std::process::Command;
+
+ #[test]
+ fn check_vendor_and_brand() {
+ let child = Command::new("sysctl")
+ .arg("-a")
+ .output()
+ .expect("Failed to start command...");
+
+ assert!(child.status.success());
+ let stdout = String::from_utf8(child.stdout).expect("Not valid UTF8");
+
+ let sys = System::new_with_specifics(
+ crate::RefreshKind::new().with_cpu(CpuRefreshKind::new().with_cpu_usage()),
+ );
+ let cpus = sys.cpus();
+ assert!(!cpus.is_empty(), "no CPU found");
+ if let Some(line) = stdout.lines().find(|l| l.contains("machdep.cpu.vendor")) {
+ let sysctl_value = line.split(":").skip(1).next().unwrap();
+ assert_eq!(cpus[0].vendor_id(), sysctl_value.trim());
+ }
+ if let Some(line) = stdout
+ .lines()
+ .find(|l| l.contains("machdep.cpu.brand_string"))
+ {
+ let sysctl_value = line.split(":").skip(1).next().unwrap();
+ assert_eq!(cpus[0].brand(), sysctl_value.trim());
+ }
+ }
+}
diff --git a/vendor/sysinfo/src/apple/disk.rs b/vendor/sysinfo/src/apple/disk.rs
new file mode 100644
index 000000000..9f0b4a3a3
--- /dev/null
+++ b/vendor/sysinfo/src/apple/disk.rs
@@ -0,0 +1,66 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::utils::to_cpath;
+use crate::{DiskExt, DiskType};
+
+#[cfg(target_os = "macos")]
+pub(crate) use crate::sys::inner::disk::*;
+
+use libc::statfs;
+use std::ffi::{OsStr, OsString};
+use std::mem;
+use std::path::{Path, PathBuf};
+
+#[doc = include_str!("../../md_doc/disk.md")]
+pub struct Disk {
+ pub(crate) type_: DiskType,
+ pub(crate) name: OsString,
+ pub(crate) file_system: Vec<u8>,
+ pub(crate) mount_point: PathBuf,
+ pub(crate) total_space: u64,
+ pub(crate) available_space: u64,
+ pub(crate) is_removable: bool,
+}
+
+impl DiskExt for Disk {
+ fn type_(&self) -> DiskType {
+ self.type_
+ }
+
+ fn name(&self) -> &OsStr {
+ &self.name
+ }
+
+ fn file_system(&self) -> &[u8] {
+ &self.file_system
+ }
+
+ fn mount_point(&self) -> &Path {
+ &self.mount_point
+ }
+
+ fn total_space(&self) -> u64 {
+ self.total_space
+ }
+
+ fn available_space(&self) -> u64 {
+ self.available_space
+ }
+
+ fn is_removable(&self) -> bool {
+ self.is_removable
+ }
+
+ fn refresh(&mut self) -> bool {
+ unsafe {
+ let mut stat: statfs = mem::zeroed();
+ let mount_point_cpath = to_cpath(&self.mount_point);
+ if statfs(mount_point_cpath.as_ptr() as *const i8, &mut stat) == 0 {
+ self.available_space = u64::from(stat.f_bsize).saturating_mul(stat.f_bavail);
+ true
+ } else {
+ false
+ }
+ }
+ }
+}
diff --git a/vendor/sysinfo/src/apple/ffi.rs b/vendor/sysinfo/src/apple/ffi.rs
new file mode 100644
index 000000000..7a8248537
--- /dev/null
+++ b/vendor/sysinfo/src/apple/ffi.rs
@@ -0,0 +1,28 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use libc::c_void;
+
+// Reexport items defined in either macos or ios ffi module.
+pub use crate::sys::inner::ffi::*;
+
+#[repr(C)]
+pub struct __DADisk(c_void);
+#[repr(C)]
+pub struct __DASession(c_void);
+
+// #[allow(non_camel_case_types)]
+// pub type io_name_t = [u8; 128];
+// #[allow(non_camel_case_types)]
+// pub type io_registry_entry_t = io_object_t;
+
+// pub type IOOptionBits = u32;
+
+#[cfg_attr(feature = "debug", derive(Eq, Hash, PartialEq))]
+#[derive(Clone)]
+#[repr(C)]
+pub struct Val_t {
+ pub key: [i8; 5],
+ pub data_size: u32,
+ pub data_type: [i8; 5], // UInt32Char_t
+ pub bytes: [i8; 32], // SMCBytes_t
+}
diff --git a/vendor/sysinfo/src/apple/ios.rs b/vendor/sysinfo/src/apple/ios.rs
new file mode 100644
index 000000000..0393c5ec6
--- /dev/null
+++ b/vendor/sysinfo/src/apple/ios.rs
@@ -0,0 +1,5 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+pub mod ffi {}
+pub use crate::sys::app_store::component;
+pub use crate::sys::app_store::process;
diff --git a/vendor/sysinfo/src/apple/macos/component.rs b/vendor/sysinfo/src/apple/macos/component.rs
new file mode 100644
index 000000000..384efb950
--- /dev/null
+++ b/vendor/sysinfo/src/apple/macos/component.rs
@@ -0,0 +1,221 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::sys::ffi;
+use crate::ComponentExt;
+
+use libc::{c_char, c_int, c_void};
+
+use std::mem;
+
+pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[
+ ("PECI CPU", &['T' as i8, 'C' as i8, 'X' as i8, 'C' as i8]), // PECI CPU "TCXC"
+ ("PECI CPU", &['T' as i8, 'C' as i8, 'X' as i8, 'c' as i8]), // PECI CPU "TCXc"
+ (
+ "CPU Proximity",
+ &['T' as i8, 'C' as i8, '0' as i8, 'P' as i8],
+ ), // CPU Proximity (heat spreader) "TC0P"
+ ("GPU", &['T' as i8, 'G' as i8, '0' as i8, 'P' as i8]), // GPU "TG0P"
+ ("Battery", &['T' as i8, 'B' as i8, '0' as i8, 'T' as i8]), // Battery "TB0T"
+];
+
+pub(crate) struct ComponentFFI {
+ input_structure: ffi::KeyData_t,
+ val: ffi::Val_t,
+}
+
+impl ComponentFFI {
+ fn new(key: &[i8], con: ffi::io_connect_t) -> Option<ComponentFFI> {
+ unsafe {
+ get_key_size(con, key)
+ .ok()
+ .map(|(input_structure, val)| ComponentFFI {
+ input_structure,
+ val,
+ })
+ }
+ }
+
+ fn temperature(&self, con: ffi::io_connect_t) -> Option<f32> {
+ get_temperature_inner(con, &self.input_structure, &self.val)
+ }
+}
+
+#[doc = include_str!("../../../md_doc/component.md")]
+pub struct Component {
+ temperature: f32,
+ max: f32,
+ critical: Option<f32>,
+ label: String,
+ ffi_part: ComponentFFI,
+ connection: ffi::io_connect_t,
+}
+
+impl Component {
+ /// Creates a new `Component` with the given information.
+ pub(crate) fn new(
+ label: String,
+ max: Option<f32>,
+ critical: Option<f32>,
+ key: &[i8],
+ connection: ffi::io_connect_t,
+ ) -> Option<Component> {
+ let ffi_part = ComponentFFI::new(key, connection)?;
+ ffi_part
+ .temperature(connection)
+ .map(|temperature| Component {
+ temperature,
+ label,
+ max: max.unwrap_or(0.0),
+ critical,
+ ffi_part,
+ connection,
+ })
+ }
+}
+
+impl ComponentExt for Component {
+ fn temperature(&self) -> f32 {
+ self.temperature
+ }
+
+ fn max(&self) -> f32 {
+ self.max
+ }
+
+ fn critical(&self) -> Option<f32> {
+ self.critical
+ }
+
+ fn label(&self) -> &str {
+ &self.label
+ }
+
+ fn refresh(&mut self) {
+ if let Some(temp) = self.ffi_part.temperature(self.connection) {
+ self.temperature = temp;
+ if self.temperature > self.max {
+ self.max = self.temperature;
+ }
+ }
+ }
+}
+
+unsafe fn perform_call(
+ conn: ffi::io_connect_t,
+ index: c_int,
+ input_structure: *const ffi::KeyData_t,
+ output_structure: *mut ffi::KeyData_t,
+) -> i32 {
+ let mut structure_output_size = mem::size_of::<ffi::KeyData_t>();
+
+ ffi::IOConnectCallStructMethod(
+ conn,
+ index as u32,
+ input_structure,
+ mem::size_of::<ffi::KeyData_t>(),
+ output_structure,
+ &mut structure_output_size,
+ )
+}
+
+// Adapted from https://github.com/lavoiesl/osx-cpu-temp/blob/master/smc.c#L28
+#[inline]
+fn strtoul(s: &[i8]) -> u32 {
+ unsafe {
+ ((*s.get_unchecked(0) as u32) << (3u32 << 3))
+ + ((*s.get_unchecked(1) as u32) << (2u32 << 3))
+ + ((*s.get_unchecked(2) as u32) << (1u32 << 3))
+ + (*s.get_unchecked(3) as u32)
+ }
+}
+
+#[inline]
+unsafe fn ultostr(s: *mut c_char, val: u32) {
+ *s.offset(0) = ((val >> 24) % 128) as i8;
+ *s.offset(1) = ((val >> 16) % 128) as i8;
+ *s.offset(2) = ((val >> 8) % 128) as i8;
+ *s.offset(3) = (val % 128) as i8;
+ *s.offset(4) = 0;
+}
+
+unsafe fn get_key_size(
+ con: ffi::io_connect_t,
+ key: &[i8],
+) -> Result<(ffi::KeyData_t, ffi::Val_t), i32> {
+ let mut input_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();
+ let mut output_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();
+ let mut val: ffi::Val_t = mem::zeroed::<ffi::Val_t>();
+
+ input_structure.key = strtoul(key);
+ input_structure.data8 = ffi::SMC_CMD_READ_KEYINFO;
+
+ let result = perform_call(
+ con,
+ ffi::KERNEL_INDEX_SMC,
+ &input_structure,
+ &mut output_structure,
+ );
+ if result != ffi::KIO_RETURN_SUCCESS {
+ return Err(result);
+ }
+
+ val.data_size = output_structure.key_info.data_size;
+ ultostr(
+ val.data_type.as_mut_ptr(),
+ output_structure.key_info.data_type,
+ );
+ input_structure.key_info.data_size = val.data_size;
+ input_structure.data8 = ffi::SMC_CMD_READ_BYTES;
+ Ok((input_structure, val))
+}
+
+unsafe fn read_key(
+ con: ffi::io_connect_t,
+ input_structure: &ffi::KeyData_t,
+ mut val: ffi::Val_t,
+) -> Result<ffi::Val_t, i32> {
+ let mut output_structure: ffi::KeyData_t = mem::zeroed::<ffi::KeyData_t>();
+
+ match perform_call(
+ con,
+ ffi::KERNEL_INDEX_SMC,
+ input_structure,
+ &mut output_structure,
+ ) {
+ ffi::KIO_RETURN_SUCCESS => {
+ libc::memcpy(
+ val.bytes.as_mut_ptr() as *mut c_void,
+ output_structure.bytes.as_mut_ptr() as *mut c_void,
+ mem::size_of::<[u8; 32]>(),
+ );
+ Ok(val)
+ }
+ result => Err(result),
+ }
+}
+
+fn get_temperature_inner(
+ con: ffi::io_connect_t,
+ input_structure: &ffi::KeyData_t,
+ original_val: &ffi::Val_t,
+) -> Option<f32> {
+ unsafe {
+ if let Ok(val) = read_key(con, input_structure, (*original_val).clone()) {
+ if val.data_size > 0
+ && libc::strcmp(val.data_type.as_ptr(), b"sp78\0".as_ptr() as *const i8) == 0
+ {
+ // convert sp78 value to temperature
+ let x = (i32::from(val.bytes[0]) << 6) + (i32::from(val.bytes[1]) >> 2);
+ return Some(x as f32 / 64f32);
+ }
+ }
+ }
+ None
+}
+
+pub(crate) fn get_temperature(con: ffi::io_connect_t, key: &[i8]) -> Option<f32> {
+ unsafe {
+ let (input_structure, val) = get_key_size(con, key).ok()?;
+ get_temperature_inner(con, &input_structure, &val)
+ }
+}
diff --git a/vendor/sysinfo/src/apple/macos/disk.rs b/vendor/sysinfo/src/apple/macos/disk.rs
new file mode 100644
index 000000000..7cc5a83ce
--- /dev/null
+++ b/vendor/sysinfo/src/apple/macos/disk.rs
@@ -0,0 +1,199 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::sys::{ffi, utils};
+use crate::utils::to_cpath;
+use crate::{Disk, DiskType};
+
+use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull, CFRelease};
+use core_foundation_sys::dictionary::{CFDictionaryGetValueIfPresent, CFDictionaryRef};
+use core_foundation_sys::number::{kCFBooleanTrue, CFBooleanRef};
+use core_foundation_sys::string as cfs;
+
+use libc::{c_char, c_int, c_void, statfs};
+
+use std::ffi::{OsStr, OsString};
+use std::mem;
+use std::os::unix::ffi::OsStrExt;
+use std::path::PathBuf;
+use std::ptr;
+
+fn to_path(mount_path: &[c_char]) -> Option<PathBuf> {
+ let mut tmp = Vec::with_capacity(mount_path.len());
+ for &c in mount_path {
+ if c == 0 {
+ break;
+ }
+ tmp.push(c as u8);
+ }
+ if tmp.is_empty() {
+ None
+ } else {
+ let path = OsStr::from_bytes(&tmp);
+ Some(PathBuf::from(path))
+ }
+}
+
+pub(crate) fn get_disks(session: ffi::DASessionRef) -> Vec<Disk> {
+ if session.is_null() {
+ return Vec::new();
+ }
+ unsafe {
+ let count = libc::getfsstat(ptr::null_mut(), 0, libc::MNT_NOWAIT);
+ if count < 1 {
+ return Vec::new();
+ }
+ let bufsize = count * mem::size_of::<libc::statfs>() as c_int;
+ let mut disks = Vec::with_capacity(count as _);
+ let count = libc::getfsstat(disks.as_mut_ptr(), bufsize, libc::MNT_NOWAIT);
+ if count < 1 {
+ return Vec::new();
+ }
+ disks.set_len(count as _);
+ disks
+ .into_iter()
+ .filter_map(|c_disk| {
+ let mount_point = to_path(&c_disk.f_mntonname)?;
+ let disk = ffi::DADiskCreateFromBSDName(
+ kCFAllocatorDefault as _,
+ session,
+ c_disk.f_mntfromname.as_ptr(),
+ );
+ let dict = ffi::DADiskCopyDescription(disk);
+ if dict.is_null() {
+ return None;
+ }
+ // Keeping this around in case one might want the list of the available
+ // keys in "dict".
+ // core_foundation_sys::base::CFShow(dict as _);
+ let name = match get_str_value(dict, b"DAMediaName\0").map(OsString::from) {
+ Some(n) => n,
+ None => return None,
+ };
+ let removable = get_bool_value(dict, b"DAMediaRemovable\0").unwrap_or(false);
+ let ejectable = get_bool_value(dict, b"DAMediaEjectable\0").unwrap_or(false);
+ // This is very hackish but still better than nothing...
+ let type_ = if let Some(model) = get_str_value(dict, b"DADeviceModel\0") {
+ if model.contains("SSD") {
+ DiskType::SSD
+ } else {
+ // We just assume by default that this is a HDD
+ DiskType::HDD
+ }
+ } else {
+ DiskType::Unknown(-1)
+ };
+
+ CFRelease(dict as _);
+ new_disk(name, mount_point, type_, removable || ejectable)
+ })
+ .collect::<Vec<_>>()
+ }
+}
+
+unsafe fn get_dict_value<T, F: FnOnce(*const c_void) -> Option<T>>(
+ dict: CFDictionaryRef,
+ key: &[u8],
+ callback: F,
+) -> Option<T> {
+ let key = ffi::CFStringCreateWithCStringNoCopy(
+ ptr::null_mut(),
+ key.as_ptr() as *const c_char,
+ cfs::kCFStringEncodingUTF8,
+ kCFAllocatorNull as _,
+ );
+ let mut value = std::ptr::null();
+ let ret = if CFDictionaryGetValueIfPresent(dict, key as _, &mut value) != 0 {
+ callback(value)
+ } else {
+ None
+ };
+ CFRelease(key as _);
+ ret
+}
+
+unsafe fn get_str_value(dict: CFDictionaryRef, key: &[u8]) -> Option<String> {
+ get_dict_value(dict, key, |v| {
+ let v = v as cfs::CFStringRef;
+
+ let len_utf16 = cfs::CFStringGetLength(v);
+ let len_bytes = len_utf16 as usize * 2; // Two bytes per UTF-16 codepoint.
+
+ let v_ptr = cfs::CFStringGetCStringPtr(v, cfs::kCFStringEncodingUTF8);
+ if v_ptr.is_null() {
+ // Fallback on CFStringGetString to read the underlying bytes from the CFString.
+ let mut buf = vec![0; len_bytes];
+ let success = cfs::CFStringGetCString(
+ v,
+ buf.as_mut_ptr(),
+ len_bytes as _,
+ cfs::kCFStringEncodingUTF8,
+ );
+
+ if success != 0 {
+ utils::vec_to_rust(buf)
+ } else {
+ None
+ }
+ } else {
+ utils::cstr_to_rust_with_size(v_ptr, Some(len_bytes))
+ }
+ })
+}
+
+unsafe fn get_bool_value(dict: CFDictionaryRef, key: &[u8]) -> Option<bool> {
+ get_dict_value(dict, key, |v| Some(v as CFBooleanRef == kCFBooleanTrue))
+}
+
+fn new_disk(
+ name: OsString,
+ mount_point: PathBuf,
+ type_: DiskType,
+ is_removable: bool,
+) -> Option<Disk> {
+ let mount_point_cpath = to_cpath(&mount_point);
+ let mut total_space = 0;
+ let mut available_space = 0;
+ let mut file_system = None;
+ unsafe {
+ let mut stat: statfs = mem::zeroed();
+ if statfs(mount_point_cpath.as_ptr() as *const i8, &mut stat) == 0 {
+ // APFS is "special" because its a snapshot-based filesystem, and modern
+ // macOS devices take full advantage of this.
+ //
+ // By default, listing volumes with `statfs` can return both the root-level
+ // "data" partition and any snapshots that exist. However, other than some flags and
+ // reserved(undocumented) bytes, there is no difference between the OS boot snapshot
+ // and the "data" partition.
+ //
+ // To avoid duplicating the number of disks (and therefore available space, etc), only return
+ // a disk (which is really a partition with APFS) if it is the root of the filesystem.
+ let is_root = stat.f_flags & libc::MNT_ROOTFS as u32 == 0;
+ if !is_root {
+ return None;
+ }
+
+ total_space = u64::from(stat.f_bsize).saturating_mul(stat.f_blocks);
+ available_space = u64::from(stat.f_bsize).saturating_mul(stat.f_bavail);
+ let mut vec = Vec::with_capacity(stat.f_fstypename.len());
+ for x in &stat.f_fstypename {
+ if *x == 0 {
+ break;
+ }
+ vec.push(*x as u8);
+ }
+ file_system = Some(vec);
+ }
+ if total_space == 0 {
+ return None;
+ }
+ Some(Disk {
+ type_,
+ name,
+ file_system: file_system.unwrap_or_else(|| b"<Unknown>".to_vec()),
+ mount_point,
+ total_space,
+ available_space,
+ is_removable,
+ })
+ }
+}
diff --git a/vendor/sysinfo/src/apple/macos/ffi.rs b/vendor/sysinfo/src/apple/macos/ffi.rs
new file mode 100644
index 000000000..f884701d9
--- /dev/null
+++ b/vendor/sysinfo/src/apple/macos/ffi.rs
@@ -0,0 +1,156 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use core_foundation_sys::base::CFAllocatorRef;
+use core_foundation_sys::dictionary::CFMutableDictionaryRef;
+use core_foundation_sys::string::{CFStringEncoding, CFStringRef};
+
+use libc::{c_char, c_void};
+#[cfg(not(feature = "apple-sandbox"))]
+use libc::{mach_port_t, size_t};
+
+pub(crate) use crate::sys::ffi::*;
+
+#[cfg(not(feature = "apple-sandbox"))]
+extern "C" {
+ // The proc_* PID functions are internal Apple APIs which are not
+ // allowed in App store releases as Apple blocks any binary using them.
+
+ // IOKit is only available on MacOS: https://developer.apple.com/documentation/iokit, and when not running inside
+ // of the default macOS sandbox.
+ pub fn IOMasterPort(a: i32, b: *mut mach_port_t) -> i32;
+
+ pub fn IOServiceMatching(a: *const c_char) -> *mut c_void;
+
+ pub fn IOServiceGetMatchingServices(
+ a: mach_port_t,
+ b: *mut c_void,
+ c: *mut io_iterator_t,
+ ) -> i32;
+
+ pub fn IOIteratorNext(iterator: io_iterator_t) -> io_object_t;
+
+ pub fn IOObjectRelease(obj: io_object_t) -> i32;
+
+ pub fn IOServiceOpen(device: io_object_t, a: u32, t: u32, x: *mut io_connect_t) -> i32;
+
+ pub fn IOServiceClose(a: io_connect_t) -> i32;
+
+ pub fn IOConnectCallStructMethod(
+ connection: mach_port_t,
+ selector: u32,
+ inputStruct: *const KeyData_t,
+ inputStructCnt: size_t,
+ outputStruct: *mut KeyData_t,
+ outputStructCnt: *mut size_t,
+ ) -> i32;
+ // pub fn IORegistryEntryCreateCFProperties(
+ // entry: io_registry_entry_t,
+ // properties: *mut CFMutableDictionaryRef,
+ // allocator: CFAllocatorRef,
+ // options: IOOptionBits,
+ // ) -> kern_return_t;
+ // pub fn IORegistryEntryGetName(entry: io_registry_entry_t, name: *mut c_char) -> kern_return_t;
+}
+
+extern "C" {
+ pub fn CFStringCreateWithCStringNoCopy(
+ alloc: *mut c_void,
+ cStr: *const c_char,
+ encoding: CFStringEncoding,
+ contentsDeallocator: *mut c_void,
+ ) -> CFStringRef;
+
+ // Disk information functions are non-operational on iOS because of the sandboxing
+ // restrictions of apps, so they don't can't filesystem information. This results in
+ // mountedVolumeURLs and similar returning `nil`. Hence, they are MacOS specific here.
+
+ pub fn DASessionCreate(allocator: CFAllocatorRef) -> DASessionRef;
+
+ // pub fn DADiskCreateFromVolumePath(
+ // allocator: CFAllocatorRef,
+ // session: DASessionRef,
+ // path: CFURLRef,
+ // ) -> DADiskRef;
+ pub fn DADiskCreateFromBSDName(
+ allocator: CFAllocatorRef,
+ session: DASessionRef,
+ path: *const c_char,
+ ) -> DADiskRef;
+ // pub fn DADiskGetBSDName(disk: DADiskRef) -> *const c_char;
+
+ pub fn DADiskCopyDescription(disk: DADiskRef) -> CFMutableDictionaryRef;
+}
+
+pub type DADiskRef = *const __DADisk;
+pub type DASessionRef = *const __DASession;
+
+// We need to wrap `DASessionRef` to be sure `System` remains Send+Sync.
+pub struct SessionWrap(pub DASessionRef);
+
+unsafe impl Send for SessionWrap {}
+unsafe impl Sync for SessionWrap {}
+
+#[cfg(not(feature = "apple-sandbox"))]
+mod io_service {
+ use super::mach_port_t;
+
+ #[allow(non_camel_case_types)]
+ pub type io_object_t = mach_port_t;
+ #[allow(non_camel_case_types)]
+ pub type io_connect_t = io_object_t;
+ #[allow(non_camel_case_types)]
+ pub type io_iterator_t = io_object_t;
+
+ #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
+ #[repr(C)]
+ pub struct KeyData_vers_t {
+ pub major: u8,
+ pub minor: u8,
+ pub build: u8,
+ pub reserved: [u8; 1],
+ pub release: u16,
+ }
+
+ #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
+ #[repr(C)]
+ pub struct KeyData_pLimitData_t {
+ pub version: u16,
+ pub length: u16,
+ pub cpu_plimit: u32,
+ pub gpu_plimit: u32,
+ pub mem_plimit: u32,
+ }
+
+ #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
+ #[repr(C)]
+ pub struct KeyData_keyInfo_t {
+ pub data_size: u32,
+ pub data_type: u32,
+ pub data_attributes: u8,
+ }
+
+ #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
+ #[repr(C)]
+ pub struct KeyData_t {
+ pub key: u32,
+ pub vers: KeyData_vers_t,
+ pub p_limit_data: KeyData_pLimitData_t,
+ pub key_info: KeyData_keyInfo_t,
+ pub result: u8,
+ pub status: u8,
+ pub data8: u8,
+ pub data32: u32,
+ pub bytes: [i8; 32], // SMCBytes_t
+ }
+
+ pub const KERNEL_INDEX_SMC: i32 = 2;
+ pub const SMC_CMD_READ_KEYINFO: u8 = 9;
+ pub const SMC_CMD_READ_BYTES: u8 = 5;
+
+ pub const KIO_RETURN_SUCCESS: i32 = 0;
+}
+
+#[cfg(feature = "apple-sandbox")]
+mod io_service {}
+
+pub use io_service::*;
diff --git a/vendor/sysinfo/src/apple/macos/mod.rs b/vendor/sysinfo/src/apple/macos/mod.rs
new file mode 100644
index 000000000..172bbfddc
--- /dev/null
+++ b/vendor/sysinfo/src/apple/macos/mod.rs
@@ -0,0 +1,17 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+pub mod disk;
+pub mod ffi;
+
+#[cfg(not(feature = "apple-sandbox"))]
+pub mod system;
+
+#[cfg(not(feature = "apple-sandbox"))]
+pub mod component;
+#[cfg(not(feature = "apple-sandbox"))]
+pub mod process;
+
+#[cfg(feature = "apple-sandbox")]
+pub use crate::sys::app_store::component;
+#[cfg(feature = "apple-sandbox")]
+pub use crate::sys::app_store::process;
diff --git a/vendor/sysinfo/src/apple/macos/process.rs b/vendor/sysinfo/src/apple/macos/process.rs
new file mode 100644
index 000000000..f146126cf
--- /dev/null
+++ b/vendor/sysinfo/src/apple/macos/process.rs
@@ -0,0 +1,643 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use std::ffi::CStr;
+use std::mem::{self, MaybeUninit};
+use std::ops::Deref;
+use std::path::{Path, PathBuf};
+
+use std::borrow::Borrow;
+
+use libc::{c_int, c_void, kill, size_t};
+
+use crate::{DiskUsage, Gid, Pid, ProcessExt, ProcessRefreshKind, ProcessStatus, Signal, Uid};
+
+use crate::sys::process::ThreadStatus;
+use crate::sys::system::Wrap;
+
+#[doc = include_str!("../../../md_doc/process.md")]
+pub struct Process {
+ pub(crate) name: String,
+ pub(crate) cmd: Vec<String>,
+ pub(crate) exe: PathBuf,
+ pid: Pid,
+ parent: Option<Pid>,
+ pub(crate) environ: Vec<String>,
+ cwd: PathBuf,
+ pub(crate) root: PathBuf,
+ pub(crate) memory: u64,
+ pub(crate) virtual_memory: u64,
+ old_utime: u64,
+ old_stime: u64,
+ start_time: u64,
+ run_time: u64,
+ updated: bool,
+ cpu_usage: f32,
+ user_id: Option<Uid>,
+ group_id: Option<Gid>,
+ pub(crate) process_status: ProcessStatus,
+ /// Status of process (running, stopped, waiting, etc). `None` means `sysinfo` doesn't have
+ /// enough rights to get this information.
+ ///
+ /// This is very likely this one that you want instead of `process_status`.
+ pub status: Option<ThreadStatus>,
+ pub(crate) old_read_bytes: u64,
+ pub(crate) old_written_bytes: u64,
+ pub(crate) read_bytes: u64,
+ pub(crate) written_bytes: u64,
+}
+
+impl Process {
+ pub(crate) fn new_empty(pid: Pid, exe: PathBuf, name: String, cwd: PathBuf) -> Process {
+ Process {
+ name,
+ pid,
+ parent: None,
+ cmd: Vec::new(),
+ environ: Vec::new(),
+ exe,
+ cwd,
+ root: PathBuf::new(),
+ memory: 0,
+ virtual_memory: 0,
+ cpu_usage: 0.,
+ old_utime: 0,
+ old_stime: 0,
+ updated: true,
+ start_time: 0,
+ run_time: 0,
+ user_id: None,
+ group_id: None,
+ process_status: ProcessStatus::Unknown(0),
+ status: None,
+ old_read_bytes: 0,
+ old_written_bytes: 0,
+ read_bytes: 0,
+ written_bytes: 0,
+ }
+ }
+
+ pub(crate) fn new(pid: Pid, parent: Option<Pid>, start_time: u64, run_time: u64) -> Process {
+ Process {
+ name: String::new(),
+ pid,
+ parent,
+ cmd: Vec::new(),
+ environ: Vec::new(),
+ exe: PathBuf::new(),
+ cwd: PathBuf::new(),
+ root: PathBuf::new(),
+ memory: 0,
+ virtual_memory: 0,
+ cpu_usage: 0.,
+ old_utime: 0,
+ old_stime: 0,
+ updated: true,
+ start_time,
+ run_time,
+ user_id: None,
+ group_id: None,
+ process_status: ProcessStatus::Unknown(0),
+ status: None,
+ old_read_bytes: 0,
+ old_written_bytes: 0,
+ read_bytes: 0,
+ written_bytes: 0,
+ }
+ }
+}
+
+impl ProcessExt for Process {
+ fn kill_with(&self, signal: Signal) -> Option<bool> {
+ let c_signal = crate::sys::system::convert_signal(signal)?;
+ unsafe { Some(kill(self.pid.0, c_signal) == 0) }
+ }
+
+ fn name(&self) -> &str {
+ &self.name
+ }
+
+ fn cmd(&self) -> &[String] {
+ &self.cmd
+ }
+
+ fn exe(&self) -> &Path {
+ self.exe.as_path()
+ }
+
+ fn pid(&self) -> Pid {
+ self.pid
+ }
+
+ fn environ(&self) -> &[String] {
+ &self.environ
+ }
+
+ fn cwd(&self) -> &Path {
+ self.cwd.as_path()
+ }
+
+ fn root(&self) -> &Path {
+ self.root.as_path()
+ }
+
+ fn memory(&self) -> u64 {
+ self.memory
+ }
+
+ fn virtual_memory(&self) -> u64 {
+ self.virtual_memory
+ }
+
+ fn parent(&self) -> Option<Pid> {
+ self.parent
+ }
+
+ fn status(&self) -> ProcessStatus {
+ self.process_status
+ }
+
+ fn start_time(&self) -> u64 {
+ self.start_time
+ }
+
+ fn run_time(&self) -> u64 {
+ self.run_time
+ }
+
+ fn cpu_usage(&self) -> f32 {
+ self.cpu_usage
+ }
+
+ fn disk_usage(&self) -> DiskUsage {
+ DiskUsage {
+ read_bytes: self.read_bytes - self.old_read_bytes,
+ total_read_bytes: self.read_bytes,
+ written_bytes: self.written_bytes - self.old_written_bytes,
+ total_written_bytes: self.written_bytes,
+ }
+ }
+
+ fn user_id(&self) -> Option<&Uid> {
+ self.user_id.as_ref()
+ }
+
+ fn group_id(&self) -> Option<Gid> {
+ self.group_id
+ }
+}
+
+#[allow(deprecated)] // Because of libc::mach_absolute_time.
+pub(crate) fn compute_cpu_usage(
+ p: &mut Process,
+ task_info: libc::proc_taskinfo,
+ system_time: u64,
+ user_time: u64,
+ time_interval: Option<f64>,
+) {
+ if let Some(time_interval) = time_interval {
+ let total_existing_time = p.old_stime.saturating_add(p.old_utime);
+ if time_interval > 0.000001 && total_existing_time > 0 {
+ let total_current_time = task_info
+ .pti_total_system
+ .saturating_add(task_info.pti_total_user);
+
+ let total_time_diff = total_current_time.saturating_sub(total_existing_time);
+ p.cpu_usage = (total_time_diff as f64 / time_interval * 100.) as f32;
+ } else {
+ p.cpu_usage = 0.;
+ }
+ p.old_stime = task_info.pti_total_system;
+ p.old_utime = task_info.pti_total_user;
+ } else {
+ unsafe {
+ // This is the "backup way" of CPU computation.
+ let time = libc::mach_absolute_time();
+ let task_time = user_time
+ .saturating_add(system_time)
+ .saturating_add(task_info.pti_total_user)
+ .saturating_add(task_info.pti_total_system);
+
+ let system_time_delta = if task_time < p.old_utime {
+ task_time
+ } else {
+ task_time.saturating_sub(p.old_utime)
+ };
+ let time_delta = if time < p.old_stime {
+ time
+ } else {
+ time.saturating_sub(p.old_stime)
+ };
+ p.old_utime = task_time;
+ p.old_stime = time;
+ p.cpu_usage = if time_delta == 0 {
+ 0f32
+ } else {
+ (system_time_delta as f64 * 100f64 / time_delta as f64) as f32
+ };
+ }
+ }
+ p.updated = true;
+}
+
+/*pub fn set_time(p: &mut Process, utime: u64, stime: u64) {
+ p.old_utime = p.utime;
+ p.old_stime = p.stime;
+ p.utime = utime;
+ p.stime = stime;
+ p.updated = true;
+}*/
+
+#[inline]
+pub(crate) fn has_been_updated(p: &mut Process) -> bool {
+ let old = p.updated;
+ p.updated = false;
+ old
+}
+
+#[inline]
+pub(crate) fn force_update(p: &mut Process) {
+ p.updated = true;
+}
+
+unsafe fn get_task_info(pid: Pid) -> libc::proc_taskinfo {
+ let mut task_info = mem::zeroed::<libc::proc_taskinfo>();
+ // If it doesn't work, we just don't have memory information for this process
+ // so it's "fine".
+ libc::proc_pidinfo(
+ pid.0,
+ libc::PROC_PIDTASKINFO,
+ 0,
+ &mut task_info as *mut libc::proc_taskinfo as *mut c_void,
+ mem::size_of::<libc::proc_taskinfo>() as _,
+ );
+ task_info
+}
+
+#[inline]
+fn check_if_pid_is_alive(pid: Pid) -> bool {
+ unsafe { kill(pid.0, 0) == 0 }
+ // For the full complete check, it'd need to be (but that seems unneeded):
+ // unsafe {
+ // *libc::__errno_location() == libc::ESRCH
+ // }
+}
+
+#[inline]
+fn do_not_get_env_path(_: &str, _: &mut PathBuf, _: &mut bool) {}
+
+#[inline]
+fn do_get_env_path(env: &str, root: &mut PathBuf, check: &mut bool) {
+ if *check && env.starts_with("PATH=") {
+ *check = false;
+ *root = Path::new(&env[5..]).to_path_buf();
+ }
+}
+
+pub(crate) fn update_process(
+ wrap: &Wrap,
+ pid: Pid,
+ mut size: size_t,
+ time_interval: Option<f64>,
+ now: u64,
+ refresh_kind: ProcessRefreshKind,
+) -> Result<Option<Process>, ()> {
+ let mut proc_args = Vec::with_capacity(size as usize);
+
+ unsafe {
+ if let Some(ref mut p) = (*wrap.0.get()).get_mut(&pid) {
+ if p.memory == 0 {
+ // We don't have access to this process' information.
+ force_update(p);
+ return if check_if_pid_is_alive(pid) {
+ Ok(None)
+ } else {
+ Err(())
+ };
+ }
+ let task_info = get_task_info(pid);
+ let mut thread_info = mem::zeroed::<libc::proc_threadinfo>();
+ let (user_time, system_time, thread_status) = if libc::proc_pidinfo(
+ pid.0,
+ libc::PROC_PIDTHREADINFO,
+ 0,
+ &mut thread_info as *mut libc::proc_threadinfo as *mut c_void,
+ mem::size_of::<libc::proc_threadinfo>() as _,
+ ) != 0
+ {
+ (
+ thread_info.pth_user_time,
+ thread_info.pth_system_time,
+ Some(ThreadStatus::from(thread_info.pth_run_state)),
+ )
+ } else {
+ // It very likely means that the process is dead...
+ return if check_if_pid_is_alive(pid) {
+ Ok(None)
+ } else {
+ Err(())
+ };
+ };
+ p.status = thread_status;
+ if refresh_kind.cpu() {
+ compute_cpu_usage(p, task_info, system_time, user_time, time_interval);
+ }
+
+ p.memory = task_info.pti_resident_size / 1_000;
+ p.virtual_memory = task_info.pti_virtual_size / 1_000;
+ if refresh_kind.disk_usage() {
+ update_proc_disk_activity(p);
+ }
+ return Ok(None);
+ }
+
+ let mut vnodepathinfo = mem::zeroed::<libc::proc_vnodepathinfo>();
+ let result = libc::proc_pidinfo(
+ pid.0,
+ libc::PROC_PIDVNODEPATHINFO,
+ 0,
+ &mut vnodepathinfo as *mut _ as *mut _,
+ mem::size_of::<libc::proc_vnodepathinfo>() as _,
+ );
+ let cwd = if result > 0 {
+ let buffer = vnodepathinfo.pvi_cdir.vip_path;
+ let buffer = CStr::from_ptr(buffer.as_ptr() as _);
+ buffer
+ .to_str()
+ .map(PathBuf::from)
+ .unwrap_or_else(|_| PathBuf::new())
+ } else {
+ PathBuf::new()
+ };
+
+ let mut info = mem::zeroed::<libc::proc_bsdinfo>();
+ if libc::proc_pidinfo(
+ pid.0,
+ libc::PROC_PIDTBSDINFO,
+ 0,
+ &mut info as *mut _ as *mut _,
+ mem::size_of::<libc::proc_bsdinfo>() as _,
+ ) != mem::size_of::<libc::proc_bsdinfo>() as _
+ {
+ let mut buffer: Vec<u8> = Vec::with_capacity(libc::PROC_PIDPATHINFO_MAXSIZE as _);
+ match libc::proc_pidpath(
+ pid.0,
+ buffer.as_mut_ptr() as *mut _,
+ libc::PROC_PIDPATHINFO_MAXSIZE as _,
+ ) {
+ x if x > 0 => {
+ buffer.set_len(x as _);
+ let tmp = String::from_utf8_unchecked(buffer);
+ let exe = PathBuf::from(tmp);
+ let name = exe
+ .file_name()
+ .and_then(|x| x.to_str())
+ .unwrap_or("")
+ .to_owned();
+ return Ok(Some(Process::new_empty(pid, exe, name, cwd)));
+ }
+ _ => {}
+ }
+ return Err(());
+ }
+ let parent = match info.pbi_ppid as i32 {
+ 0 => None,
+ p => Some(Pid(p)),
+ };
+
+ let ptr: *mut u8 = proc_args.as_mut_slice().as_mut_ptr();
+ let mut mib = [libc::CTL_KERN, libc::KERN_PROCARGS2, pid.0 as _];
+ /*
+ * /---------------\ 0x00000000
+ * | ::::::::::::: |
+ * |---------------| <-- Beginning of data returned by sysctl() is here.
+ * | argc |
+ * |---------------|
+ * | exec_path |
+ * |---------------|
+ * | 0 |
+ * |---------------|
+ * | arg[0] |
+ * |---------------|
+ * | 0 |
+ * |---------------|
+ * | arg[n] |
+ * |---------------|
+ * | 0 |
+ * |---------------|
+ * | env[0] |
+ * |---------------|
+ * | 0 |
+ * |---------------|
+ * | env[n] |
+ * |---------------|
+ * | ::::::::::::: |
+ * |---------------| <-- Top of stack.
+ * : :
+ * : :
+ * \---------------/ 0xffffffff
+ */
+ if libc::sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ ptr as *mut c_void,
+ &mut size,
+ std::ptr::null_mut(),
+ 0,
+ ) == -1
+ {
+ return Err(()); // not enough rights I assume?
+ }
+ let mut n_args: c_int = 0;
+ libc::memcpy(
+ (&mut n_args) as *mut c_int as *mut c_void,
+ ptr as *const c_void,
+ mem::size_of::<c_int>(),
+ );
+
+ let mut cp = ptr.add(mem::size_of::<c_int>());
+ let mut start = cp;
+
+ let start_time = info.pbi_start_tvsec;
+ let run_time = now.saturating_sub(start_time);
+
+ let mut p = if cp < ptr.add(size) {
+ while cp < ptr.add(size) && *cp != 0 {
+ cp = cp.offset(1);
+ }
+ let exe = Path::new(get_unchecked_str(cp, start).as_str()).to_path_buf();
+ let name = exe
+ .file_name()
+ .and_then(|x| x.to_str())
+ .unwrap_or("")
+ .to_owned();
+ while cp < ptr.add(size) && *cp == 0 {
+ cp = cp.offset(1);
+ }
+ start = cp;
+ let mut c = 0;
+ let mut cmd = Vec::with_capacity(n_args as usize);
+ while c < n_args && cp < ptr.add(size) {
+ if *cp == 0 {
+ c += 1;
+ cmd.push(get_unchecked_str(cp, start));
+ start = cp.offset(1);
+ }
+ cp = cp.offset(1);
+ }
+
+ #[inline]
+ unsafe fn get_environ<F: Fn(&str, &mut PathBuf, &mut bool)>(
+ ptr: *mut u8,
+ mut cp: *mut u8,
+ size: size_t,
+ mut root: PathBuf,
+ callback: F,
+ ) -> (Vec<String>, PathBuf) {
+ let mut environ = Vec::with_capacity(10);
+ let mut start = cp;
+ let mut check = true;
+ while cp < ptr.add(size) {
+ if *cp == 0 {
+ if cp == start {
+ break;
+ }
+ let e = get_unchecked_str(cp, start);
+ callback(&e, &mut root, &mut check);
+ environ.push(e);
+ start = cp.offset(1);
+ }
+ cp = cp.offset(1);
+ }
+ (environ, root)
+ }
+
+ let (environ, root) = if exe.is_absolute() {
+ if let Some(parent_path) = exe.parent() {
+ get_environ(
+ ptr,
+ cp,
+ size,
+ parent_path.to_path_buf(),
+ do_not_get_env_path,
+ )
+ } else {
+ get_environ(ptr, cp, size, PathBuf::new(), do_get_env_path)
+ }
+ } else {
+ get_environ(ptr, cp, size, PathBuf::new(), do_get_env_path)
+ };
+ let mut p = Process::new(pid, parent, start_time, run_time);
+
+ p.exe = exe;
+ p.name = name;
+ p.cwd = cwd;
+ p.cmd = parse_command_line(&cmd);
+ p.environ = environ;
+ p.root = root;
+ p
+ } else {
+ Process::new(pid, parent, start_time, run_time)
+ };
+
+ let task_info = get_task_info(pid);
+
+ p.memory = task_info.pti_resident_size / 1_000;
+ p.virtual_memory = task_info.pti_virtual_size / 1_000;
+
+ p.user_id = Some(Uid(info.pbi_uid));
+ p.group_id = Some(Gid(info.pbi_gid));
+ p.process_status = ProcessStatus::from(info.pbi_status);
+ if refresh_kind.disk_usage() {
+ update_proc_disk_activity(&mut p);
+ }
+ Ok(Some(p))
+ }
+}
+
+fn update_proc_disk_activity(p: &mut Process) {
+ p.old_read_bytes = p.read_bytes;
+ p.old_written_bytes = p.written_bytes;
+
+ let mut pidrusage = MaybeUninit::<libc::rusage_info_v2>::uninit();
+
+ unsafe {
+ let retval = libc::proc_pid_rusage(
+ p.pid().0 as _,
+ libc::RUSAGE_INFO_V2,
+ pidrusage.as_mut_ptr() as _,
+ );
+
+ if retval < 0 {
+ sysinfo_debug!("proc_pid_rusage failed: {:?}", retval);
+ } else {
+ let pidrusage = pidrusage.assume_init();
+ p.read_bytes = pidrusage.ri_diskio_bytesread;
+ p.written_bytes = pidrusage.ri_diskio_byteswritten;
+ }
+ }
+}
+
+#[allow(clippy::uninit_vec)]
+pub(crate) fn get_proc_list() -> Option<Vec<Pid>> {
+ unsafe {
+ let count = libc::proc_listallpids(::std::ptr::null_mut(), 0);
+ if count < 1 {
+ return None;
+ }
+ let mut pids: Vec<Pid> = Vec::with_capacity(count as usize);
+ pids.set_len(count as usize);
+ let count = count * mem::size_of::<Pid>() as i32;
+ let x = libc::proc_listallpids(pids.as_mut_ptr() as *mut c_void, count);
+
+ if x < 1 || x as usize >= pids.len() {
+ None
+ } else {
+ pids.set_len(x as usize);
+ Some(pids)
+ }
+ }
+}
+
+unsafe fn get_unchecked_str(cp: *mut u8, start: *mut u8) -> String {
+ let len = cp as usize - start as usize;
+ let part = Vec::from_raw_parts(start, len, len);
+ let tmp = String::from_utf8_unchecked(part.clone());
+ mem::forget(part);
+ tmp
+}
+
+fn parse_command_line<T: Deref<Target = str> + Borrow<str>>(cmd: &[T]) -> Vec<String> {
+ let mut x = 0;
+ let mut command = Vec::with_capacity(cmd.len());
+ while x < cmd.len() {
+ let mut y = x;
+ if cmd[y].starts_with('\'') || cmd[y].starts_with('"') {
+ let c = if cmd[y].starts_with('\'') { '\'' } else { '"' };
+ while y < cmd.len() && !cmd[y].ends_with(c) {
+ y += 1;
+ }
+ command.push(cmd[x..y].join(" "));
+ x = y;
+ } else {
+ command.push(cmd[x].to_owned());
+ }
+ x += 1;
+ }
+ command
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_get_path() {
+ let mut path = PathBuf::new();
+ let mut check = true;
+
+ do_get_env_path("PATH=tadam", &mut path, &mut check);
+
+ assert!(!check);
+ assert_eq!(path, PathBuf::from("tadam"));
+ }
+}
diff --git a/vendor/sysinfo/src/apple/macos/system.rs b/vendor/sysinfo/src/apple/macos/system.rs
new file mode 100644
index 000000000..949532234
--- /dev/null
+++ b/vendor/sysinfo/src/apple/macos/system.rs
@@ -0,0 +1,136 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+#[allow(deprecated)]
+use libc::{mach_timebase_info, mach_timebase_info_data_t};
+
+use libc::{
+ host_processor_info, mach_port_t, munmap, natural_t, processor_cpu_load_info,
+ processor_cpu_load_info_t, sysconf, vm_page_size, PROCESSOR_CPU_LOAD_INFO, _SC_CLK_TCK,
+};
+use std::ptr::null_mut;
+
+unsafe fn free_cpu_load_info(cpu_load: &mut processor_cpu_load_info_t) {
+ if !cpu_load.is_null() {
+ munmap(*cpu_load as _, vm_page_size);
+ *cpu_load = null_mut();
+ }
+}
+
+pub(crate) struct SystemTimeInfo {
+ timebase_to_ns: f64,
+ clock_per_sec: f64,
+ old_cpu_load: processor_cpu_load_info_t,
+ old_cpu_count: natural_t,
+}
+
+unsafe impl Send for SystemTimeInfo {}
+unsafe impl Sync for SystemTimeInfo {}
+
+impl SystemTimeInfo {
+ #[allow(deprecated)] // Everything related to mach_timebase_info_data_t
+ pub fn new(port: mach_port_t) -> Option<Self> {
+ unsafe {
+ let clock_ticks_per_sec = sysconf(_SC_CLK_TCK);
+
+ // FIXME: Maybe check errno here? Problem is that if errno is not 0 before this call,
+ // we will get an error which isn't related...
+ // if let Some(er) = std::io::Error::last_os_error().raw_os_error() {
+ // if err != 0 {
+ // println!("==> {:?}", er);
+ // sysinfo_debug!("Failed to get _SC_CLK_TCK value, using old CPU tick measure system");
+ // return None;
+ // }
+ // }
+
+ let mut info = mach_timebase_info_data_t { numer: 0, denom: 0 };
+ if mach_timebase_info(&mut info) != libc::KERN_SUCCESS {
+ sysinfo_debug!("mach_timebase_info failed, using default value of 1");
+ info.numer = 1;
+ info.denom = 1;
+ }
+
+ let mut old_cpu_load = null_mut();
+ let old_cpu_count = match Self::update_ticks(port, &mut old_cpu_load) {
+ Some(c) => c,
+ None => {
+ sysinfo_debug!("host_processor_info failed, using old CPU tick measure system");
+ return None;
+ }
+ };
+
+ let nano_per_seconds = 1_000_000_000.;
+ sysinfo_debug!("");
+ Some(Self {
+ timebase_to_ns: info.numer as f64 / info.denom as f64,
+ clock_per_sec: nano_per_seconds / clock_ticks_per_sec as f64,
+ old_cpu_load,
+ old_cpu_count,
+ })
+ }
+ }
+
+ fn update_ticks(
+ port: mach_port_t,
+ cpu_load: &mut processor_cpu_load_info_t,
+ ) -> Option<natural_t> {
+ let mut info_size = std::mem::size_of::<processor_cpu_load_info_t>() as _;
+ let mut cpu_count = 0;
+
+ unsafe {
+ free_cpu_load_info(cpu_load);
+
+ if host_processor_info(
+ port,
+ PROCESSOR_CPU_LOAD_INFO,
+ &mut cpu_count,
+ cpu_load as *mut _ as *mut _,
+ &mut info_size,
+ ) != 0
+ {
+ sysinfo_debug!("host_processor_info failed, not updating CPU ticks usage...");
+ None
+ } else if cpu_count < 1 || cpu_load.is_null() {
+ None
+ } else {
+ Some(cpu_count)
+ }
+ }
+ }
+
+ pub fn get_time_interval(&mut self, port: mach_port_t) -> f64 {
+ let mut total = 0;
+ let mut new_cpu_load = null_mut();
+
+ let new_cpu_count = match Self::update_ticks(port, &mut new_cpu_load) {
+ Some(c) => c,
+ None => return 0.,
+ };
+ let cpu_count = std::cmp::min(self.old_cpu_count, new_cpu_count);
+ unsafe {
+ for i in 0..cpu_count {
+ let new_load: &processor_cpu_load_info = &*new_cpu_load.offset(i as _);
+ let old_load: &processor_cpu_load_info = &*self.old_cpu_load.offset(i as _);
+ for (new, old) in new_load.cpu_ticks.iter().zip(old_load.cpu_ticks.iter()) {
+ if new > old {
+ total += new - old;
+ }
+ }
+ }
+
+ free_cpu_load_info(&mut self.old_cpu_load);
+ self.old_cpu_load = new_cpu_load;
+ self.old_cpu_count = new_cpu_count;
+
+ // Now we convert the ticks to nanoseconds:
+ total as f64 / self.timebase_to_ns * self.clock_per_sec / cpu_count as f64
+ }
+ }
+}
+
+impl Drop for SystemTimeInfo {
+ fn drop(&mut self) {
+ unsafe {
+ free_cpu_load_info(&mut self.old_cpu_load);
+ }
+ }
+}
diff --git a/vendor/sysinfo/src/apple/mod.rs b/vendor/sysinfo/src/apple/mod.rs
new file mode 100644
index 000000000..daff800a2
--- /dev/null
+++ b/vendor/sysinfo/src/apple/mod.rs
@@ -0,0 +1,31 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+#[cfg(target_os = "macos")]
+pub(crate) mod macos;
+#[cfg(target_os = "macos")]
+pub(crate) use self::macos as inner;
+
+#[cfg(target_os = "ios")]
+pub(crate) mod ios;
+#[cfg(target_os = "ios")]
+pub(crate) use self::ios as inner;
+
+#[cfg(any(target_os = "ios", feature = "apple-sandbox"))]
+pub(crate) mod app_store;
+
+pub mod component;
+pub mod cpu;
+pub mod disk;
+mod ffi;
+pub mod network;
+pub mod process;
+pub mod system;
+pub mod users;
+mod utils;
+
+pub use self::component::Component;
+pub use self::cpu::Cpu;
+pub use self::disk::Disk;
+pub use self::network::{NetworkData, Networks};
+pub use self::process::Process;
+pub use self::system::System;
diff --git a/vendor/sysinfo/src/apple/network.rs b/vendor/sysinfo/src/apple/network.rs
new file mode 100644
index 000000000..f1316920e
--- /dev/null
+++ b/vendor/sysinfo/src/apple/network.rs
@@ -0,0 +1,239 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use libc::{self, c_char, if_msghdr2, CTL_NET, NET_RT_IFLIST2, PF_ROUTE, RTM_IFINFO2};
+
+use std::collections::{hash_map, HashMap};
+use std::ptr::null_mut;
+
+use crate::{NetworkExt, NetworksExt, NetworksIter};
+
+macro_rules! old_and_new {
+ ($ty_:expr, $name:ident, $old:ident, $new_val:expr) => {{
+ $ty_.$old = $ty_.$name;
+ $ty_.$name = $new_val;
+ }};
+}
+
+#[doc = include_str!("../../md_doc/networks.md")]
+pub struct Networks {
+ interfaces: HashMap<String, NetworkData>,
+}
+
+impl Networks {
+ pub(crate) fn new() -> Self {
+ Networks {
+ interfaces: HashMap::new(),
+ }
+ }
+
+ #[allow(clippy::cast_ptr_alignment)]
+ #[allow(clippy::uninit_vec)]
+ fn update_networks(&mut self) {
+ let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0];
+ let mut len = 0;
+ unsafe {
+ if libc::sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ null_mut(),
+ &mut len,
+ null_mut(),
+ 0,
+ ) < 0
+ {
+ // TODO: might be nice to put an error in here...
+ return;
+ }
+ let mut buf = Vec::with_capacity(len);
+ buf.set_len(len);
+ if libc::sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ buf.as_mut_ptr(),
+ &mut len,
+ null_mut(),
+ 0,
+ ) < 0
+ {
+ // TODO: might be nice to put an error in here...
+ return;
+ }
+ let buf = buf.as_ptr() as *const c_char;
+ let lim = buf.add(len);
+ let mut next = buf;
+ while next < lim {
+ let ifm = next as *const libc::if_msghdr;
+ next = next.offset((*ifm).ifm_msglen as isize);
+ if (*ifm).ifm_type == RTM_IFINFO2 as u8 {
+ // The interface (line description) name stored at ifname will be returned in
+ // the default coded character set identifier (CCSID) currently in effect for
+ // the job. If this is not a single byte CCSID, then storage greater than
+ // IFNAMSIZ (16) bytes may be needed. 22 bytes is large enough for all CCSIDs.
+ let mut name = vec![0u8; libc::IFNAMSIZ + 6];
+
+ let if2m: *const if_msghdr2 = ifm as *const if_msghdr2;
+ let pname =
+ libc::if_indextoname((*if2m).ifm_index as _, name.as_mut_ptr() as _);
+ if pname.is_null() {
+ continue;
+ }
+ name.set_len(libc::strlen(pname));
+ let name = String::from_utf8_unchecked(name);
+ match self.interfaces.entry(name) {
+ hash_map::Entry::Occupied(mut e) => {
+ let mut interface = e.get_mut();
+ old_and_new!(
+ interface,
+ current_out,
+ old_out,
+ (*if2m).ifm_data.ifi_obytes
+ );
+ old_and_new!(
+ interface,
+ current_in,
+ old_in,
+ (*if2m).ifm_data.ifi_ibytes
+ );
+ old_and_new!(
+ interface,
+ packets_in,
+ old_packets_in,
+ (*if2m).ifm_data.ifi_ipackets
+ );
+ old_and_new!(
+ interface,
+ packets_out,
+ old_packets_out,
+ (*if2m).ifm_data.ifi_opackets
+ );
+ old_and_new!(
+ interface,
+ errors_in,
+ old_errors_in,
+ (*if2m).ifm_data.ifi_ierrors
+ );
+ old_and_new!(
+ interface,
+ errors_out,
+ old_errors_out,
+ (*if2m).ifm_data.ifi_oerrors
+ );
+ interface.updated = true;
+ }
+ hash_map::Entry::Vacant(e) => {
+ let current_in = (*if2m).ifm_data.ifi_ibytes;
+ let current_out = (*if2m).ifm_data.ifi_obytes;
+ let packets_in = (*if2m).ifm_data.ifi_ipackets;
+ let packets_out = (*if2m).ifm_data.ifi_opackets;
+ let errors_in = (*if2m).ifm_data.ifi_ierrors;
+ let errors_out = (*if2m).ifm_data.ifi_oerrors;
+
+ e.insert(NetworkData {
+ current_in,
+ old_in: current_in,
+ current_out,
+ old_out: current_out,
+ packets_in,
+ old_packets_in: packets_in,
+ packets_out,
+ old_packets_out: packets_out,
+ errors_in,
+ old_errors_in: errors_in,
+ errors_out,
+ old_errors_out: errors_out,
+ updated: true,
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+impl NetworksExt for Networks {
+ #[allow(clippy::needless_lifetimes)]
+ fn iter<'a>(&'a self) -> NetworksIter<'a> {
+ NetworksIter::new(self.interfaces.iter())
+ }
+
+ fn refresh_networks_list(&mut self) {
+ for (_, data) in self.interfaces.iter_mut() {
+ data.updated = false;
+ }
+ self.update_networks();
+ self.interfaces.retain(|_, data| data.updated);
+ }
+
+ fn refresh(&mut self) {
+ self.update_networks();
+ }
+}
+
+#[doc = include_str!("../../md_doc/network_data.md")]
+#[derive(PartialEq, Eq)]
+pub struct NetworkData {
+ current_in: u64,
+ old_in: u64,
+ current_out: u64,
+ old_out: u64,
+ packets_in: u64,
+ old_packets_in: u64,
+ packets_out: u64,
+ old_packets_out: u64,
+ errors_in: u64,
+ old_errors_in: u64,
+ errors_out: u64,
+ old_errors_out: u64,
+ updated: bool,
+}
+
+impl NetworkExt for NetworkData {
+ fn received(&self) -> u64 {
+ self.current_in.saturating_sub(self.old_in)
+ }
+
+ fn total_received(&self) -> u64 {
+ self.current_in
+ }
+
+ fn transmitted(&self) -> u64 {
+ self.current_out.saturating_sub(self.old_out)
+ }
+
+ fn total_transmitted(&self) -> u64 {
+ self.current_out
+ }
+
+ fn packets_received(&self) -> u64 {
+ self.packets_in.saturating_sub(self.old_packets_in)
+ }
+
+ fn total_packets_received(&self) -> u64 {
+ self.packets_in
+ }
+
+ fn packets_transmitted(&self) -> u64 {
+ self.packets_out.saturating_sub(self.old_packets_out)
+ }
+
+ fn total_packets_transmitted(&self) -> u64 {
+ self.packets_out
+ }
+
+ fn errors_on_received(&self) -> u64 {
+ self.errors_in.saturating_sub(self.old_errors_in)
+ }
+
+ fn total_errors_on_received(&self) -> u64 {
+ self.errors_in
+ }
+
+ fn errors_on_transmitted(&self) -> u64 {
+ self.errors_out.saturating_sub(self.old_errors_out)
+ }
+
+ fn total_errors_on_transmitted(&self) -> u64 {
+ self.errors_out
+ }
+}
diff --git a/vendor/sysinfo/src/apple/process.rs b/vendor/sysinfo/src/apple/process.rs
new file mode 100644
index 000000000..e0f005bdc
--- /dev/null
+++ b/vendor/sysinfo/src/apple/process.rs
@@ -0,0 +1,83 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use std::fmt;
+
+pub use crate::sys::inner::process::*;
+use crate::ProcessStatus;
+
+#[doc(hidden)]
+impl From<u32> for ProcessStatus {
+ fn from(status: u32) -> ProcessStatus {
+ match status {
+ 1 => ProcessStatus::Idle,
+ 2 => ProcessStatus::Run,
+ 3 => ProcessStatus::Sleep,
+ 4 => ProcessStatus::Stop,
+ 5 => ProcessStatus::Zombie,
+ x => ProcessStatus::Unknown(x),
+ }
+ }
+}
+
+impl fmt::Display for ProcessStatus {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(match *self {
+ ProcessStatus::Idle => "Idle",
+ ProcessStatus::Run => "Runnable",
+ ProcessStatus::Sleep => "Sleeping",
+ ProcessStatus::Stop => "Stopped",
+ ProcessStatus::Zombie => "Zombie",
+ _ => "Unknown",
+ })
+ }
+}
+
+/// Enum describing the different status of a thread.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ThreadStatus {
+ /// Thread is running normally.
+ Running,
+ /// Thread is stopped.
+ Stopped,
+ /// Thread is waiting normally.
+ Waiting,
+ /// Thread is in an uninterruptible wait
+ Uninterruptible,
+ /// Thread is halted at a clean point.
+ Halted,
+ /// Unknown.
+ Unknown(i32),
+}
+
+impl From<i32> for ThreadStatus {
+ fn from(status: i32) -> ThreadStatus {
+ match status {
+ 1 => ThreadStatus::Running,
+ 2 => ThreadStatus::Stopped,
+ 3 => ThreadStatus::Waiting,
+ 4 => ThreadStatus::Uninterruptible,
+ 5 => ThreadStatus::Halted,
+ x => ThreadStatus::Unknown(x),
+ }
+ }
+}
+
+impl ThreadStatus {
+ /// Used to display `ThreadStatus`.
+ pub fn to_string(&self) -> &str {
+ match *self {
+ ThreadStatus::Running => "Running",
+ ThreadStatus::Stopped => "Stopped",
+ ThreadStatus::Waiting => "Waiting",
+ ThreadStatus::Uninterruptible => "Uninterruptible",
+ ThreadStatus::Halted => "Halted",
+ ThreadStatus::Unknown(_) => "Unknown",
+ }
+ }
+}
+
+impl fmt::Display for ThreadStatus {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.to_string())
+ }
+}
diff --git a/vendor/sysinfo/src/apple/system.rs b/vendor/sysinfo/src/apple/system.rs
new file mode 100644
index 000000000..abe617dee
--- /dev/null
+++ b/vendor/sysinfo/src/apple/system.rs
@@ -0,0 +1,763 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::sys::component::Component;
+use crate::sys::cpu::*;
+use crate::sys::disk::*;
+#[cfg(target_os = "macos")]
+use crate::sys::ffi;
+use crate::sys::network::Networks;
+use crate::sys::process::*;
+#[cfg(target_os = "macos")]
+use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease};
+
+use crate::{
+ CpuExt, CpuRefreshKind, LoadAvg, Pid, ProcessRefreshKind, RefreshKind, SystemExt, User,
+};
+
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+use crate::ProcessExt;
+
+use std::cell::UnsafeCell;
+use std::collections::HashMap;
+use std::mem;
+use std::sync::Arc;
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+use std::time::SystemTime;
+
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+use libc::size_t;
+
+use libc::{
+ c_char, c_int, c_void, host_statistics64, mach_port_t, sysconf, sysctl, sysctlbyname, timeval,
+ vm_statistics64, _SC_PAGESIZE,
+};
+
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+declare_signals! {
+ c_int,
+ Signal::Hangup => libc::SIGHUP,
+ Signal::Interrupt => libc::SIGINT,
+ Signal::Quit => libc::SIGQUIT,
+ Signal::Illegal => libc::SIGILL,
+ Signal::Trap => libc::SIGTRAP,
+ Signal::Abort => libc::SIGABRT,
+ Signal::IOT => libc::SIGIOT,
+ Signal::Bus => libc::SIGBUS,
+ Signal::FloatingPointException => libc::SIGFPE,
+ Signal::Kill => libc::SIGKILL,
+ Signal::User1 => libc::SIGUSR1,
+ Signal::Segv => libc::SIGSEGV,
+ Signal::User2 => libc::SIGUSR2,
+ Signal::Pipe => libc::SIGPIPE,
+ Signal::Alarm => libc::SIGALRM,
+ Signal::Term => libc::SIGTERM,
+ Signal::Child => libc::SIGCHLD,
+ Signal::Continue => libc::SIGCONT,
+ Signal::Stop => libc::SIGSTOP,
+ Signal::TSTP => libc::SIGTSTP,
+ Signal::TTIN => libc::SIGTTIN,
+ Signal::TTOU => libc::SIGTTOU,
+ Signal::Urgent => libc::SIGURG,
+ Signal::XCPU => libc::SIGXCPU,
+ Signal::XFSZ => libc::SIGXFSZ,
+ Signal::VirtualAlarm => libc::SIGVTALRM,
+ Signal::Profiling => libc::SIGPROF,
+ Signal::Winch => libc::SIGWINCH,
+ Signal::IO => libc::SIGIO,
+ // SIGPOLL doesn't exist on apple targets but since it's an equivalent of SIGIO on unix,
+ // we simply use the SIGIO constant.
+ Signal::Poll => libc::SIGIO,
+ Signal::Sys => libc::SIGSYS,
+ _ => None,
+}
+#[cfg(any(target_os = "ios", feature = "apple-sandbox"))]
+declare_signals! {
+ c_int,
+ _ => None,
+}
+
+#[doc = include_str!("../../md_doc/system.md")]
+pub struct System {
+ process_list: HashMap<Pid, Process>,
+ mem_total: u64,
+ mem_free: u64,
+ mem_available: u64,
+ swap_total: u64,
+ swap_free: u64,
+ global_cpu: Cpu,
+ cpus: Vec<Cpu>,
+ page_size_kb: u64,
+ components: Vec<Component>,
+ // Used to get CPU information, not supported on iOS, or inside the default macOS sandbox.
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ connection: Option<ffi::io_connect_t>,
+ disks: Vec<Disk>,
+ networks: Networks,
+ port: mach_port_t,
+ users: Vec<User>,
+ boot_time: u64,
+ // Used to get disk information, to be more specific, it's needed by the
+ // DADiskCreateFromVolumePath function. Not supported on iOS.
+ #[cfg(target_os = "macos")]
+ session: ffi::SessionWrap,
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ clock_info: Option<crate::sys::macos::system::SystemTimeInfo>,
+ got_cpu_frequency: bool,
+}
+
+impl Drop for System {
+ fn drop(&mut self) {
+ #[cfg(target_os = "macos")]
+ unsafe {
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ if let Some(conn) = self.connection {
+ ffi::IOServiceClose(conn);
+ }
+
+ if !self.session.0.is_null() {
+ CFRelease(self.session.0 as _);
+ }
+ }
+ }
+}
+
+pub(crate) struct Wrap<'a>(pub UnsafeCell<&'a mut HashMap<Pid, Process>>);
+
+unsafe impl<'a> Send for Wrap<'a> {}
+unsafe impl<'a> Sync for Wrap<'a> {}
+
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+impl System {
+ fn clear_procs(&mut self) {
+ use crate::sys::macos::process;
+
+ self.process_list
+ .retain(|_, proc_| process::has_been_updated(proc_));
+ }
+}
+
+fn boot_time() -> u64 {
+ let mut boot_time = timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ };
+ let mut len = std::mem::size_of::<timeval>();
+ let mut mib: [c_int; 2] = [libc::CTL_KERN, libc::KERN_BOOTTIME];
+
+ unsafe {
+ if sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ &mut boot_time as *mut timeval as *mut _,
+ &mut len,
+ std::ptr::null_mut(),
+ 0,
+ ) < 0
+ {
+ 0
+ } else {
+ boot_time.tv_sec as _
+ }
+ }
+}
+
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+fn get_now() -> u64 {
+ SystemTime::now()
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .map(|n| n.as_secs())
+ .unwrap_or(0)
+}
+
+impl SystemExt for System {
+ const IS_SUPPORTED: bool = true;
+ const SUPPORTED_SIGNALS: &'static [Signal] = supported_signals();
+
+ fn new_with_specifics(refreshes: RefreshKind) -> System {
+ unsafe {
+ let port = libc::mach_host_self();
+
+ let mut s = System {
+ process_list: HashMap::with_capacity(200),
+ mem_total: 0,
+ mem_free: 0,
+ mem_available: 0,
+ swap_total: 0,
+ swap_free: 0,
+ global_cpu: Cpu::new(
+ "0".to_owned(),
+ Arc::new(CpuData::new(std::ptr::null_mut(), 0)),
+ 0,
+ String::new(),
+ String::new(),
+ ),
+ cpus: Vec::new(),
+ page_size_kb: sysconf(_SC_PAGESIZE) as u64 / 1_000,
+ components: Vec::with_capacity(2),
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ connection: get_io_service_connection(),
+ disks: Vec::with_capacity(1),
+ networks: Networks::new(),
+ port,
+ users: Vec::new(),
+ boot_time: boot_time(),
+ #[cfg(target_os = "macos")]
+ session: ffi::SessionWrap(::std::ptr::null_mut()),
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ clock_info: crate::sys::macos::system::SystemTimeInfo::new(port),
+ got_cpu_frequency: false,
+ };
+ s.refresh_specifics(refreshes);
+ s
+ }
+ }
+
+ fn refresh_memory(&mut self) {
+ let mut mib = [0, 0];
+
+ unsafe {
+ // get system values
+ // get swap info
+ let mut xs: libc::xsw_usage = mem::zeroed::<libc::xsw_usage>();
+ if get_sys_value(
+ libc::CTL_VM as _,
+ libc::VM_SWAPUSAGE as _,
+ mem::size_of::<libc::xsw_usage>(),
+ &mut xs as *mut _ as *mut c_void,
+ &mut mib,
+ ) {
+ self.swap_total = xs.xsu_total / 1_000;
+ self.swap_free = xs.xsu_avail / 1_000;
+ }
+ // get ram info
+ if self.mem_total < 1 {
+ get_sys_value(
+ libc::CTL_HW as _,
+ libc::HW_MEMSIZE as _,
+ mem::size_of::<u64>(),
+ &mut self.mem_total as *mut u64 as *mut c_void,
+ &mut mib,
+ );
+ self.mem_total /= 1_000;
+ }
+ let mut count: u32 = libc::HOST_VM_INFO64_COUNT as _;
+ let mut stat = mem::zeroed::<vm_statistics64>();
+ if host_statistics64(
+ self.port,
+ libc::HOST_VM_INFO64,
+ &mut stat as *mut vm_statistics64 as *mut _,
+ &mut count,
+ ) == libc::KERN_SUCCESS
+ {
+ // From the apple documentation:
+ //
+ // /*
+ // * NB: speculative pages are already accounted for in "free_count",
+ // * so "speculative_count" is the number of "free" pages that are
+ // * used to hold data that was read speculatively from disk but
+ // * haven't actually been used by anyone so far.
+ // */
+ self.mem_available = self
+ .mem_total
+ .saturating_sub(
+ u64::from(stat.active_count)
+ .saturating_add(u64::from(stat.inactive_count))
+ .saturating_add(u64::from(stat.wire_count))
+ .saturating_add(u64::from(stat.speculative_count))
+ .saturating_sub(u64::from(stat.purgeable_count)),
+ )
+ .saturating_mul(self.page_size_kb);
+ self.mem_free = u64::from(stat.free_count).saturating_mul(self.page_size_kb);
+ }
+ }
+ }
+
+ #[cfg(any(target_os = "ios", feature = "apple-sandbox"))]
+ fn refresh_components_list(&mut self) {}
+
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ fn refresh_components_list(&mut self) {
+ if let Some(con) = self.connection {
+ self.components.clear();
+ // getting CPU critical temperature
+ let critical_temp = crate::apple::component::get_temperature(
+ con,
+ &['T' as i8, 'C' as i8, '0' as i8, 'D' as i8, 0],
+ );
+
+ for (id, v) in crate::apple::component::COMPONENTS_TEMPERATURE_IDS.iter() {
+ if let Some(c) = Component::new((*id).to_owned(), None, critical_temp, v, con) {
+ self.components.push(c);
+ }
+ }
+ }
+ }
+
+ fn refresh_cpu_specifics(&mut self, refresh_kind: CpuRefreshKind) {
+ let cpus = &mut self.cpus;
+ if cpus.is_empty() {
+ init_cpus(self.port, cpus, &mut self.global_cpu, refresh_kind);
+ self.got_cpu_frequency = refresh_kind.frequency();
+ return;
+ }
+ if refresh_kind.frequency() && !self.got_cpu_frequency {
+ let frequency = get_cpu_frequency();
+ for proc_ in cpus.iter_mut() {
+ proc_.set_frequency(frequency);
+ }
+ self.got_cpu_frequency = true;
+ }
+ if refresh_kind.cpu_usage() {
+ update_cpu_usage(self.port, &mut self.global_cpu, |proc_data, cpu_info| {
+ let mut percentage = 0f32;
+ let mut offset = 0;
+ for proc_ in cpus.iter_mut() {
+ let cpu_usage = compute_usage_of_cpu(proc_, cpu_info, offset);
+ proc_.update(cpu_usage, Arc::clone(&proc_data));
+ percentage += proc_.cpu_usage();
+
+ offset += libc::CPU_STATE_MAX as isize;
+ }
+ (percentage, cpus.len())
+ });
+ }
+ }
+
+ #[cfg(any(target_os = "ios", feature = "apple-sandbox"))]
+ fn refresh_processes_specifics(&mut self, _refresh_kind: ProcessRefreshKind) {}
+
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ fn refresh_processes_specifics(&mut self, refresh_kind: ProcessRefreshKind) {
+ use crate::utils::into_iter;
+
+ unsafe {
+ let count = libc::proc_listallpids(::std::ptr::null_mut(), 0);
+ if count < 1 {
+ return;
+ }
+ }
+ if let Some(pids) = get_proc_list() {
+ let now = get_now();
+ let arg_max = get_arg_max();
+ let port = self.port;
+ let time_interval = self.clock_info.as_mut().map(|c| c.get_time_interval(port));
+ let entries: Vec<Process> = {
+ let wrap = &Wrap(UnsafeCell::new(&mut self.process_list));
+
+ #[cfg(feature = "multithread")]
+ use rayon::iter::ParallelIterator;
+
+ into_iter(pids)
+ .flat_map(|pid| {
+ match update_process(
+ wrap,
+ pid,
+ arg_max as size_t,
+ time_interval,
+ now,
+ refresh_kind,
+ ) {
+ Ok(x) => x,
+ _ => None,
+ }
+ })
+ .collect()
+ };
+ entries.into_iter().for_each(|entry| {
+ self.process_list.insert(entry.pid(), entry);
+ });
+ self.clear_procs();
+ }
+ }
+
+ #[cfg(any(target_os = "ios", feature = "apple-sandbox"))]
+ fn refresh_process_specifics(&mut self, _pid: Pid, _refresh_kind: ProcessRefreshKind) -> bool {
+ false
+ }
+
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ fn refresh_process_specifics(&mut self, pid: Pid, refresh_kind: ProcessRefreshKind) -> bool {
+ let now = get_now();
+ let arg_max = get_arg_max();
+ let port = self.port;
+ let time_interval = self.clock_info.as_mut().map(|c| c.get_time_interval(port));
+ match {
+ let wrap = Wrap(UnsafeCell::new(&mut self.process_list));
+ update_process(
+ &wrap,
+ pid,
+ arg_max as size_t,
+ time_interval,
+ now,
+ refresh_kind,
+ )
+ } {
+ Ok(Some(p)) => {
+ self.process_list.insert(p.pid(), p);
+ true
+ }
+ Ok(_) => true,
+ Err(_) => false,
+ }
+ }
+
+ #[cfg(target_os = "ios")]
+ fn refresh_disks_list(&mut self) {}
+
+ #[cfg(target_os = "macos")]
+ fn refresh_disks_list(&mut self) {
+ unsafe {
+ if self.session.0.is_null() {
+ self.session.0 = ffi::DASessionCreate(kCFAllocatorDefault as _);
+ }
+ self.disks = get_disks(self.session.0);
+ }
+ }
+
+ fn refresh_users_list(&mut self) {
+ self.users = crate::apple::users::get_users_list();
+ }
+
+ // COMMON PART
+ //
+ // Need to be moved into a "common" file to avoid duplication.
+
+ fn processes(&self) -> &HashMap<Pid, Process> {
+ &self.process_list
+ }
+
+ fn process(&self, pid: Pid) -> Option<&Process> {
+ self.process_list.get(&pid)
+ }
+
+ fn global_cpu_info(&self) -> &Cpu {
+ &self.global_cpu
+ }
+
+ fn cpus(&self) -> &[Cpu] {
+ &self.cpus
+ }
+
+ fn physical_core_count(&self) -> Option<usize> {
+ let mut physical_core_count = 0;
+
+ unsafe {
+ if get_sys_value_by_name(
+ b"hw.physicalcpu\0",
+ &mut mem::size_of::<u32>(),
+ &mut physical_core_count as *mut usize as *mut c_void,
+ ) {
+ Some(physical_core_count)
+ } else {
+ None
+ }
+ }
+ }
+
+ fn networks(&self) -> &Networks {
+ &self.networks
+ }
+
+ fn networks_mut(&mut self) -> &mut Networks {
+ &mut self.networks
+ }
+
+ fn total_memory(&self) -> u64 {
+ self.mem_total
+ }
+
+ fn free_memory(&self) -> u64 {
+ self.mem_free
+ }
+
+ fn available_memory(&self) -> u64 {
+ self.mem_available
+ }
+
+ fn used_memory(&self) -> u64 {
+ self.mem_total - self.mem_free
+ }
+
+ fn total_swap(&self) -> u64 {
+ self.swap_total
+ }
+
+ fn free_swap(&self) -> u64 {
+ self.swap_free
+ }
+
+ // TODO: need to be checked
+ fn used_swap(&self) -> u64 {
+ self.swap_total - self.swap_free
+ }
+
+ fn components(&self) -> &[Component] {
+ &self.components
+ }
+
+ fn components_mut(&mut self) -> &mut [Component] {
+ &mut self.components
+ }
+
+ fn disks(&self) -> &[Disk] {
+ &self.disks
+ }
+
+ fn disks_mut(&mut self) -> &mut [Disk] {
+ &mut self.disks
+ }
+
+ fn uptime(&self) -> u64 {
+ unsafe {
+ let csec = libc::time(::std::ptr::null_mut());
+
+ libc::difftime(csec, self.boot_time as _) as u64
+ }
+ }
+
+ fn load_average(&self) -> LoadAvg {
+ let mut loads = vec![0f64; 3];
+
+ unsafe {
+ libc::getloadavg(loads.as_mut_ptr(), 3);
+ LoadAvg {
+ one: loads[0],
+ five: loads[1],
+ fifteen: loads[2],
+ }
+ }
+ }
+
+ fn users(&self) -> &[User] {
+ &self.users
+ }
+
+ fn boot_time(&self) -> u64 {
+ self.boot_time
+ }
+
+ fn name(&self) -> Option<String> {
+ get_system_info(libc::KERN_OSTYPE, Some("Darwin"))
+ }
+
+ fn long_os_version(&self) -> Option<String> {
+ #[cfg(target_os = "macos")]
+ let friendly_name = match self.os_version().unwrap_or_default() {
+ f_n if f_n.starts_with("10.16")
+ | f_n.starts_with("11.0")
+ | f_n.starts_with("11.1")
+ | f_n.starts_with("11.2") =>
+ {
+ "Big Sur"
+ }
+ f_n if f_n.starts_with("10.15") => "Catalina",
+ f_n if f_n.starts_with("10.14") => "Mojave",
+ f_n if f_n.starts_with("10.13") => "High Sierra",
+ f_n if f_n.starts_with("10.12") => "Sierra",
+ f_n if f_n.starts_with("10.11") => "El Capitan",
+ f_n if f_n.starts_with("10.10") => "Yosemite",
+ f_n if f_n.starts_with("10.9") => "Mavericks",
+ f_n if f_n.starts_with("10.8") => "Mountain Lion",
+ f_n if f_n.starts_with("10.7") => "Lion",
+ f_n if f_n.starts_with("10.6") => "Snow Leopard",
+ f_n if f_n.starts_with("10.5") => "Leopard",
+ f_n if f_n.starts_with("10.4") => "Tiger",
+ f_n if f_n.starts_with("10.3") => "Panther",
+ f_n if f_n.starts_with("10.2") => "Jaguar",
+ f_n if f_n.starts_with("10.1") => "Puma",
+ f_n if f_n.starts_with("10.0") => "Cheetah",
+ _ => "",
+ };
+
+ #[cfg(target_os = "macos")]
+ let long_name = Some(format!(
+ "MacOS {} {}",
+ self.os_version().unwrap_or_default(),
+ friendly_name
+ ));
+
+ #[cfg(target_os = "ios")]
+ let long_name = Some(format!("iOS {}", self.os_version().unwrap_or_default()));
+
+ long_name
+ }
+
+ fn host_name(&self) -> Option<String> {
+ get_system_info(libc::KERN_HOSTNAME, None)
+ }
+
+ fn kernel_version(&self) -> Option<String> {
+ get_system_info(libc::KERN_OSRELEASE, None)
+ }
+
+ fn os_version(&self) -> Option<String> {
+ unsafe {
+ // get the size for the buffer first
+ let mut size = 0;
+ if get_sys_value_by_name(b"kern.osproductversion\0", &mut size, std::ptr::null_mut())
+ && size > 0
+ {
+ // now create a buffer with the size and get the real value
+ let mut buf = vec![0_u8; size as usize];
+
+ if get_sys_value_by_name(
+ b"kern.osproductversion\0",
+ &mut size,
+ buf.as_mut_ptr() as *mut c_void,
+ ) {
+ if let Some(pos) = buf.iter().position(|x| *x == 0) {
+ // Shrink buffer to terminate the null bytes
+ buf.resize(pos, 0);
+ }
+
+ String::from_utf8(buf).ok()
+ } else {
+ // getting the system value failed
+ None
+ }
+ } else {
+ // getting the system value failed, or did not return a buffer size
+ None
+ }
+ }
+ }
+}
+
+impl Default for System {
+ fn default() -> System {
+ System::new()
+ }
+}
+
+// code from https://github.com/Chris911/iStats
+// Not supported on iOS, or in the default macOS
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+fn get_io_service_connection() -> Option<ffi::io_connect_t> {
+ let mut master_port: mach_port_t = 0;
+ let mut iterator: ffi::io_iterator_t = 0;
+
+ unsafe {
+ ffi::IOMasterPort(libc::MACH_PORT_NULL, &mut master_port);
+
+ let matching_dictionary = ffi::IOServiceMatching(b"AppleSMC\0".as_ptr() as *const i8);
+ let result =
+ ffi::IOServiceGetMatchingServices(master_port, matching_dictionary, &mut iterator);
+ if result != ffi::KIO_RETURN_SUCCESS {
+ sysinfo_debug!("Error: IOServiceGetMatchingServices() = {}", result);
+ return None;
+ }
+
+ let device = ffi::IOIteratorNext(iterator);
+ ffi::IOObjectRelease(iterator);
+ if device == 0 {
+ sysinfo_debug!("Error: no SMC found");
+ return None;
+ }
+
+ let mut conn = 0;
+ let result = ffi::IOServiceOpen(device, libc::mach_task_self(), 0, &mut conn);
+ ffi::IOObjectRelease(device);
+ if result != ffi::KIO_RETURN_SUCCESS {
+ sysinfo_debug!("Error: IOServiceOpen() = {}", result);
+ return None;
+ }
+
+ Some(conn)
+ }
+}
+
+#[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+fn get_arg_max() -> usize {
+ let mut mib = [libc::CTL_KERN, libc::KERN_ARGMAX];
+ let mut arg_max = 0i32;
+ let mut size = mem::size_of::<c_int>();
+ unsafe {
+ if sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ (&mut arg_max) as *mut i32 as *mut c_void,
+ &mut size,
+ std::ptr::null_mut(),
+ 0,
+ ) == -1
+ {
+ 4096 // We default to this value
+ } else {
+ arg_max as usize
+ }
+ }
+}
+
+pub(crate) unsafe fn get_sys_value(
+ high: u32,
+ low: u32,
+ mut len: usize,
+ value: *mut c_void,
+ mib: &mut [i32; 2],
+) -> bool {
+ mib[0] = high as i32;
+ mib[1] = low as i32;
+ sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ value,
+ &mut len as *mut usize,
+ std::ptr::null_mut(),
+ 0,
+ ) == 0
+}
+
+unsafe fn get_sys_value_by_name(name: &[u8], len: &mut usize, value: *mut c_void) -> bool {
+ sysctlbyname(
+ name.as_ptr() as *const c_char,
+ value,
+ len,
+ std::ptr::null_mut(),
+ 0,
+ ) == 0
+}
+
+fn get_system_info(value: c_int, default: Option<&str>) -> Option<String> {
+ let mut mib: [c_int; 2] = [libc::CTL_KERN, value];
+ let mut size = 0;
+
+ unsafe {
+ // Call first to get size
+ sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ std::ptr::null_mut(),
+ &mut size,
+ std::ptr::null_mut(),
+ 0,
+ );
+
+ // exit early if we did not update the size
+ if size == 0 {
+ default.map(|s| s.to_owned())
+ } else {
+ // set the buffer to the correct size
+ let mut buf = vec![0_u8; size as usize];
+
+ if sysctl(
+ mib.as_mut_ptr(),
+ mib.len() as _,
+ buf.as_mut_ptr() as _,
+ &mut size,
+ std::ptr::null_mut(),
+ 0,
+ ) == -1
+ {
+ // If command fails return default
+ default.map(|s| s.to_owned())
+ } else {
+ if let Some(pos) = buf.iter().position(|x| *x == 0) {
+ // Shrink buffer to terminate the null bytes
+ buf.resize(pos, 0);
+ }
+
+ String::from_utf8(buf).ok()
+ }
+ }
+ }
+}
diff --git a/vendor/sysinfo/src/apple/users.rs b/vendor/sysinfo/src/apple/users.rs
new file mode 100644
index 000000000..690aceee1
--- /dev/null
+++ b/vendor/sysinfo/src/apple/users.rs
@@ -0,0 +1,178 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::{
+ common::{Gid, Uid},
+ User,
+};
+
+use crate::sys::utils;
+use libc::{c_char, endpwent, getgrgid, getgrouplist, getpwent, gid_t, setpwent, strlen};
+
+fn get_user_groups(name: *const c_char, group_id: gid_t) -> Vec<String> {
+ let mut add = 0;
+
+ loop {
+ let mut nb_groups = 256 + add;
+ let mut groups = Vec::with_capacity(nb_groups as _);
+ unsafe {
+ if getgrouplist(name, group_id as _, groups.as_mut_ptr(), &mut nb_groups) == -1 {
+ add += 100;
+ continue;
+ }
+ groups.set_len(nb_groups as _);
+ return groups
+ .into_iter()
+ .filter_map(|g| {
+ let group = getgrgid(g as _);
+ if group.is_null() {
+ return None;
+ }
+ utils::cstr_to_rust((*group).gr_name)
+ })
+ .collect();
+ }
+ }
+}
+
+fn endswith(s1: *const c_char, s2: &[u8]) -> bool {
+ if s1.is_null() {
+ return false;
+ }
+ unsafe {
+ let mut len = strlen(s1) as isize - 1;
+ let mut i = s2.len() as isize - 1;
+ while len >= 0 && i >= 0 && *s1.offset(len) == s2[i as usize] as _ {
+ i -= 1;
+ len -= 1;
+ }
+ i == -1
+ }
+}
+
+fn users_list<F>(filter: F) -> Vec<User>
+where
+ F: Fn(*const c_char, u32) -> bool,
+{
+ let mut users = Vec::new();
+
+ unsafe {
+ setpwent();
+ loop {
+ let pw = getpwent();
+ if pw.is_null() {
+ break;
+ }
+
+ if !filter((*pw).pw_shell, (*pw).pw_uid) {
+ // This is not a "real" or "local" user.
+ continue;
+ }
+
+ let groups = get_user_groups((*pw).pw_name, (*pw).pw_gid);
+ let uid = (*pw).pw_uid;
+ let gid = (*pw).pw_gid;
+ if let Some(name) = utils::cstr_to_rust((*pw).pw_name) {
+ users.push(User {
+ uid: Uid(uid),
+ gid: Gid(gid),
+ name,
+ groups,
+ });
+ }
+ }
+ endpwent();
+ }
+ users.sort_unstable_by(|x, y| x.name.partial_cmp(&y.name).unwrap());
+ users.dedup_by(|a, b| a.name == b.name);
+ users
+}
+
+pub(crate) fn get_users_list() -> Vec<User> {
+ users_list(|shell, uid| {
+ !endswith(shell, b"/false") && !endswith(shell, b"/uucico") && uid < 65536
+ })
+}
+
+// This was the OSX-based solution. It provides enough information, but what a mess!
+// pub fn get_users_list() -> Vec<User> {
+// let mut users = Vec::new();
+// let node_name = b"/Local/Default\0";
+
+// unsafe {
+// let node_name = ffi::CFStringCreateWithCStringNoCopy(
+// std::ptr::null_mut(),
+// node_name.as_ptr() as *const c_char,
+// ffi::kCFStringEncodingMacRoman,
+// ffi::kCFAllocatorNull as *mut c_void,
+// );
+// let node_ref = ffi::ODNodeCreateWithName(
+// ffi::kCFAllocatorDefault,
+// ffi::kODSessionDefault,
+// node_name,
+// std::ptr::null_mut(),
+// );
+// let query = ffi::ODQueryCreateWithNode(
+// ffi::kCFAllocatorDefault,
+// node_ref,
+// ffi::kODRecordTypeUsers as _, // kODRecordTypeGroups
+// std::ptr::null(),
+// 0,
+// std::ptr::null(),
+// std::ptr::null(),
+// 0,
+// std::ptr::null_mut(),
+// );
+// if query.is_null() {
+// return users;
+// }
+// let results = ffi::ODQueryCopyResults(
+// query,
+// false as _,
+// std::ptr::null_mut(),
+// );
+// let len = ffi::CFArrayGetCount(results);
+// for i in 0..len {
+// let name = match get_user_name(ffi::CFArrayGetValueAtIndex(results, i)) {
+// Some(n) => n,
+// None => continue,
+// };
+// let groups = get_user_groups(&name);
+// users.push(User { name });
+// }
+
+// ffi::CFRelease(results as *const c_void);
+// ffi::CFRelease(query as *const c_void);
+// ffi::CFRelease(node_ref as *const c_void);
+// ffi::CFRelease(node_name as *const c_void);
+// }
+// users.sort_unstable_by(|x, y| x.name.partial_cmp(&y.name).unwrap());
+// return users;
+// }
+
+// fn get_user_name(result: *const c_void) -> Option<String> {
+// let user_name = ffi::ODRecordGetRecordName(result as _);
+// let ptr = ffi::CFStringGetCharactersPtr(user_name);
+// String::from_utf16(&if ptr.is_null() {
+// let len = ffi::CFStringGetLength(user_name); // It returns the len in UTF-16 code pairs.
+// if len == 0 {
+// continue;
+// }
+// let mut v = Vec::with_capacity(len as _);
+// for x in 0..len {
+// v.push(ffi::CFStringGetCharacterAtIndex(user_name, x));
+// }
+// v
+// } else {
+// let mut v: Vec<u16> = Vec::new();
+// let mut x = 0;
+// loop {
+// let letter = *ptr.offset(x);
+// if letter == 0 {
+// break;
+// }
+// v.push(letter);
+// x += 1;
+// }
+// v
+// }.ok()
+// }
diff --git a/vendor/sysinfo/src/apple/utils.rs b/vendor/sysinfo/src/apple/utils.rs
new file mode 100644
index 000000000..019295b95
--- /dev/null
+++ b/vendor/sysinfo/src/apple/utils.rs
@@ -0,0 +1,39 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use libc::c_char;
+
+pub(crate) fn cstr_to_rust(c: *const c_char) -> Option<String> {
+ cstr_to_rust_with_size(c, None)
+}
+
+pub(crate) fn cstr_to_rust_with_size(c: *const c_char, size: Option<usize>) -> Option<String> {
+ if c.is_null() {
+ return None;
+ }
+ let mut s = match size {
+ Some(len) => Vec::with_capacity(len),
+ None => Vec::new(),
+ };
+ let mut i = 0;
+ unsafe {
+ loop {
+ let value = *c.offset(i) as u8;
+ if value == 0 {
+ break;
+ }
+ s.push(value);
+ i += 1;
+ }
+ String::from_utf8(s).ok()
+ }
+}
+
+#[cfg(target_os = "macos")]
+pub(crate) fn vec_to_rust(buf: Vec<i8>) -> Option<String> {
+ String::from_utf8(
+ buf.into_iter()
+ .flat_map(|b| if b > 0 { Some(b as u8) } else { None })
+ .collect(),
+ )
+ .ok()
+}