summaryrefslogtreecommitdiffstats
path: root/vendor/sysinfo/src/apple/macos
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/sysinfo/src/apple/macos')
-rw-r--r--vendor/sysinfo/src/apple/macos/component/arm.rs179
-rw-r--r--vendor/sysinfo/src/apple/macos/component/mod.rs13
-rw-r--r--vendor/sysinfo/src/apple/macos/component/x86.rs (renamed from vendor/sysinfo/src/apple/macos/component.rs)145
-rw-r--r--vendor/sysinfo/src/apple/macos/disk.rs281
-rw-r--r--vendor/sysinfo/src/apple/macos/ffi.rs295
-rw-r--r--vendor/sysinfo/src/apple/macos/mod.rs3
-rw-r--r--vendor/sysinfo/src/apple/macos/process.rs511
-rw-r--r--vendor/sysinfo/src/apple/macos/utils.rs30
8 files changed, 947 insertions, 510 deletions
diff --git a/vendor/sysinfo/src/apple/macos/component/arm.rs b/vendor/sysinfo/src/apple/macos/component/arm.rs
new file mode 100644
index 000000000..328ffebfa
--- /dev/null
+++ b/vendor/sysinfo/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/src/apple/macos/component/mod.rs b/vendor/sysinfo/src/apple/macos/component/mod.rs
new file mode 100644
index 000000000..50b359e61
--- /dev/null
+++ b/vendor/sysinfo/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/src/apple/macos/component.rs b/vendor/sysinfo/src/apple/macos/component/x86.rs
index 384efb950..415f90455 100644
--- a/vendor/sysinfo/src/apple/macos/component.rs
+++ b/vendor/sysinfo/src/apple/macos/component/x86.rs
@@ -1,13 +1,13 @@
// Take a look at the license at the top of the repository in the LICENSE file.
-use crate::sys::ffi;
+use crate::sys::{ffi, macos::utils::IOReleaser};
use crate::ComponentExt;
use libc::{c_char, c_int, c_void};
use std::mem;
-pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[
+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"
(
@@ -21,33 +21,69 @@ pub(crate) const COMPONENTS_TEMPERATURE_IDS: &[(&str, &[i8])] = &[
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], con: ffi::io_connect_t) -> Option<ComponentFFI> {
+ fn new(key: &[i8], connection: ffi::io_connect_t) -> Option<ComponentFFI> {
unsafe {
- get_key_size(con, key)
+ get_key_size(connection, key)
.ok()
.map(|(input_structure, val)| ComponentFFI {
input_structure,
val,
+ connection,
})
}
}
- fn temperature(&self, con: ffi::io_connect_t) -> Option<f32> {
- get_temperature_inner(con, &self.input_structure, &self.val)
+ 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")]
+#[doc = include_str!("../../../../md_doc/component.md")]
pub struct Component {
temperature: f32,
max: f32,
critical: Option<f32>,
label: String,
ffi_part: ComponentFFI,
- connection: ffi::io_connect_t,
}
impl Component {
@@ -60,16 +96,13 @@ impl Component {
connection: ffi::io_connect_t,
) -> Option<Component> {
let ffi_part = ComponentFFI::new(key, connection)?;
- ffi_part
- .temperature(connection)
- .map(|temperature| Component {
- temperature,
- label,
- max: max.unwrap_or(0.0),
- critical,
- ffi_part,
- connection,
- })
+ ffi_part.temperature().map(|temperature| Component {
+ temperature,
+ label,
+ max: max.unwrap_or(temperature),
+ critical,
+ ffi_part,
+ })
}
}
@@ -91,7 +124,7 @@ impl ComponentExt for Component {
}
fn refresh(&mut self) {
- if let Some(temp) = self.ffi_part.temperature(self.connection) {
+ if let Some(temp) = self.ffi_part.temperature() {
self.temperature = temp;
if self.temperature > self.max {
self.max = self.temperature;
@@ -213,9 +246,81 @@ fn get_temperature_inner(
None
}
-pub(crate) fn get_temperature(con: ffi::io_connect_t, key: &[i8]) -> Option<f32> {
+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/src/apple/macos/disk.rs b/vendor/sysinfo/src/apple/macos/disk.rs
index 7cc5a83ce..3a4372a2f 100644
--- a/vendor/sysinfo/src/apple/macos/disk.rs
+++ b/vendor/sysinfo/src/apple/macos/disk.rs
@@ -1,199 +1,126 @@
// Take a look at the license at the top of the repository in the LICENSE file.
-use crate::sys::{ffi, utils};
-use crate::utils::to_cpath;
-use crate::{Disk, DiskType};
+use 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, CFRelease};
-use core_foundation_sys::dictionary::{CFDictionaryGetValueIfPresent, CFDictionaryRef};
-use core_foundation_sys::number::{kCFBooleanTrue, CFBooleanRef};
+use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull};
use core_foundation_sys::string as cfs;
-use libc::{c_char, c_int, c_void, statfs};
+use std::ffi::CStr;
-use std::ffi::{OsStr, OsString};
-use std::mem;
-use std::os::unix::ffi::OsStrExt;
-use std::path::PathBuf;
-use std::ptr;
+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,
+ ))?
+ };
-fn to_path(mount_path: &[c_char]) -> Option<PathBuf> {
- let mut tmp = Vec::with_capacity(mount_path.len());
- for &c in mount_path {
- if c == 0 {
- break;
- }
- tmp.push(c as u8);
- }
- if tmp.is_empty() {
- None
- } else {
- let path = OsStr::from_bytes(&tmp);
- Some(PathBuf::from(path))
- }
-}
+ // 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()) };
-pub(crate) fn get_disks(session: ffi::DASessionRef) -> Vec<Disk> {
- if session.is_null() {
- return Vec::new();
+ if matching.is_null() {
+ return None;
}
- unsafe {
- let count = libc::getfsstat(ptr::null_mut(), 0, libc::MNT_NOWAIT);
- if count < 1 {
- return Vec::new();
- }
- let bufsize = count * mem::size_of::<libc::statfs>() as c_int;
- let mut disks = Vec::with_capacity(count as _);
- let count = libc::getfsstat(disks.as_mut_ptr(), bufsize, libc::MNT_NOWAIT);
- if count < 1 {
- return Vec::new();
- }
- disks.set_len(count as _);
- disks
- .into_iter()
- .filter_map(|c_disk| {
- let mount_point = to_path(&c_disk.f_mntonname)?;
- let disk = ffi::DADiskCreateFromBSDName(
- kCFAllocatorDefault as _,
- session,
- c_disk.f_mntfromname.as_ptr(),
- );
- let dict = ffi::DADiskCopyDescription(disk);
- if dict.is_null() {
- return None;
- }
- // Keeping this around in case one might want the list of the available
- // keys in "dict".
- // core_foundation_sys::base::CFShow(dict as _);
- let name = match get_str_value(dict, b"DAMediaName\0").map(OsString::from) {
- Some(n) => n,
- None => return None,
- };
- let removable = get_bool_value(dict, b"DAMediaRemovable\0").unwrap_or(false);
- let ejectable = get_bool_value(dict, b"DAMediaEjectable\0").unwrap_or(false);
- // This is very hackish but still better than nothing...
- let type_ = if let Some(model) = get_str_value(dict, b"DADeviceModel\0") {
- if model.contains("SSD") {
- DiskType::SSD
- } else {
- // We just assume by default that this is a HDD
- DiskType::HDD
- }
- } else {
- DiskType::Unknown(-1)
- };
- CFRelease(dict as _);
- new_disk(name, mount_point, type_, removable || ejectable)
- })
- .collect::<Vec<_>>()
+ 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;
}
-}
-unsafe fn get_dict_value<T, F: FnOnce(*const c_void) -> Option<T>>(
- dict: CFDictionaryRef,
- key: &[u8],
- callback: F,
-) -> Option<T> {
- let key = ffi::CFStringCreateWithCStringNoCopy(
- ptr::null_mut(),
- key.as_ptr() as *const c_char,
- cfs::kCFStringEncodingUTF8,
- kCFAllocatorNull as _,
- );
- let mut value = std::ptr::null();
- let ret = if CFDictionaryGetValueIfPresent(dict, key as _, &mut value) != 0 {
- callback(value)
- } else {
- None
- };
- CFRelease(key as _);
- ret
-}
+ // 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) };
-unsafe fn get_str_value(dict: CFDictionaryRef, key: &[u8]) -> Option<String> {
- get_dict_value(dict, key, |v| {
- let v = v as cfs::CFStringRef;
-
- let len_utf16 = cfs::CFStringGetLength(v);
- let len_bytes = len_utf16 as usize * 2; // Two bytes per UTF-16 codepoint.
-
- let v_ptr = cfs::CFStringGetCStringPtr(v, cfs::kCFStringEncodingUTF8);
- if v_ptr.is_null() {
- // Fallback on CFStringGetString to read the underlying bytes from the CFString.
- let mut buf = vec![0; len_bytes];
- let success = cfs::CFStringGetCString(
- v,
- buf.as_mut_ptr(),
- len_bytes as _,
- cfs::kCFStringEncodingUTF8,
- );
-
- if success != 0 {
- utils::vec_to_rust(buf)
- } else {
- None
+ 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;
}
- } else {
- utils::cstr_to_rust_with_size(v_ptr, Some(len_bytes))
- }
- })
-}
-unsafe fn get_bool_value(dict: CFDictionaryRef, key: &[u8]) -> Option<bool> {
- get_dict_value(dict, key, |v| Some(v as CFBooleanRef == kCFBooleanTrue))
-}
+ current_service_entry = match IOReleaser::new(parent_entry) {
+ Some(service) => service,
+ // There were no more parents left
+ None => break,
+ };
-fn new_disk(
- name: OsString,
- mount_point: PathBuf,
- type_: DiskType,
- is_removable: bool,
-) -> Option<Disk> {
- let mount_point_cpath = to_cpath(&mount_point);
- let mut total_space = 0;
- let mut available_space = 0;
- let mut file_system = None;
- unsafe {
- let mut stat: statfs = mem::zeroed();
- if statfs(mount_point_cpath.as_ptr() as *const i8, &mut stat) == 0 {
- // APFS is "special" because its a snapshot-based filesystem, and modern
- // macOS devices take full advantage of this.
- //
- // By default, listing volumes with `statfs` can return both the root-level
- // "data" partition and any snapshots that exist. However, other than some flags and
- // reserved(undocumented) bytes, there is no difference between the OS boot snapshot
- // and the "data" partition.
- //
- // To avoid duplicating the number of disks (and therefore available space, etc), only return
- // a disk (which is really a partition with APFS) if it is the root of the filesystem.
- let is_root = stat.f_flags & libc::MNT_ROOTFS as u32 == 0;
- if !is_root {
- return None;
- }
+ 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),
+ )
+ };
- total_space = u64::from(stat.f_bsize).saturating_mul(stat.f_blocks);
- available_space = u64::from(stat.f_bsize).saturating_mul(stat.f_bavail);
- let mut vec = Vec::with_capacity(stat.f_fstypename.len());
- for x in &stat.f_fstypename {
- if *x == 0 {
- break;
+ 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);
}
- vec.push(*x as u8);
}
- file_system = Some(vec);
- }
- if total_space == 0 {
- return None;
}
- Some(Disk {
- type_,
- name,
- file_system: file_system.unwrap_or_else(|| b"<Unknown>".to_vec()),
- mount_point,
- total_space,
- available_space,
- is_removable,
- })
}
+
+ None
}
diff --git a/vendor/sysinfo/src/apple/macos/ffi.rs b/vendor/sysinfo/src/apple/macos/ffi.rs
index f884701d9..0b9c82cfa 100644
--- a/vendor/sysinfo/src/apple/macos/ffi.rs
+++ b/vendor/sysinfo/src/apple/macos/ffi.rs
@@ -1,105 +1,111 @@
// Take a look at the license at the top of the repository in the LICENSE file.
-use core_foundation_sys::base::CFAllocatorRef;
-use core_foundation_sys::dictionary::CFMutableDictionaryRef;
-use core_foundation_sys::string::{CFStringEncoding, CFStringRef};
+use 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, c_void};
-#[cfg(not(feature = "apple-sandbox"))]
-use libc::{mach_port_t, size_t};
+use libc::{c_char, kern_return_t};
-pub(crate) use crate::sys::ffi::*;
+// Note: IOKit is only available on MacOS up until very recent iOS versions: https://developer.apple.com/documentation/iokit
-#[cfg(not(feature = "apple-sandbox"))]
-extern "C" {
- // The proc_* PID functions are internal Apple APIs which are not
- // allowed in App store releases as Apple blocks any binary using them.
+#[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;
- // IOKit is only available on MacOS: https://developer.apple.com/documentation/iokit, and when not running inside
- // of the default macOS sandbox.
- pub fn IOMasterPort(a: i32, b: *mut mach_port_t) -> i32;
+pub type IOOptionBits = u32;
- pub fn IOServiceMatching(a: *const c_char) -> *mut c_void;
+#[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(
- a: mach_port_t,
- b: *mut c_void,
- c: *mut io_iterator_t,
- ) -> i32;
+ 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) -> i32;
-
- pub fn IOServiceOpen(device: io_object_t, a: u32, t: u32, x: *mut io_connect_t) -> i32;
-
- pub fn IOServiceClose(a: io_connect_t) -> i32;
-
- pub fn IOConnectCallStructMethod(
- connection: mach_port_t,
- selector: u32,
- inputStruct: *const KeyData_t,
- inputStructCnt: size_t,
- outputStruct: *mut KeyData_t,
- outputStructCnt: *mut size_t,
- ) -> i32;
- // pub fn IORegistryEntryCreateCFProperties(
- // entry: io_registry_entry_t,
- // properties: *mut CFMutableDictionaryRef,
- // allocator: CFAllocatorRef,
- // options: IOOptionBits,
- // ) -> kern_return_t;
- // pub fn IORegistryEntryGetName(entry: io_registry_entry_t, name: *mut c_char) -> kern_return_t;
-}
+ pub fn IOObjectRelease(obj: io_object_t) -> kern_return_t;
-extern "C" {
- pub fn CFStringCreateWithCStringNoCopy(
- alloc: *mut c_void,
- cStr: *const c_char,
- encoding: CFStringEncoding,
- contentsDeallocator: *mut c_void,
- ) -> CFStringRef;
-
- // Disk information functions are non-operational on iOS because of the sandboxing
- // restrictions of apps, so they don't can't filesystem information. This results in
- // mountedVolumeURLs and similar returning `nil`. Hence, they are MacOS specific here.
-
- pub fn DASessionCreate(allocator: CFAllocatorRef) -> DASessionRef;
-
- // pub fn DADiskCreateFromVolumePath(
- // allocator: CFAllocatorRef,
- // session: DASessionRef,
- // path: CFURLRef,
- // ) -> DADiskRef;
- pub fn DADiskCreateFromBSDName(
+ pub fn IORegistryEntryCreateCFProperty(
+ entry: io_registry_entry_t,
+ key: CFStringRef,
allocator: CFAllocatorRef,
- session: DASessionRef,
- path: *const c_char,
- ) -> DADiskRef;
- // pub fn DADiskGetBSDName(disk: DADiskRef) -> *const c_char;
-
- pub fn DADiskCopyDescription(disk: DADiskRef) -> CFMutableDictionaryRef;
-}
+ 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 type DADiskRef = *const __DADisk;
-pub type DASessionRef = *const __DASession;
+ pub fn IOBSDNameMatching(
+ mainPort: mach_port_t,
+ options: u32,
+ bsdName: *const c_char,
+ ) -> CFMutableDictionaryRef;
-// We need to wrap `DASessionRef` to be sure `System` remains Send+Sync.
-pub struct SessionWrap(pub DASessionRef);
-
-unsafe impl Send for SessionWrap {}
-unsafe impl Sync for SessionWrap {}
+ // 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(not(feature = "apple-sandbox"))]
+#[cfg(all(
+ not(feature = "apple-sandbox"),
+ any(target_arch = "x86", target_arch = "x86_64")
+))]
mod io_service {
- use super::mach_port_t;
+ 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_object_t = mach_port_t;
- #[allow(non_camel_case_types)]
pub type io_connect_t = io_object_t;
+
#[allow(non_camel_case_types)]
- pub type io_iterator_t = io_object_t;
+ 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)]
@@ -143,8 +149,13 @@ mod io_service {
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;
@@ -153,4 +164,128 @@ mod io_service {
#[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/src/apple/macos/mod.rs b/vendor/sysinfo/src/apple/macos/mod.rs
index 172bbfddc..856c5931d 100644
--- a/vendor/sysinfo/src/apple/macos/mod.rs
+++ b/vendor/sysinfo/src/apple/macos/mod.rs
@@ -2,16 +2,19 @@
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/src/apple/macos/process.rs b/vendor/sysinfo/src/apple/macos/process.rs
index f146126cf..fff9c1f71 100644
--- a/vendor/sysinfo/src/apple/macos/process.rs
+++ b/vendor/sysinfo/src/apple/macos/process.rs
@@ -30,7 +30,7 @@ pub struct Process {
old_stime: u64,
start_time: u64,
run_time: u64,
- updated: bool,
+ pub(crate) updated: bool,
cpu_usage: f32,
user_id: Option<Uid>,
group_id: Option<Gid>,
@@ -184,6 +184,20 @@ impl ProcessExt for Process {
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.
@@ -202,7 +216,9 @@ pub(crate) fn compute_cpu_usage(
.saturating_add(task_info.pti_total_user);
let total_time_diff = total_current_time.saturating_sub(total_existing_time);
- p.cpu_usage = (total_time_diff as f64 / time_interval * 100.) as f32;
+ if total_time_diff > 0 {
+ p.cpu_usage = (total_time_diff as f64 / time_interval * 100.) as f32;
+ }
} else {
p.cpu_usage = 0.;
}
@@ -236,7 +252,6 @@ pub(crate) fn compute_cpu_usage(
};
}
}
- p.updated = true;
}
/*pub fn set_time(p: &mut Process, utime: u64, stime: u64) {
@@ -247,18 +262,6 @@ pub(crate) fn compute_cpu_usage(
p.updated = true;
}*/
-#[inline]
-pub(crate) fn has_been_updated(p: &mut Process) -> bool {
- let old = p.updated;
- p.updated = false;
- old
-}
-
-#[inline]
-pub(crate) fn force_update(p: &mut Process) {
- p.updated = true;
-}
-
unsafe fn get_task_info(pid: Pid) -> libc::proc_taskinfo {
let mut task_info = mem::zeroed::<libc::proc_taskinfo>();
// If it doesn't work, we just don't have memory information for this process
@@ -274,12 +277,22 @@ unsafe fn get_task_info(pid: Pid) -> libc::proc_taskinfo {
}
#[inline]
-fn check_if_pid_is_alive(pid: Pid) -> bool {
- unsafe { kill(pid.0, 0) == 0 }
- // For the full complete check, it'd need to be (but that seems unneeded):
- // unsafe {
- // *libc::__errno_location() == libc::ESRCH
- // }
+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]
@@ -293,91 +306,52 @@ fn do_get_env_path(env: &str, root: &mut PathBuf, check: &mut bool) {
}
}
-pub(crate) fn update_process(
- wrap: &Wrap,
+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,
- time_interval: Option<f64>,
now: u64,
refresh_kind: ProcessRefreshKind,
+ info: Option<libc::proc_bsdinfo>,
) -> Result<Option<Process>, ()> {
- let mut proc_args = Vec::with_capacity(size as usize);
-
- unsafe {
- if let Some(ref mut p) = (*wrap.0.get()).get_mut(&pid) {
- if p.memory == 0 {
- // We don't have access to this process' information.
- force_update(p);
- return if check_if_pid_is_alive(pid) {
- Ok(None)
- } else {
- Err(())
- };
- }
- let task_info = get_task_info(pid);
- let mut thread_info = mem::zeroed::<libc::proc_threadinfo>();
- let (user_time, system_time, thread_status) = if libc::proc_pidinfo(
- pid.0,
- libc::PROC_PIDTHREADINFO,
- 0,
- &mut thread_info as *mut libc::proc_threadinfo as *mut c_void,
- mem::size_of::<libc::proc_threadinfo>() as _,
- ) != 0
- {
- (
- thread_info.pth_user_time,
- thread_info.pth_system_time,
- Some(ThreadStatus::from(thread_info.pth_run_state)),
- )
- } else {
- // It very likely means that the process is dead...
- return if check_if_pid_is_alive(pid) {
- Ok(None)
- } else {
- Err(())
- };
- };
- p.status = thread_status;
- if refresh_kind.cpu() {
- compute_cpu_usage(p, task_info, system_time, user_time, time_interval);
- }
-
- p.memory = task_info.pti_resident_size / 1_000;
- p.virtual_memory = task_info.pti_virtual_size / 1_000;
- if refresh_kind.disk_usage() {
- update_proc_disk_activity(p);
- }
- return Ok(None);
- }
-
- let mut vnodepathinfo = mem::zeroed::<libc::proc_vnodepathinfo>();
- let result = libc::proc_pidinfo(
- pid.0,
- libc::PROC_PIDVNODEPATHINFO,
- 0,
- &mut vnodepathinfo as *mut _ as *mut _,
- mem::size_of::<libc::proc_vnodepathinfo>() as _,
- );
- let cwd = if result > 0 {
- let buffer = vnodepathinfo.pvi_cdir.vip_path;
- let buffer = CStr::from_ptr(buffer.as_ptr() as _);
- buffer
- .to_str()
- .map(PathBuf::from)
- .unwrap_or_else(|_| PathBuf::new())
- } else {
- PathBuf::new()
- };
+ let mut vnodepathinfo = mem::zeroed::<libc::proc_vnodepathinfo>();
+ let result = libc::proc_pidinfo(
+ pid.0,
+ libc::PROC_PIDVNODEPATHINFO,
+ 0,
+ &mut vnodepathinfo as *mut _ as *mut _,
+ mem::size_of::<libc::proc_vnodepathinfo>() as _,
+ );
+ let cwd = if result > 0 {
+ let buffer = vnodepathinfo.pvi_cdir.vip_path;
+ let buffer = CStr::from_ptr(buffer.as_ptr() as _);
+ buffer
+ .to_str()
+ .map(PathBuf::from)
+ .unwrap_or_else(|_| PathBuf::new())
+ } else {
+ PathBuf::new()
+ };
- let mut info = mem::zeroed::<libc::proc_bsdinfo>();
- if libc::proc_pidinfo(
- pid.0,
- libc::PROC_PIDTBSDINFO,
- 0,
- &mut info as *mut _ as *mut _,
- mem::size_of::<libc::proc_bsdinfo>() as _,
- ) != mem::size_of::<libc::proc_bsdinfo>() as _
- {
+ let 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,
@@ -399,158 +373,228 @@ pub(crate) fn update_process(
}
return Err(());
}
- let parent = match info.pbi_ppid as i32 {
- 0 => None,
- p => Some(Pid(p)),
- };
-
- let ptr: *mut u8 = proc_args.as_mut_slice().as_mut_ptr();
- let mut mib = [libc::CTL_KERN, libc::KERN_PROCARGS2, pid.0 as _];
- /*
- * /---------------\ 0x00000000
- * | ::::::::::::: |
- * |---------------| <-- Beginning of data returned by sysctl() is here.
- * | argc |
- * |---------------|
- * | exec_path |
- * |---------------|
- * | 0 |
- * |---------------|
- * | arg[0] |
- * |---------------|
- * | 0 |
- * |---------------|
- * | arg[n] |
- * |---------------|
- * | 0 |
- * |---------------|
- * | env[0] |
- * |---------------|
- * | 0 |
- * |---------------|
- * | env[n] |
- * |---------------|
- * | ::::::::::::: |
- * |---------------| <-- Top of stack.
- * : :
- * : :
- * \---------------/ 0xffffffff
- */
- if libc::sysctl(
- mib.as_mut_ptr(),
- mib.len() as _,
- ptr as *mut c_void,
- &mut size,
- std::ptr::null_mut(),
- 0,
- ) == -1
- {
- return Err(()); // not enough rights I assume?
- }
- let mut n_args: c_int = 0;
- libc::memcpy(
- (&mut n_args) as *mut c_int as *mut c_void,
- ptr as *const c_void,
- mem::size_of::<c_int>(),
- );
+ };
+ let 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 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 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);
+ 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);
}
- start = cp;
- let mut c = 0;
- let mut cmd = Vec::with_capacity(n_args as usize);
- while c < n_args && cp < ptr.add(size) {
+ 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 {
- c += 1;
- cmd.push(get_unchecked_str(cp, start));
+ 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)
+ }
- #[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;
- 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,
- )
+ 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 {
- get_environ(ptr, cp, size, PathBuf::new(), do_get_env_path)
+ 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 {
- get_environ(ptr, cp, size, PathBuf::new(), do_get_env_path)
+ // 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(());
+ }
};
- 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.status = thread_status;
- p.memory = task_info.pti_resident_size / 1_000;
- p.virtual_memory = task_info.pti_virtual_size / 1_000;
+ if refresh_kind.cpu() {
+ compute_cpu_usage(p, task_info, system_time, user_time, time_interval);
+ }
- 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);
+ 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);
}
- Ok(Some(p))
+ create_new_process(pid, size, now, refresh_kind, get_bsd_info(pid))
}
}
@@ -577,6 +621,7 @@ fn update_proc_disk_activity(p: &mut Process) {
}
}
+#[allow(unknown_lints)]
#[allow(clippy::uninit_vec)]
pub(crate) fn get_proc_list() -> Option<Vec<Pid>> {
unsafe {
diff --git a/vendor/sysinfo/src/apple/macos/utils.rs b/vendor/sysinfo/src/apple/macos/utils.rs
new file mode 100644
index 000000000..ff870db55
--- /dev/null
+++ b/vendor/sysinfo/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 _) };
+ }
+}