#[cfg(not(target_os = "macos"))]
fn main() {
println!("macos_probe: macOS-only ground-truth probe; nothing to do on this OS.");
}
#[cfg(target_os = "macos")]
fn main() {
macos::run();
}
#[cfg(target_os = "macos")]
mod macos {
use std::ffi::{c_char, c_int, c_void, CString};
extern "C" {
fn dlopen(path: *const c_char, flag: c_int) -> *mut c_void;
fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
}
const RTLD_NOW: c_int = 2;
#[link(name = "CoreFoundation", kind = "framework")]
extern "C" {
fn CFRelease(cf: *const c_void);
fn CFDictionaryGetValue(dict: *const c_void, key: *const c_void) -> *const c_void;
fn CFArrayGetCount(array: *const c_void) -> isize;
fn CFArrayGetValueAtIndex(array: *const c_void, idx: isize) -> *const c_void;
fn CFStringCreateWithCString(
alloc: *const c_void,
s: *const c_char,
encoding: u32,
) -> *const c_void;
fn CFStringGetCString(s: *const c_void, buf: *mut c_char, len: isize, encoding: u32) -> u8;
}
const K_CF_STRING_ENCODING_UTF8: u32 = 0x0800_0100;
unsafe fn cfstring_to_string(s: *const c_void) -> String {
if s.is_null() {
return String::new();
}
let mut buf = [0 as c_char; 512];
if CFStringGetCString(
s,
buf.as_mut_ptr(),
buf.len() as isize,
K_CF_STRING_ENCODING_UTF8,
) == 0
{
return String::new();
}
std::ffi::CStr::from_ptr(buf.as_ptr())
.to_string_lossy()
.into_owned()
}
type FnCopyAllChannels = unsafe extern "C" fn(u64, u64) -> *const c_void;
type FnChannelGetStr = unsafe extern "C" fn(*const c_void) -> *const c_void;
const PRESENCE_ONLY_SYMBOLS: &[&str] = &[
"IOReportCreateSubscription",
"IOReportCreateSamples",
"IOReportCreateSamplesDelta",
"IOReportStateGetCount",
"IOReportStateGetNameForIndex",
"IOReportStateGetResidency",
"IOReportSimpleGetIntegerValue",
];
pub(super) fn run() {
println!("== macos_probe: IOReport ground truth (design §4.5/§5.5) ==");
let path = CString::new("/usr/lib/libIOReport.dylib").expect("static path");
let handle = unsafe { dlopen(path.as_ptr(), RTLD_NOW) };
if handle.is_null() {
println!("libIOReport: ABSENT (dlopen failed) — Tier C has no substrate here");
return;
}
println!("libIOReport: present (dlopen ok)");
let sym = |name: &str| -> *mut c_void {
let c = CString::new(name).expect("static symbol name");
unsafe { dlsym(handle, c.as_ptr()) }
};
for name in PRESENCE_ONLY_SYMBOLS {
let p = sym(name);
println!(
"symbol|{name}|{}",
if p.is_null() { "ABSENT" } else { "present" }
);
}
let copy_all = sym("IOReportCopyAllChannels");
let get_group = sym("IOReportChannelGetGroup");
let get_subgroup = sym("IOReportChannelGetSubGroup");
let get_name = sym("IOReportChannelGetChannelName");
let get_unit = sym("IOReportChannelGetUnitLabel");
for (name, p) in [
("IOReportCopyAllChannels", copy_all),
("IOReportChannelGetGroup", get_group),
("IOReportChannelGetSubGroup", get_subgroup),
("IOReportChannelGetChannelName", get_name),
("IOReportChannelGetUnitLabel", get_unit),
] {
println!(
"symbol|{name}|{}",
if p.is_null() { "ABSENT" } else { "present" }
);
}
if copy_all.is_null()
|| get_group.is_null()
|| get_subgroup.is_null()
|| get_name.is_null()
|| get_unit.is_null()
{
println!("channel enumeration skipped: required symbol(s) missing (see above)");
return;
}
unsafe {
let copy_all: FnCopyAllChannels = std::mem::transmute(copy_all);
let get_group: FnChannelGetStr = std::mem::transmute(get_group);
let get_subgroup: FnChannelGetStr = std::mem::transmute(get_subgroup);
let get_name: FnChannelGetStr = std::mem::transmute(get_name);
let get_unit: FnChannelGetStr = std::mem::transmute(get_unit);
let all = copy_all(0, 0);
if all.is_null() {
println!("IOReportCopyAllChannels returned NULL — no channels visible");
return;
}
let key = CString::new("IOReportChannels").expect("static key");
let cfkey = CFStringCreateWithCString(
std::ptr::null(),
key.as_ptr(),
K_CF_STRING_ENCODING_UTF8,
);
let channels = CFDictionaryGetValue(all, cfkey);
if channels.is_null() {
println!("channels dict has no IOReportChannels array — dump it via ioreg");
CFRelease(all);
return;
}
let n = CFArrayGetCount(channels);
println!("== {n} channels (fixture format; commit verbatim per README) ==");
for i in 0..n {
let item = CFArrayGetValueAtIndex(channels, i);
if item.is_null() {
continue;
}
println!(
"channel|{}|{}|{}|{}",
cfstring_to_string(get_group(item)),
cfstring_to_string(get_subgroup(item)),
cfstring_to_string(get_name(item)),
cfstring_to_string(get_unit(item)),
);
}
CFRelease(all);
}
}
}