summaryrefslogtreecommitdiffstats
path: root/vendor/sysinfo-0.26.7/src/apple
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /vendor/sysinfo-0.26.7/src/apple
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/sysinfo-0.26.7/src/apple')
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/app_store/component.rs26
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/app_store/mod.rs4
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/app_store/process.rs84
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/component.rs3
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/cpu.rs331
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/disk.rs395
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/ffi.rs38
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/ios.rs5
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/component/arm.rs179
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/component/mod.rs13
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/component/x86.rs326
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/disk.rs126
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/ffi.rs291
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/mod.rs20
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/process.rs688
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/system.rs136
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/macos/utils.rs30
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/mod.rs32
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/network.rs240
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/process.rs83
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/system.rs691
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/users.rs178
-rw-r--r--vendor/sysinfo-0.26.7/src/apple/utils.rs71
23 files changed, 3990 insertions, 0 deletions
diff --git a/vendor/sysinfo-0.26.7/src/apple/app_store/component.rs b/vendor/sysinfo-0.26.7/src/apple/app_store/component.rs
new file mode 100644
index 000000000..914fc9406
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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-0.26.7/src/apple/app_store/mod.rs b/vendor/sysinfo-0.26.7/src/apple/app_store/mod.rs
new file mode 100644
index 000000000..0df24cabf
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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-0.26.7/src/apple/app_store/process.rs b/vendor/sysinfo-0.26.7/src/apple/app_store/process.rs
new file mode 100644
index 000000000..7c43697a6
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/app_store/process.rs
@@ -0,0 +1,84 @@
+// 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
+ }
+
+ fn wait(&self) {}
+}
diff --git a/vendor/sysinfo-0.26.7/src/apple/component.rs b/vendor/sysinfo-0.26.7/src/apple/component.rs
new file mode 100644
index 000000000..7c4196e72
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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-0.26.7/src/apple/cpu.rs b/vendor/sysinfo-0.26.7/src/apple/cpu.rs
new file mode 100644
index 000000000..e613bdd2c
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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(':').nth(1).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(':').nth(1).unwrap();
+ assert_eq!(cpus[0].brand(), sysctl_value.trim());
+ }
+ }
+}
diff --git a/vendor/sysinfo-0.26.7/src/apple/disk.rs b/vendor/sysinfo-0.26.7/src/apple/disk.rs
new file mode 100644
index 000000000..d866d5bba
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/disk.rs
@@ -0,0 +1,395 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::sys::{
+ ffi,
+ utils::{self, CFReleaser},
+};
+use crate::{DiskExt, DiskType};
+
+use core_foundation_sys::array::CFArrayCreate;
+use core_foundation_sys::base::kCFAllocatorDefault;
+use core_foundation_sys::dictionary::{CFDictionaryGetValueIfPresent, CFDictionaryRef};
+use core_foundation_sys::number::{kCFBooleanTrue, CFBooleanRef, CFNumberGetValue};
+use core_foundation_sys::string::{self as cfs, CFStringRef};
+
+use libc::c_void;
+
+use std::ffi::{CStr, OsStr, OsString};
+use std::os::unix::ffi::OsStrExt;
+use std::path::{Path, PathBuf};
+use std::ptr;
+
+#[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,
+ volume_url: RetainedCFURL,
+ 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 {
+ if let Some(requested_properties) = build_requested_properties(&[
+ ffi::kCFURLVolumeAvailableCapacityKey,
+ ffi::kCFURLVolumeAvailableCapacityForImportantUsageKey,
+ ]) {
+ match get_disk_properties(&self.volume_url, &requested_properties) {
+ Some(disk_props) => {
+ self.available_space = get_available_volume_space(&disk_props);
+ true
+ }
+ None => false,
+ }
+ } else {
+ sysinfo_debug!("failed to create volume key list, skipping refresh");
+ false
+ }
+ }
+ }
+}
+
+pub(super) unsafe fn get_disks() -> Vec<Disk> {
+ let raw_disks = {
+ let count = libc::getfsstat(ptr::null_mut(), 0, libc::MNT_NOWAIT);
+ if count < 1 {
+ return Vec::new();
+ }
+ let bufsize = count * std::mem::size_of::<libc::statfs>() as libc::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 usize);
+
+ disks
+ };
+
+ // Create a list of properties about the disk that we want to fetch.
+ let requested_properties = match build_requested_properties(&[
+ ffi::kCFURLVolumeIsEjectableKey,
+ ffi::kCFURLVolumeIsRemovableKey,
+ ffi::kCFURLVolumeIsInternalKey,
+ ffi::kCFURLVolumeTotalCapacityKey,
+ ffi::kCFURLVolumeAvailableCapacityForImportantUsageKey,
+ ffi::kCFURLVolumeAvailableCapacityKey,
+ ffi::kCFURLVolumeNameKey,
+ ffi::kCFURLVolumeIsBrowsableKey,
+ ffi::kCFURLVolumeIsLocalKey,
+ ]) {
+ Some(properties) => properties,
+ None => {
+ sysinfo_debug!("failed to create volume key list");
+ return Vec::new();
+ }
+ };
+
+ let mut disks = Vec::with_capacity(raw_disks.len());
+ for c_disk in raw_disks {
+ let volume_url = match CFReleaser::new(
+ core_foundation_sys::url::CFURLCreateFromFileSystemRepresentation(
+ kCFAllocatorDefault,
+ c_disk.f_mntonname.as_ptr() as *const _,
+ c_disk.f_mntonname.len() as _,
+ false as _,
+ ),
+ ) {
+ Some(url) => url,
+ None => {
+ sysinfo_debug!("getfsstat returned incompatible paths");
+ continue;
+ }
+ };
+
+ let prop_dict = match get_disk_properties(&volume_url, &requested_properties) {
+ Some(props) => props,
+ None => continue,
+ };
+
+ // Future note: There is a difference between `kCFURLVolumeIsBrowsableKey` and the
+ // `kCFURLEnumeratorSkipInvisibles` option of `CFURLEnumeratorOptions`. Specifically,
+ // the first one considers the writable `Data`(`/System/Volumes/Data`) partition to be
+ // browsable, while it is classified as "invisible" by CoreFoundation's volume emumerator.
+ let browsable = get_bool_value(
+ prop_dict.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeIsBrowsableKey),
+ )
+ .unwrap_or_default();
+
+ // Do not return invisible "disks". Most of the time, these are APFS snapshots, hidden
+ // system volumes, etc. Browsable is defined to be visible in the system's UI like Finder,
+ // disk utility, system information, etc.
+ //
+ // To avoid seemingly duplicating many disks and creating an inaccurate view of the system's resources,
+ // these are skipped entirely.
+ if !browsable {
+ continue;
+ }
+
+ let local_only = get_bool_value(
+ prop_dict.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeIsLocalKey),
+ )
+ .unwrap_or(true);
+
+ // Skip any drive that is not locally attached to the system.
+ //
+ // This includes items like SMB mounts, and matches the other platform's behavior.
+ if !local_only {
+ continue;
+ }
+
+ let mount_point = PathBuf::from(OsStr::from_bytes(
+ CStr::from_ptr(c_disk.f_mntonname.as_ptr()).to_bytes(),
+ ));
+
+ disks.extend(new_disk(mount_point, volume_url, c_disk, &prop_dict))
+ }
+
+ disks
+}
+
+type RetainedCFArray = CFReleaser<core_foundation_sys::array::__CFArray>;
+type RetainedCFDictionary = CFReleaser<core_foundation_sys::dictionary::__CFDictionary>;
+type RetainedCFURL = CFReleaser<core_foundation_sys::url::__CFURL>;
+
+unsafe fn build_requested_properties(properties: &[CFStringRef]) -> Option<RetainedCFArray> {
+ CFReleaser::new(CFArrayCreate(
+ ptr::null_mut(),
+ properties.as_ptr() as *const *const c_void,
+ properties.len() as _,
+ &core_foundation_sys::array::kCFTypeArrayCallBacks,
+ ))
+}
+
+fn get_disk_properties(
+ volume_url: &RetainedCFURL,
+ requested_properties: &RetainedCFArray,
+) -> Option<RetainedCFDictionary> {
+ CFReleaser::new(unsafe {
+ ffi::CFURLCopyResourcePropertiesForKeys(
+ volume_url.inner(),
+ requested_properties.inner(),
+ ptr::null_mut(),
+ )
+ })
+}
+
+fn get_available_volume_space(disk_props: &RetainedCFDictionary) -> u64 {
+ // We prefer `AvailableCapacityForImportantUsage` over `AvailableCapacity` because
+ // it takes more of the system's properties into account, like the trash, system-managed caches,
+ // etc. It generally also returns higher values too, because of the above, so it's a more accurate
+ // representation of what the system _could_ still use.
+ unsafe {
+ get_int_value(
+ disk_props.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeAvailableCapacityForImportantUsageKey),
+ )
+ .filter(|bytes| *bytes != 0)
+ .or_else(|| {
+ get_int_value(
+ disk_props.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeAvailableCapacityKey),
+ )
+ })
+ }
+ .unwrap_or_default() as u64
+}
+
+pub(super) enum DictKey {
+ Extern(CFStringRef),
+ #[cfg(target_os = "macos")]
+ Defined(&'static str),
+}
+
+unsafe fn get_dict_value<T, F: FnOnce(*const c_void) -> Option<T>>(
+ dict: CFDictionaryRef,
+ key: DictKey,
+ callback: F,
+) -> Option<T> {
+ #[cfg(target_os = "macos")]
+ let _defined;
+ let key = match key {
+ DictKey::Extern(val) => val,
+ #[cfg(target_os = "macos")]
+ DictKey::Defined(val) => {
+ _defined = CFReleaser::new(cfs::CFStringCreateWithBytesNoCopy(
+ kCFAllocatorDefault,
+ val.as_ptr(),
+ val.len() as _,
+ cfs::kCFStringEncodingUTF8,
+ false as _,
+ core_foundation_sys::base::kCFAllocatorNull,
+ ))?;
+
+ _defined.inner()
+ }
+ };
+
+ let mut value = std::ptr::null();
+ if CFDictionaryGetValueIfPresent(dict, key.cast(), &mut value) != 0 {
+ callback(value)
+ } else {
+ None
+ }
+}
+
+pub(super) unsafe fn get_str_value(dict: CFDictionaryRef, key: DictKey) -> Option<String> {
+ get_dict_value(dict, key, |v| {
+ let v = v as cfs::CFStringRef;
+
+ let len_utf16 = cfs::CFStringGetLength(v) as usize;
+ let len_bytes = len_utf16 * 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: DictKey) -> Option<bool> {
+ get_dict_value(dict, key, |v| Some(v as CFBooleanRef == kCFBooleanTrue))
+}
+
+unsafe fn get_int_value(dict: CFDictionaryRef, key: DictKey) -> Option<i64> {
+ get_dict_value(dict, key, |v| {
+ let mut val: i64 = 0;
+ if CFNumberGetValue(
+ v.cast(),
+ core_foundation_sys::number::kCFNumberSInt64Type,
+ &mut val as *mut i64 as *mut c_void,
+ ) {
+ Some(val)
+ } else {
+ None
+ }
+ })
+}
+
+unsafe fn new_disk(
+ mount_point: PathBuf,
+ volume_url: RetainedCFURL,
+ c_disk: libc::statfs,
+ disk_props: &RetainedCFDictionary,
+) -> Option<Disk> {
+ // IOKit is not available on any but the most recent (16+) iOS and iPadOS versions.
+ // Due to this, we can't query the medium type. All iOS devices use flash-based storage
+ // so we just assume the disk type is an SSD until Rust has a way to conditionally link to
+ // IOKit in more recent deployment versions.
+ #[cfg(target_os = "macos")]
+ let type_ = crate::sys::inner::disk::get_disk_type(&c_disk).unwrap_or(DiskType::Unknown(-1));
+ #[cfg(not(target_os = "macos"))]
+ let type_ = DiskType::SSD;
+
+ // Note: Since we requested these properties from the system, we don't expect
+ // these property retrievals to fail.
+
+ let name = get_str_value(
+ disk_props.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeNameKey),
+ )
+ .map(OsString::from)?;
+
+ let is_removable = {
+ let ejectable = get_bool_value(
+ disk_props.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeIsEjectableKey),
+ )
+ .unwrap_or_default();
+
+ let removable = get_bool_value(
+ disk_props.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeIsRemovableKey),
+ )
+ .unwrap_or_default();
+
+ let is_removable = ejectable || removable;
+
+ if is_removable {
+ is_removable
+ } else {
+ // If neither `ejectable` or `removable` return `true`, fallback to checking
+ // if the disk is attached to the internal system.
+ let internal = get_bool_value(
+ disk_props.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeIsInternalKey),
+ )
+ .unwrap_or_default();
+
+ !internal
+ }
+ };
+
+ let total_space = get_int_value(
+ disk_props.inner(),
+ DictKey::Extern(ffi::kCFURLVolumeTotalCapacityKey),
+ )? as u64;
+
+ let available_space = get_available_volume_space(disk_props);
+
+ let file_system = IntoIterator::into_iter(c_disk.f_fstypename)
+ .filter_map(|b| if b != 0 { Some(b as u8) } else { None })
+ .collect();
+
+ Some(Disk {
+ type_,
+ name,
+ file_system,
+ mount_point,
+ volume_url,
+ total_space,
+ available_space,
+ is_removable,
+ })
+}
diff --git a/vendor/sysinfo-0.26.7/src/apple/ffi.rs b/vendor/sysinfo-0.26.7/src/apple/ffi.rs
new file mode 100644
index 000000000..72822202f
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/ffi.rs
@@ -0,0 +1,38 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use core_foundation_sys::{
+ array::CFArrayRef, dictionary::CFDictionaryRef, error::CFErrorRef, string::CFStringRef,
+ url::CFURLRef,
+};
+
+// Reexport items defined in either macos or ios ffi module.
+pub use crate::sys::inner::ffi::*;
+
+#[link(name = "CoreFoundation", kind = "framework")]
+extern "C" {
+ pub fn CFURLCopyResourcePropertiesForKeys(
+ url: CFURLRef,
+ keys: CFArrayRef,
+ error: *mut CFErrorRef,
+ ) -> CFDictionaryRef;
+
+ pub static kCFURLVolumeIsEjectableKey: CFStringRef;
+ pub static kCFURLVolumeIsRemovableKey: CFStringRef;
+ pub static kCFURLVolumeAvailableCapacityKey: CFStringRef;
+ pub static kCFURLVolumeAvailableCapacityForImportantUsageKey: CFStringRef;
+ pub static kCFURLVolumeTotalCapacityKey: CFStringRef;
+ pub static kCFURLVolumeNameKey: CFStringRef;
+ pub static kCFURLVolumeIsLocalKey: CFStringRef;
+ pub static kCFURLVolumeIsInternalKey: CFStringRef;
+ pub static kCFURLVolumeIsBrowsableKey: CFStringRef;
+}
+
+#[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-0.26.7/src/apple/ios.rs b/vendor/sysinfo-0.26.7/src/apple/ios.rs
new file mode 100644
index 000000000..0393c5ec6
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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-0.26.7/src/apple/macos/component/arm.rs b/vendor/sysinfo-0.26.7/src/apple/macos/component/arm.rs
new file mode 100644
index 000000000..328ffebfa
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/component/arm.rs
@@ -0,0 +1,179 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use std::ffi::CStr;
+
+use core_foundation_sys::array::{CFArrayGetCount, CFArrayGetValueAtIndex};
+use core_foundation_sys::base::{kCFAllocatorDefault, CFRetain};
+use core_foundation_sys::string::{
+ kCFStringEncodingUTF8, CFStringCreateWithBytes, CFStringGetCStringPtr,
+};
+
+use crate::apple::inner::ffi::{
+ kHIDPage_AppleVendor, kHIDUsage_AppleVendor_TemperatureSensor, kIOHIDEventTypeTemperature,
+ matching, IOHIDEventFieldBase, IOHIDEventGetFloatValue, IOHIDEventSystemClientCopyServices,
+ IOHIDEventSystemClientCreate, IOHIDEventSystemClientSetMatching, IOHIDServiceClientCopyEvent,
+ IOHIDServiceClientCopyProperty, __IOHIDEventSystemClient, __IOHIDServiceClient,
+ HID_DEVICE_PROPERTY_PRODUCT,
+};
+use crate::sys::utils::CFReleaser;
+use crate::ComponentExt;
+
+pub(crate) struct Components {
+ pub inner: Vec<Component>,
+ client: Option<CFReleaser<__IOHIDEventSystemClient>>,
+}
+
+impl Components {
+ pub(crate) fn new() -> Self {
+ Self {
+ inner: vec![],
+ client: None,
+ }
+ }
+
+ pub(crate) fn refresh(&mut self) {
+ self.inner.clear();
+
+ unsafe {
+ let matches = match CFReleaser::new(matching(
+ kHIDPage_AppleVendor,
+ kHIDUsage_AppleVendor_TemperatureSensor,
+ )) {
+ Some(m) => m,
+ None => return,
+ };
+
+ if self.client.is_none() {
+ let client =
+ match CFReleaser::new(IOHIDEventSystemClientCreate(kCFAllocatorDefault)) {
+ Some(c) => c,
+ None => return,
+ };
+ // Without this call, client is freed during the execution of the program. It must be kept!
+ CFRetain(client.inner() as _);
+ self.client = Some(client);
+ }
+
+ let client = self.client.as_ref().unwrap();
+
+ let _ = IOHIDEventSystemClientSetMatching(client.inner(), matches.inner());
+
+ let services = match CFReleaser::new(IOHIDEventSystemClientCopyServices(client.inner()))
+ {
+ Some(s) => s,
+ None => return,
+ };
+
+ let key_ref = match CFReleaser::new(CFStringCreateWithBytes(
+ kCFAllocatorDefault,
+ HID_DEVICE_PROPERTY_PRODUCT.as_ptr(),
+ HID_DEVICE_PROPERTY_PRODUCT.len() as _,
+ kCFStringEncodingUTF8,
+ false as _,
+ )) {
+ Some(r) => r,
+ None => return,
+ };
+
+ let count = CFArrayGetCount(services.inner());
+
+ for i in 0..count {
+ let service = match CFReleaser::new(
+ CFArrayGetValueAtIndex(services.inner(), i) as *const _
+ ) {
+ Some(s) => s,
+ None => continue,
+ };
+
+ let name = match CFReleaser::new(IOHIDServiceClientCopyProperty(
+ service.inner(),
+ key_ref.inner(),
+ )) {
+ Some(n) => n,
+ None => continue,
+ };
+
+ let name_ptr =
+ CFStringGetCStringPtr(name.inner() as *const _, kCFStringEncodingUTF8);
+ let name_str = CStr::from_ptr(name_ptr).to_string_lossy().to_string();
+
+ let mut component = Component::new(name_str, None, None, service);
+ component.refresh();
+
+ self.inner.push(component);
+ }
+ }
+ }
+}
+
+unsafe impl Send for Components {}
+unsafe impl Sync for Components {}
+
+#[doc = include_str!("../../../../md_doc/component.md")]
+pub struct Component {
+ service: CFReleaser<__IOHIDServiceClient>,
+ temperature: f32,
+ label: String,
+ max: f32,
+ critical: Option<f32>,
+}
+
+impl Component {
+ pub(crate) fn new(
+ label: String,
+ max: Option<f32>,
+ critical: Option<f32>,
+ service: CFReleaser<__IOHIDServiceClient>,
+ ) -> Self {
+ Self {
+ service,
+ label,
+ max: max.unwrap_or(0.),
+ critical,
+ temperature: 0.,
+ }
+ }
+}
+
+unsafe impl Send for Component {}
+unsafe impl Sync for Component {}
+
+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) {
+ unsafe {
+ let event = match CFReleaser::new(IOHIDServiceClientCopyEvent(
+ self.service.inner() as *const _,
+ kIOHIDEventTypeTemperature,
+ 0,
+ 0,
+ )) {
+ Some(e) => e,
+ None => return,
+ };
+
+ self.temperature = IOHIDEventGetFloatValue(
+ event.inner(),
+ IOHIDEventFieldBase(kIOHIDEventTypeTemperature),
+ ) as _;
+ if self.temperature > self.max {
+ self.max = self.temperature;
+ }
+ }
+ }
+}
diff --git a/vendor/sysinfo-0.26.7/src/apple/macos/component/mod.rs b/vendor/sysinfo-0.26.7/src/apple/macos/component/mod.rs
new file mode 100644
index 000000000..50b359e61
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/component/mod.rs
@@ -0,0 +1,13 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub(crate) mod x86;
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub use self::x86::*;
+
+#[cfg(target_arch = "aarch64")]
+pub(crate) mod arm;
+
+#[cfg(target_arch = "aarch64")]
+pub use self::arm::*;
diff --git a/vendor/sysinfo-0.26.7/src/apple/macos/component/x86.rs b/vendor/sysinfo-0.26.7/src/apple/macos/component/x86.rs
new file mode 100644
index 000000000..415f90455
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/component/x86.rs
@@ -0,0 +1,326 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::sys::{ffi, macos::utils::IOReleaser};
+use crate::ComponentExt;
+
+use libc::{c_char, c_int, c_void};
+
+use std::mem;
+
+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,
+ /// It is the `System::connection`. We need it to not require an extra argument
+ /// in `ComponentExt::refresh`.
+ connection: ffi::io_connect_t,
+}
+
+impl ComponentFFI {
+ fn new(key: &[i8], connection: ffi::io_connect_t) -> Option<ComponentFFI> {
+ unsafe {
+ get_key_size(connection, key)
+ .ok()
+ .map(|(input_structure, val)| ComponentFFI {
+ input_structure,
+ val,
+ connection,
+ })
+ }
+ }
+
+ fn temperature(&self) -> Option<f32> {
+ get_temperature_inner(self.connection, &self.input_structure, &self.val)
+ }
+}
+
+/// Used to get CPU information, not supported on iOS, or inside the default macOS sandbox.
+pub(crate) struct Components {
+ pub inner: Vec<Component>,
+ connection: Option<IoService>,
+}
+
+impl Components {
+ pub(crate) fn new() -> Self {
+ Self {
+ inner: Vec::with_capacity(2),
+ connection: IoService::new_connection(),
+ }
+ }
+
+ pub(crate) fn refresh(&mut self) {
+ if let Some(ref connection) = self.connection {
+ let connection = connection.inner();
+ self.inner.clear();
+ // getting CPU critical temperature
+ let critical_temp =
+ get_temperature(connection, &['T' as i8, 'C' as i8, '0' as i8, 'D' as i8, 0]);
+
+ for (id, v) in COMPONENTS_TEMPERATURE_IDS.iter() {
+ if let Some(c) =
+ Component::new((*id).to_owned(), None, critical_temp, v, connection)
+ {
+ self.inner.push(c);
+ }
+ }
+ }
+ }
+}
+
+#[doc = include_str!("../../../../md_doc/component.md")]
+pub struct Component {
+ temperature: f32,
+ max: f32,
+ critical: Option<f32>,
+ label: String,
+ ffi_part: ComponentFFI,
+}
+
+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().map(|temperature| Component {
+ temperature,
+ label,
+ max: max.unwrap_or(temperature),
+ critical,
+ ffi_part,
+ })
+ }
+}
+
+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.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
+}
+
+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)
+ }
+}
+
+pub(crate) struct IoService(ffi::io_connect_t);
+
+impl IoService {
+ fn new(obj: ffi::io_connect_t) -> Option<Self> {
+ if obj == 0 {
+ None
+ } else {
+ Some(Self(obj))
+ }
+ }
+
+ pub(crate) fn inner(&self) -> ffi::io_connect_t {
+ self.0
+ }
+
+ // code from https://github.com/Chris911/iStats
+ // Not supported on iOS, or in the default macOS
+ pub(crate) fn new_connection() -> Option<Self> {
+ let mut iterator: ffi::io_iterator_t = 0;
+
+ unsafe {
+ let matching_dictionary = ffi::IOServiceMatching(b"AppleSMC\0".as_ptr() as *const i8);
+ let result = ffi::IOServiceGetMatchingServices(
+ ffi::kIOMasterPortDefault,
+ matching_dictionary,
+ &mut iterator,
+ );
+ if result != ffi::KIO_RETURN_SUCCESS {
+ sysinfo_debug!("Error: IOServiceGetMatchingServices() = {}", result);
+ return None;
+ }
+ let iterator = match IOReleaser::new(iterator) {
+ Some(i) => i,
+ None => {
+ sysinfo_debug!("Error: IOServiceGetMatchingServices() succeeded but returned invalid descriptor");
+ return None;
+ }
+ };
+
+ let device = match IOReleaser::new(ffi::IOIteratorNext(iterator.inner())) {
+ Some(d) => d,
+ None => {
+ sysinfo_debug!("Error: no SMC found");
+ return None;
+ }
+ };
+
+ let mut conn = 0;
+ let result = ffi::IOServiceOpen(device.inner(), libc::mach_task_self(), 0, &mut conn);
+ if result != ffi::KIO_RETURN_SUCCESS {
+ sysinfo_debug!("Error: IOServiceOpen() = {}", result);
+ return None;
+ }
+ let conn = IoService::new(conn);
+ if conn.is_none() {
+ sysinfo_debug!(
+ "Error: IOServiceOpen() succeeded but returned invalid descriptor..."
+ );
+ }
+ conn
+ }
+ }
+}
+
+impl Drop for IoService {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::IOServiceClose(self.0);
+ }
+ }
+}
diff --git a/vendor/sysinfo-0.26.7/src/apple/macos/disk.rs b/vendor/sysinfo-0.26.7/src/apple/macos/disk.rs
new file mode 100644
index 000000000..3a4372a2f
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/disk.rs
@@ -0,0 +1,126 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::sys::ffi;
+use crate::sys::{
+ disk::{get_str_value, DictKey},
+ macos::utils::IOReleaser,
+ utils::CFReleaser,
+};
+use crate::DiskType;
+
+use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull};
+use core_foundation_sys::string as cfs;
+
+use std::ffi::CStr;
+
+pub(crate) fn get_disk_type(disk: &libc::statfs) -> Option<DiskType> {
+ let characteristics_string = unsafe {
+ CFReleaser::new(cfs::CFStringCreateWithBytesNoCopy(
+ kCFAllocatorDefault,
+ ffi::kIOPropertyDeviceCharacteristicsKey.as_ptr(),
+ ffi::kIOPropertyDeviceCharacteristicsKey.len() as _,
+ cfs::kCFStringEncodingUTF8,
+ false as _,
+ kCFAllocatorNull,
+ ))?
+ };
+
+ // Removes `/dev/` from the value.
+ let bsd_name = unsafe {
+ CStr::from_ptr(disk.f_mntfromname.as_ptr())
+ .to_bytes()
+ .strip_prefix(b"/dev/")
+ .or_else(|| {
+ sysinfo_debug!("unknown disk mount path format");
+ None
+ })?
+ };
+
+ // We don't need to wrap this in an auto-releaser because the following call to `IOServiceGetMatchingServices`
+ // will take ownership of one retain reference.
+ let matching =
+ unsafe { ffi::IOBSDNameMatching(ffi::kIOMasterPortDefault, 0, bsd_name.as_ptr().cast()) };
+
+ if matching.is_null() {
+ return None;
+ }
+
+ let mut service_iterator: ffi::io_iterator_t = 0;
+
+ if unsafe {
+ ffi::IOServiceGetMatchingServices(
+ ffi::kIOMasterPortDefault,
+ matching.cast(),
+ &mut service_iterator,
+ )
+ } != libc::KERN_SUCCESS
+ {
+ return None;
+ }
+
+ // Safety: We checked for success, so there is always a valid iterator, even if its empty.
+ let service_iterator = unsafe { IOReleaser::new_unchecked(service_iterator) };
+
+ let mut parent_entry: ffi::io_registry_entry_t = 0;
+
+ while let Some(mut current_service_entry) =
+ IOReleaser::new(unsafe { ffi::IOIteratorNext(service_iterator.inner()) })
+ {
+ // Note: This loop is required in a non-obvious way. Due to device properties existing as a tree
+ // in IOKit, we may need an arbitrary number of calls to `IORegistryEntryCreateCFProperty` in order to find
+ // the values we are looking for. The function may return nothing if we aren't deep enough into the registry
+ // tree, so we need to continue going from child->parent node until its found.
+ loop {
+ if unsafe {
+ ffi::IORegistryEntryGetParentEntry(
+ current_service_entry.inner(),
+ ffi::kIOServicePlane.as_ptr().cast(),
+ &mut parent_entry,
+ )
+ } != libc::KERN_SUCCESS
+ {
+ break;
+ }
+
+ current_service_entry = match IOReleaser::new(parent_entry) {
+ Some(service) => service,
+ // There were no more parents left
+ None => break,
+ };
+
+ let properties_result = unsafe {
+ CFReleaser::new(ffi::IORegistryEntryCreateCFProperty(
+ current_service_entry.inner(),
+ characteristics_string.inner(),
+ kCFAllocatorDefault,
+ 0,
+ ))
+ };
+
+ if let Some(device_properties) = properties_result {
+ let disk_type = unsafe {
+ super::disk::get_str_value(
+ device_properties.inner(),
+ DictKey::Defined(ffi::kIOPropertyMediumTypeKey),
+ )
+ };
+
+ if let Some(disk_type) = disk_type.and_then(|medium| match medium.as_str() {
+ _ if medium == ffi::kIOPropertyMediumTypeSolidStateKey => Some(DiskType::SSD),
+ _ if medium == ffi::kIOPropertyMediumTypeRotationalKey => Some(DiskType::HDD),
+ _ => None,
+ }) {
+ return Some(disk_type);
+ } else {
+ // Many external drive vendors do not advertise their device's storage medium.
+ //
+ // In these cases, assuming that there were _any_ properties about them registered, we fallback
+ // to `HDD` when no storage medium is provided by the device instead of `Unknown`.
+ return Some(DiskType::HDD);
+ }
+ }
+ }
+ }
+
+ None
+}
diff --git a/vendor/sysinfo-0.26.7/src/apple/macos/ffi.rs b/vendor/sysinfo-0.26.7/src/apple/macos/ffi.rs
new file mode 100644
index 000000000..0b9c82cfa
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/ffi.rs
@@ -0,0 +1,291 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use core_foundation_sys::base::{mach_port_t, CFAllocatorRef};
+use core_foundation_sys::dictionary::{CFDictionaryRef, CFMutableDictionaryRef};
+use core_foundation_sys::string::CFStringRef;
+
+use libc::{c_char, kern_return_t};
+
+// Note: IOKit is only available on MacOS up until very recent iOS versions: https://developer.apple.com/documentation/iokit
+
+#[allow(non_camel_case_types)]
+pub type io_object_t = mach_port_t;
+
+#[allow(non_camel_case_types)]
+pub type io_iterator_t = io_object_t;
+#[allow(non_camel_case_types)]
+pub type io_registry_entry_t = io_object_t;
+#[allow(non_camel_case_types)]
+pub type io_name_t = *const c_char;
+
+pub type IOOptionBits = u32;
+
+#[allow(non_upper_case_globals)]
+pub const kIOServicePlane: &str = "IOService\0";
+#[allow(non_upper_case_globals)]
+pub const kIOPropertyDeviceCharacteristicsKey: &str = "Device Characteristics";
+#[allow(non_upper_case_globals)]
+pub const kIOPropertyMediumTypeKey: &str = "Medium Type";
+#[allow(non_upper_case_globals)]
+pub const kIOPropertyMediumTypeSolidStateKey: &str = "Solid State";
+#[allow(non_upper_case_globals)]
+pub const kIOPropertyMediumTypeRotationalKey: &str = "Rotational";
+
+// Note: Obtaining information about disks using IOKIt is allowed inside the default macOS App Sandbox.
+#[link(name = "IOKit", kind = "framework")]
+extern "C" {
+ pub fn IOServiceGetMatchingServices(
+ mainPort: mach_port_t,
+ matching: CFMutableDictionaryRef,
+ existing: *mut io_iterator_t,
+ ) -> kern_return_t;
+
+ pub fn IOIteratorNext(iterator: io_iterator_t) -> io_object_t;
+
+ pub fn IOObjectRelease(obj: io_object_t) -> kern_return_t;
+
+ pub fn IORegistryEntryCreateCFProperty(
+ entry: io_registry_entry_t,
+ key: CFStringRef,
+ allocator: CFAllocatorRef,
+ options: IOOptionBits,
+ ) -> CFDictionaryRef;
+ pub fn IORegistryEntryGetParentEntry(
+ entry: io_registry_entry_t,
+ plane: io_name_t,
+ parent: *mut io_registry_entry_t,
+ ) -> kern_return_t;
+
+ pub fn IOBSDNameMatching(
+ mainPort: mach_port_t,
+ options: u32,
+ bsdName: *const c_char,
+ ) -> CFMutableDictionaryRef;
+
+ // This is deprecated as of macOS 12.0, but Rust doesn't have a good way to only use the replacement on 12+.
+ pub static kIOMasterPortDefault: mach_port_t;
+}
+
+#[cfg(all(
+ not(feature = "apple-sandbox"),
+ any(target_arch = "x86", target_arch = "x86_64")
+))]
+mod io_service {
+ use super::{io_object_t, mach_port_t};
+ use core_foundation_sys::dictionary::CFMutableDictionaryRef;
+ use libc::{c_char, kern_return_t, size_t, task_t};
+
+ #[allow(non_camel_case_types)]
+ pub type io_connect_t = io_object_t;
+
+ #[allow(non_camel_case_types)]
+ pub type io_service_t = io_object_t;
+
+ #[allow(non_camel_case_types)]
+ pub type task_port_t = task_t;
+
+ extern "C" {
+ pub fn IOServiceMatching(a: *const c_char) -> CFMutableDictionaryRef;
+
+ pub fn IOServiceOpen(
+ device: io_service_t,
+ owning_task: task_port_t,
+ type_: u32,
+ connect: *mut io_connect_t,
+ ) -> kern_return_t;
+
+ pub fn IOServiceClose(a: io_connect_t) -> kern_return_t;
+
+ #[allow(dead_code)]
+ pub fn IOConnectCallStructMethod(
+ connection: mach_port_t,
+ selector: u32,
+ inputStruct: *const KeyData_t,
+ inputStructCnt: size_t,
+ outputStruct: *mut KeyData_t,
+ outputStructCnt: *mut size_t,
+ ) -> kern_return_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
+ }
+
+ #[allow(dead_code)]
+ pub const KERNEL_INDEX_SMC: i32 = 2;
+
+ #[allow(dead_code)]
+ pub const SMC_CMD_READ_KEYINFO: u8 = 9;
+
+ #[allow(dead_code)]
+ pub const SMC_CMD_READ_BYTES: u8 = 5;
+
+ pub const KIO_RETURN_SUCCESS: i32 = 0;
+}
+
+#[cfg(feature = "apple-sandbox")]
+mod io_service {}
+
+#[cfg(all(
+ not(feature = "apple-sandbox"),
+ any(target_arch = "x86", target_arch = "x86_64")
+))]
+pub use io_service::*;
+
+#[cfg(all(not(feature = "apple-sandbox"), target_arch = "aarch64"))]
+mod io_service {
+ use std::ptr::null;
+
+ use core_foundation_sys::array::CFArrayRef;
+ use core_foundation_sys::base::{CFAllocatorRef, CFRelease};
+ use core_foundation_sys::dictionary::{
+ kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks, CFDictionaryCreate,
+ CFDictionaryRef,
+ };
+ use core_foundation_sys::number::{kCFNumberSInt32Type, CFNumberCreate};
+ use core_foundation_sys::string::{CFStringCreateWithCString, CFStringRef};
+
+ #[repr(C)]
+ pub struct __IOHIDServiceClient(libc::c_void);
+
+ pub type IOHIDServiceClientRef = *const __IOHIDServiceClient;
+
+ #[repr(C)]
+ pub struct __IOHIDEventSystemClient(libc::c_void);
+
+ pub type IOHIDEventSystemClientRef = *const __IOHIDEventSystemClient;
+
+ #[repr(C)]
+ pub struct __IOHIDEvent(libc::c_void);
+
+ pub type IOHIDEventRef = *const __IOHIDEvent;
+
+ #[allow(non_upper_case_globals)]
+ pub const kIOHIDEventTypeTemperature: i64 = 15;
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn IOHIDEventFieldBase(event_type: i64) -> i64 {
+ event_type << 16
+ }
+
+ #[cfg(not(feature = "apple-sandbox"))]
+ extern "C" {
+ pub fn IOHIDEventSystemClientCreate(allocator: CFAllocatorRef)
+ -> IOHIDEventSystemClientRef;
+
+ pub fn IOHIDEventSystemClientSetMatching(
+ client: IOHIDEventSystemClientRef,
+ matches: CFDictionaryRef,
+ ) -> i32;
+
+ pub fn IOHIDEventSystemClientCopyServices(client: IOHIDEventSystemClientRef) -> CFArrayRef;
+
+ pub fn IOHIDServiceClientCopyProperty(
+ service: IOHIDServiceClientRef,
+ key: CFStringRef,
+ ) -> CFStringRef;
+
+ pub fn IOHIDServiceClientCopyEvent(
+ service: IOHIDServiceClientRef,
+ v0: i64,
+ v1: i32,
+ v2: i64,
+ ) -> IOHIDEventRef;
+
+ pub fn IOHIDEventGetFloatValue(event: IOHIDEventRef, field: i64) -> f64;
+ }
+
+ pub(crate) const HID_DEVICE_PROPERTY_PRODUCT: &[u8] = b"Product\0";
+
+ pub(crate) const HID_DEVICE_PROPERTY_PRIMARY_USAGE: &[u8] = b"PrimaryUsage\0";
+ pub(crate) const HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGE: &[u8] = b"PrimaryUsagePage\0";
+
+ #[allow(non_upper_case_globals)]
+ pub(crate) const kHIDPage_AppleVendor: i32 = 0xff00;
+
+ #[allow(non_upper_case_globals)]
+ pub(crate) const kHIDUsage_AppleVendor_TemperatureSensor: i32 = 0x0005;
+
+ pub(crate) fn matching(page: i32, usage: i32) -> CFDictionaryRef {
+ unsafe {
+ let keys = [
+ CFStringCreateWithCString(
+ null() as *const _,
+ HID_DEVICE_PROPERTY_PRIMARY_USAGE_PAGE.as_ptr() as *const _,
+ 0,
+ ),
+ CFStringCreateWithCString(
+ null() as *const _,
+ HID_DEVICE_PROPERTY_PRIMARY_USAGE.as_ptr() as *const _,
+ 0,
+ ),
+ ];
+
+ let nums = [
+ CFNumberCreate(null(), kCFNumberSInt32Type, &page as *const _ as *const _),
+ CFNumberCreate(null(), kCFNumberSInt32Type, &usage as *const _ as *const _),
+ ];
+
+ let dict = CFDictionaryCreate(
+ null(),
+ &keys as *const _ as *const _,
+ &nums as *const _ as *const _,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks,
+ );
+
+ for key in keys {
+ CFRelease(key as _);
+ }
+
+ for num in nums {
+ CFRelease(num as _);
+ }
+
+ dict
+ }
+ }
+}
+
+#[cfg(all(not(feature = "apple-sandbox"), target_arch = "aarch64"))]
+pub use io_service::*;
diff --git a/vendor/sysinfo-0.26.7/src/apple/macos/mod.rs b/vendor/sysinfo-0.26.7/src/apple/macos/mod.rs
new file mode 100644
index 000000000..856c5931d
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/mod.rs
@@ -0,0 +1,20 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+pub mod disk;
+pub mod ffi;
+pub(crate) mod utils;
+
+#[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-0.26.7/src/apple/macos/process.rs b/vendor/sysinfo-0.26.7/src/apple/macos/process.rs
new file mode 100644
index 000000000..fff9c1f71
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/process.rs
@@ -0,0 +1,688 @@
+// 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,
+ pub(crate) 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
+ }
+
+ fn wait(&self) {
+ let mut status = 0;
+ // attempt waiting
+ unsafe {
+ if libc::waitpid(self.pid.0, &mut status, 0) < 0 {
+ // attempt failed (non-child process) so loop until process ends
+ let duration = std::time::Duration::from_millis(10);
+ while kill(self.pid.0, 0) == 0 {
+ std::thread::sleep(duration);
+ }
+ }
+ }
+ }
+}
+
+#[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);
+ if total_time_diff > 0 {
+ 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
+ };
+ }
+ }
+}
+
+/*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;
+}*/
+
+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, check_if_alive: bool) -> bool {
+ // In case we are iterating all pids we got from `proc_listallpids`, then
+ // there is no point checking if the process is alive since it was returned
+ // from this function.
+ if !check_if_alive {
+ return true;
+ }
+ unsafe {
+ if kill(pid.0, 0) == 0 {
+ return true;
+ }
+ // `kill` failed but it might not be because the process is dead.
+ let errno = libc::__error();
+ // If errno is equal to ESCHR, it means the process is dead.
+ !errno.is_null() && *errno != 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();
+ }
+}
+
+unsafe fn get_bsd_info(pid: Pid) -> Option<libc::proc_bsdinfo> {
+ 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 _
+ {
+ None
+ } else {
+ Some(info)
+ }
+}
+
+unsafe fn create_new_process(
+ pid: Pid,
+ mut size: size_t,
+ now: u64,
+ refresh_kind: ProcessRefreshKind,
+ info: Option<libc::proc_bsdinfo>,
+) -> Result<Option<Process>, ()> {
+ 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 info = match info {
+ Some(info) => info,
+ None => {
+ 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 mut proc_args = Vec::with_capacity(size as _);
+ 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;
+ p.virtual_memory = task_info.pti_virtual_size;
+
+ 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))
+}
+
+pub(crate) fn update_process(
+ wrap: &Wrap,
+ pid: Pid,
+ size: size_t,
+ time_interval: Option<f64>,
+ now: u64,
+ refresh_kind: ProcessRefreshKind,
+ check_if_alive: bool,
+) -> Result<Option<Process>, ()> {
+ 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.
+ return if check_if_pid_is_alive(pid, check_if_alive) {
+ p.updated = true;
+ Ok(None)
+ } else {
+ Err(())
+ };
+ }
+ if let Some(info) = get_bsd_info(pid) {
+ if info.pbi_start_tvsec != p.start_time {
+ // We don't it to be removed, just replaced.
+ p.updated = true;
+ // The owner of this PID changed.
+ return create_new_process(pid, size, now, refresh_kind, Some(info));
+ }
+ }
+ 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...
+ if check_if_pid_is_alive(pid, check_if_alive) {
+ (0, 0, Some(ThreadStatus::Running))
+ } else {
+ return 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;
+ p.virtual_memory = task_info.pti_virtual_size;
+ if refresh_kind.disk_usage() {
+ update_proc_disk_activity(p);
+ }
+ p.updated = true;
+ return Ok(None);
+ }
+ create_new_process(pid, size, now, refresh_kind, get_bsd_info(pid))
+ }
+}
+
+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(unknown_lints)]
+#[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-0.26.7/src/apple/macos/system.rs b/vendor/sysinfo-0.26.7/src/apple/macos/system.rs
new file mode 100644
index 000000000..949532234
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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-0.26.7/src/apple/macos/utils.rs b/vendor/sysinfo-0.26.7/src/apple/macos/utils.rs
new file mode 100644
index 000000000..ff870db55
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/macos/utils.rs
@@ -0,0 +1,30 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use std::num::NonZeroU32;
+
+type IoObject = NonZeroU32;
+
+pub(crate) struct IOReleaser(IoObject);
+
+impl IOReleaser {
+ pub(crate) fn new(obj: u32) -> Option<Self> {
+ IoObject::new(obj).map(Self)
+ }
+
+ pub(crate) unsafe fn new_unchecked(obj: u32) -> Self {
+ // Chance at catching in-development mistakes
+ debug_assert_ne!(obj, 0);
+ Self(IoObject::new_unchecked(obj))
+ }
+
+ #[inline]
+ pub(crate) fn inner(&self) -> u32 {
+ self.0.get()
+ }
+}
+
+impl Drop for IOReleaser {
+ fn drop(&mut self) {
+ unsafe { super::ffi::IOObjectRelease(self.0.get() as _) };
+ }
+}
diff --git a/vendor/sysinfo-0.26.7/src/apple/mod.rs b/vendor/sysinfo-0.26.7/src/apple/mod.rs
new file mode 100644
index 000000000..fd6fdec2c
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/mod.rs
@@ -0,0 +1,32 @@
+// 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-0.26.7/src/apple/network.rs b/vendor/sysinfo-0.26.7/src/apple/network.rs
new file mode 100644
index 000000000..3c4918155
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/network.rs
@@ -0,0 +1,240 @@
+// 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(unknown_lints)]
+ #[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-0.26.7/src/apple/process.rs b/vendor/sysinfo-0.26.7/src/apple/process.rs
new file mode 100644
index 000000000..e0f005bdc
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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-0.26.7/src/apple/system.rs b/vendor/sysinfo-0.26.7/src/apple/system.rs
new file mode 100644
index 000000000..12abbd23b
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/system.rs
@@ -0,0 +1,691 @@
+// 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::*;
+use crate::sys::network::Networks;
+use crate::sys::process::*;
+
+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(not(any(target_os = "ios", feature = "apple-sandbox")))]
+use super::inner::component::Components;
+
+#[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,
+ #[cfg(not(any(target_os = "ios", feature = "apple-sandbox")))]
+ components: Components,
+ disks: Vec<Disk>,
+ networks: Networks,
+ port: mach_port_t,
+ users: Vec<User>,
+ boot_time: u64,
+ #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
+ clock_info: Option<crate::sys::macos::system::SystemTimeInfo>,
+ got_cpu_frequency: bool,
+}
+
+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> {}
+
+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 _,
+ #[cfg(not(any(target_os = "ios", feature = "apple-sandbox")))]
+ components: Components::new(),
+ disks: Vec::with_capacity(1),
+ networks: Networks::new(),
+ port,
+ users: Vec::new(),
+ boot_time: boot_time(),
+ #[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;
+ self.swap_free = xs.xsu_avail;
+ }
+ // 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,
+ );
+ }
+ 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(not(any(target_os = "ios", feature = "apple-sandbox")))]
+ fn refresh_components_list(&mut self) {
+ self.components.refresh();
+ }
+
+ 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,
+ false,
+ ) {
+ Ok(x) => x,
+ _ => None,
+ }
+ })
+ .collect()
+ };
+ entries.into_iter().for_each(|entry| {
+ self.process_list.insert(entry.pid(), entry);
+ });
+ self.process_list
+ .retain(|_, proc_| std::mem::replace(&mut proc_.updated, false));
+ }
+ }
+
+ #[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,
+ true,
+ )
+ } {
+ Ok(Some(p)) => {
+ self.process_list.insert(p.pid(), p);
+ true
+ }
+ Ok(_) => true,
+ Err(_) => false,
+ }
+ }
+
+ fn refresh_disks_list(&mut self) {
+ self.disks = unsafe { get_disks() };
+ }
+
+ 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
+ }
+
+ #[cfg(not(any(target_os = "ios", feature = "apple-sandbox")))]
+ fn components(&self) -> &[Component] {
+ &self.components.inner
+ }
+
+ #[cfg(any(target_os = "ios", feature = "apple-sandbox"))]
+ fn components(&self) -> &[Component] {
+ &[]
+ }
+
+ #[cfg(not(any(target_os = "ios", feature = "apple-sandbox")))]
+ fn components_mut(&mut self) -> &mut [Component] {
+ &mut self.components.inner
+ }
+
+ #[cfg(any(target_os = "ios", feature = "apple-sandbox"))]
+ fn components_mut(&mut self) -> &mut [Component] {
+ &mut []
+ }
+
+ fn disks(&self) -> &[Disk] {
+ &self.disks
+ }
+
+ fn disks_mut(&mut self) -> &mut [Disk] {
+ &mut self.disks
+ }
+
+ fn sort_disks_by<F>(&mut self, compare: F)
+ where
+ F: FnMut(&Disk, &Disk) -> std::cmp::Ordering,
+ {
+ self.disks.sort_unstable_by(compare);
+ }
+
+ 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 _];
+
+ 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
+ }
+ }
+ }
+
+ fn distribution_id(&self) -> String {
+ std::env::consts::OS.to_owned()
+ }
+}
+
+impl Default for System {
+ fn default() -> System {
+ System::new()
+ }
+}
+
+#[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 _];
+
+ 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-0.26.7/src/apple/users.rs b/vendor/sysinfo-0.26.7/src/apple/users.rs
new file mode 100644
index 000000000..690aceee1
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/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-0.26.7/src/apple/utils.rs b/vendor/sysinfo-0.26.7/src/apple/utils.rs
new file mode 100644
index 000000000..408c02c31
--- /dev/null
+++ b/vendor/sysinfo-0.26.7/src/apple/utils.rs
@@ -0,0 +1,71 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use core_foundation_sys::base::CFRelease;
+use libc::c_char;
+use std::ptr::NonNull;
+
+// A helper using to auto release the resource got from CoreFoundation.
+// More information about the ownership policy for CoreFoundation pelease refer the link below:
+// https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-CJBEJBHH
+#[repr(transparent)]
+pub(crate) struct CFReleaser<T>(NonNull<T>);
+
+impl<T> CFReleaser<T> {
+ pub(crate) fn new(ptr: *const T) -> Option<Self> {
+ // This cast is OK because `NonNull` is a transparent wrapper
+ // over a `*const T`. Additionally, mutability doesn't matter with
+ // pointers here.
+ NonNull::new(ptr as *mut T).map(Self)
+ }
+
+ pub(crate) fn inner(&self) -> *const T {
+ self.0.as_ptr().cast()
+ }
+}
+
+impl<T> Drop for CFReleaser<T> {
+ fn drop(&mut self) {
+ unsafe { CFRelease(self.0.as_ptr().cast()) }
+ }
+}
+
+// Safety: These are safe to implement because we only wrap non-mutable
+// CoreFoundation types, which are generally threadsafe unless noted
+// otherwise.
+unsafe impl<T> Send for CFReleaser<T> {}
+unsafe impl<T> Sync for CFReleaser<T> {}
+
+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()
+ }
+}
+
+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()
+}