summaryrefslogtreecommitdiffstats
path: root/vendor/sysinfo/src/apple/macos/ffi.rs
blob: 0b9c82cfaea55a804b44e2e6340094074ed9d5c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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::*;