Rust系统级IOKit绑定库IOKit-sys的使用,提供macOS底层硬件和驱动交互能力
Rust系统级IOKit绑定库IOKit-sys的使用,提供macOS底层硬件和驱动交互能力
IOKit-sys
包为OS X上的IOKit
C库提供了声明和链接。遵循*-sys
包的约定,IOKit-sys
包没有在原生库之上定义更高级别的抽象。
使用方法
在Cargo.toml
中添加IOKit-sys
作为依赖项:
[dependencies]
IOKit-sys = "0.1"
导入IOKit_sys
crate并使用Apple提供的原生IOKit
库中定义的函数:
extern crate IOKit_sys as io;
完整示例代码
下面是一个使用IOKit-sys查询系统电源信息的完整示例:
extern crate IOKit_sys as io;
use std::ptr;
fn main() {
unsafe {
// 获取IOPowerSources服务的连接
let power_sources = io::IOServiceGetMatchingService(
io::kIOMasterPortDefault,
io::IOServiceMatching(b"IOPMPowerSource\0".as_ptr() as *const _),
);
if power_sources != io::kIOReturnSuccess {
println!("Failed to get power sources service");
return;
}
// 打开服务连接
let mut conn: io::io_connect_t = 0;
let result = io::IOServiceOpen(power_sources, io::mach_task_self(), 0, &mut conn);
if result != io::kIOReturnSuccess {
println!("Failed to open IOService connection");
return;
}
// 获取电源信息
let mut output_cnt: u32 = 1;
let mut output: u32 = 0;
let result = io::IOConnectCallMethod(
conn,
0, // power source information selector
ptr::null(),
0,
ptr::null(),
0,
&mut output,
&mut output_cnt,
ptr::null_mut(),
ptr::null_mut(),
);
if result == io::kIOReturnSuccess {
println!("Current power source: {}", output);
} else {
println!("Failed to get power source info");
}
// 关闭连接
io::IOServiceClose(conn);
}
}
另一个完整示例:获取设备序列号
extern crate IOKit_sys as io;
use std::ffi::CStr;
use std::ptr;
fn main() {
unsafe {
// 获取平台专家服务
let platform_expert = io::IOServiceGetMatchingService(
io::kIOMasterPortDefault,
io::IOServiceMatching(b"IOPlatformExpertDevice\0".as_ptr() as *const _),
);
if platform_expert.is_null() {
println!("Failed to get platform expert service");
return;
}
// 获取序列号属性
let serial_number = io::IORegistryEntryCreateCFProperty(
platform_expert,
"IOPlatformSerialNumber".as_ptr() as *const _,
io::kCFAllocatorDefault,
0,
);
if serial_number.is_null() {
println!("Failed to get serial number");
io::IOObjectRelease(platform_expert);
return;
}
// 转换为字符串并打印
let cstr = CStr::from_ptr(io::CFStringGetCStringPtr(serial_number as _, io::kCFStringEncodingUTF8));
println!("Device serial number: {:?}", cstr);
// 释放资源
io::CFRelease(serial_number);
io::IOObjectRelease(platform_expert);
}
}
贡献
如果您发现IOKit-sys
缺少某些功能,可以在Github上提交issue或pull request添加所需功能。
代码结构说明:每个IOKit框架的头文件对应一个源文件。例如,src/io_return.rs
包含来自IOKit/IOReturn.h
的定义。每个文件中的定义顺序与匹配的头文件中的顺序大致相同。每个文件都在crate根目录中重新导出,例如pub use io_return::*
。
贡献者
- David Cuddeback (dcuddeback)
- Dave Hylands (dhylands)
- forticulous
- Nicolas Dusart (ndusart)
许可证
版权所有 © 2015 David Cuddeback
根据MIT许可证分发。
Rust系统级IOKit绑定库IOKit-sys使用指南
IOKit-sys
是Rust语言的系统级绑定库,提供了与macOS IOKit框架交互的能力,允许开发者访问macOS底层硬件和驱动功能。
基本介绍
IOKit是macOS的核心框架,用于与设备驱动程序和硬件交互。IOKit-sys
提供了对IOKit的Rust绑定,使Rust开发者能够:
- 发现和枚举设备
- 与设备驱动程序通信
- 访问硬件属性和功能
- 监控设备状态变化
使用方法
1. 添加依赖
首先在Cargo.toml
中添加依赖:
[dependencies]
IOKit-sys = "0.1"
2. 基本使用示例
extern crate IOKit_sys as io;
use std::ptr;
fn main() {
unsafe {
// 获取IOKit主端口
let mut master_port: io::mach_port_t = 0;
let kr = io::IOMasterPort(io::kIOMasterPortDefault, &mut master_port);
if kr != io::KERN_SUCCESS {
eprintln!("Failed to get IOKit master port");
return;
}
// 创建匹配字典
let matching_dict = io::IOServiceMatching(b"IOUSBDevice\0".as_ptr() as *const _);
// 获取设备迭代器
let mut iter: io::io_iterator_t = 0;
let kr = io::IOServiceGetMatchingServices(master_port, matching_dict, &mut iter);
if kr != io::KERN_SUCCESS {
eprintln!("Failed to get matching services");
return;
}
// 遍历USB设备
let mut device = io::IOIteratorNext(iter);
while device != 0 {
let mut name: [u8; 128] = [0; 128];
let kr = io::IORegistryEntryGetName(device, name.as_mut_ptr() as *mut _);
if kr == io::KERN_SUCCESS {
let name_str = std::ffi::CStr::from_ptr(name.as_ptr() as *const _)
.to_string_lossy();
println!("Found device: {}", name_str);
}
io::IOObjectRelease(device);
device = io::IOIteratorNext(iter);
}
io::IOObjectRelease(iter);
}
}
3. 读取设备属性
unsafe fn read_device_property(device: io::io_object_t, property_name: &str) {
let prop_name = std::ffi::CString::new(property_name).unwrap();
let mut value: io::CFTypeRef = ptr::null_mut();
let kr = io::IORegistryEntryCreateCFProperty(
device,
prop_name.as_ptr(),
io::kCFAllocatorDefault,
0,
&mut value
);
if kr == io::KERN_SUCCESS && !value.is_null() {
// 处理属性值
println!("Property {} found", property_name);
io::CFRelease(value);
}
}
4. 监控设备通知
unsafe fn setup_device_notification(notify_port: io::mach_port_t, matching_dict: io::CFDictionaryRef) {
let mut notification: io::io_object_t = 0;
let kr = io::IOServiceAddMatchingNotification(
notify_port,
io::kIOFirstMatchNotification,
matching_dict,
Some(device_added_callback),
ptr::null_mut(),
&mut notification
);
if kr == io::KERN_SUCCESS {
// 触发初始回调
device_added_callback(ptr::null_mut(), notification);
}
}
extern "C" fn device_added_callback(refcon: *mut std::ffi::c_void, iterator: io::io_iterator_t) {
unsafe {
let mut device = io::IOIteratorNext(iterator);
while device != 0 {
println!("New device detected!");
io::IOObjectRelease(device);
device = io::IOIteratorNext(iterator);
}
}
}
完整示例代码
下面是一个完整的USB设备枚举和监控示例:
extern crate IOKit_sys as io;
extern crate libc;
use std::ptr;
use std::ffi::CString;
use std::thread;
use std::time::Duration;
// USB设备结构体
struct USBDevice {
name: String,
vendor_id: Option<u32>,
product_id: Option<u32>,
}
fn main() {
// 1. 枚举所有USB设备
let usb_devices = enumerate_usb_devices().unwrap_or_else(|e| {
eprintln!("Error enumerating USB devices: {}", e);
Vec::new()
});
println!("Found {} USB devices:", usb_devices.len());
for (i, device) in usb_devices.iter().enumerate() {
println!("{}. {}", i + 1, device.name);
if let Some(vid) = device.vendor_id {
println!(" Vendor ID: {:04x}", vid);
}
if let Some(pid) = device.product_id {
println!(" Product ID: {:04x}", pid);
}
}
// 2. 设置USB设备插拔通知
if let Err(e) = setup_usb_notifications() {
eprintln!("Failed to setup USB notifications: {}", e);
}
}
// 枚举所有USB设备
fn enumerate_usb_devices() -> Result<Vec<USBDevice>, String> {
unsafe {
let mut devices = Vec::new();
let mut master_port: io::mach_port_t = 0;
// 获取IOKit主端口
let kr = io::IOMasterPort(io::kIOMasterPortDefault, &mut master_port);
if kr != io::KERN_SUCCESS {
return Err("Failed to get IOKit master port".to_string());
}
// 创建USB设备匹配字典
let matching_dict = io::IOServiceMatching(b"IOUSBDevice\0".as_ptr() as *const _);
if matching_dict.is_null() {
return Err("Failed to create matching dictionary".to_string());
}
// 获取设备迭代器
let mut iter: io::io_iterator_t = 0;
let kr = io::IOServiceGetMatchingServices(master_port, matching_dict, &mut iter);
if kr != io::KERN_SUCCESS {
return Err("Failed to get matching services".to_string());
}
// 遍历USB设备
let mut device = io::IOIteratorNext(iter);
while device != 0 {
// 获取设备名称
let mut name_buf: [u8; 128] = [0; 128];
let mut usb_device = USBDevice {
name: String::new(),
vendor_id: None,
product_id: None,
};
if io::IORegistryEntryGetName(device, name_buf.as_mut_ptr() as *mut _) == io::KERN_SUCCESS {
usb_device.name = std::ffi::CStr::from_ptr(name_buf.as_ptr() as *const _)
.to_string_lossy()
.into_owned();
}
// 获取厂商ID和产品ID
usb_device.vendor_id = get_property_uint32(device, "idVendor");
usb_device.product_id = get_property_uint32(device, "idProduct");
devices.push(usb_device);
io::IOObjectRelease(device);
device = io::IOIteratorNext(iter);
}
io::IOObjectRelease(iter);
Ok(devices)
}
}
// 获取设备的32位无符号整数属性
unsafe fn get_property_uint32(device: io::io_object_t, property_name: &str) -> Option<u32> {
let prop_name = CString::new(property_name).unwrap();
let mut value: io::CFTypeRef = ptr::null_mut();
let kr = io::IORegistryEntryCreateCFProperty(
device,
prop_name.as_ptr(),
io::kCFAllocatorDefault,
0,
&mut value
);
if kr == io::KERN_SUCCESS && !value.is_null() {
let number = value as io::CFNumberRef;
let mut num: u32 = 0;
if io::CFNumberGetValue(number, io::kCFNumberSInt32Type, &mut num as *mut _ as *mut _) != 0 {
io::CFRelease(value);
return Some(num);
}
io::CFRelease(value);
}
None
}
// 设置USB设备插拔通知
fn setup_usb_notifications() -> Result<(), String> {
unsafe {
let mut master_port: io::mach_port_t = 0;
let kr = io::IOMasterPort(io::kIOMasterPortDefault, &mut master_port);
if kr != io::KERN_SUCCESS {
return Err("Failed to get IOKit master port".to_string());
}
// 创建通知端口
let notify_port = io::IONotificationPortCreate(master_port);
if notify_port.is_null() {
return Err("Failed to create notification port".to_string());
}
// 将通知端口添加到运行循环
let run_loop_src = io::IONotificationPortGetRunLoopSource(notify_port);
let run_loop = io::CFRunLoopGetCurrent();
io::CFRunLoopAddSource(run_loop, run_loop_src, io::kCFRunLoopDefaultMode);
// 创建USB设备匹配字典
let matching_dict = io::IOServiceMatching(b"IOUSBDevice\0".as_ptr() as *const _);
if matching_dict.is_null() {
return Err("Failed to create matching dictionary".to_string());
}
// 添加设备添加通知
let mut added_iter: io::io_iterator_t = 0;
let kr = io::IOServiceAddMatchingNotification(
notify_port,
io::kIOFirstMatchNotification,
matching_dict,
Some(device_notification_callback),
ptr::null_mut(),
&mut added_iter
);
if kr != io::KERN_SUCCESS {
return Err("Failed to add matching notification".to_string());
}
// 触发初始回调
device_notification_callback(ptr::null_mut(), added_iter);
// 添加设备移除通知
let matching_dict = io::IOServiceMatching(b"IOUSBDevice\0".as_ptr() as *const _);
let mut removed_iter: io::io_iterator_t = 0;
let kr = io::IOServiceAddMatchingNotification(
notify_port,
io::kIOTerminatedNotification,
matching_dict,
Some(device_notification_callback),
ptr::null_mut(),
&mut removed_iter
);
if kr != io::KERN_SUCCESS {
return Err("Failed to add terminated notification".to_string());
}
// 触发初始回调
device_notification_callback(ptr::null_mut(), removed_iter);
println!("Monitoring USB devices. Press Ctrl+C to exit...");
// 运行事件循环
io::CFRunLoopRun();
Ok(())
}
}
// 设备通知回调函数
extern "C" fn device_notification_callback(refcon: *mut libc::c_void, iterator: io::io_iterator_t) {
unsafe {
let mut device = io::IOIteratorNext(iterator);
while device != 0 {
let mut name_buf: [u8; 128] = [0; 128];
if io::IORegistryEntryGetName(device, name_buf.as_mut_ptr() as *mut _) == io::KERN_SUCCESS {
let name = std::ffi::CStr::from_ptr(name_buf.as_ptr() as *const _)
.to_string_lossy();
// 检查是设备连接还是断开
let mut is_terminated = 0;
io::IOObjectIsClass(device, b"IOUSBDevice\0".as_ptr() as *const _, &mut is_terminated);
if is_terminated != 0 {
println!("USB device disconnected: {}", name);
} else {
println!("USB device connected: {}", name);
}
}
io::IOObjectRelease(device);
device = io::IOIteratorNext(iterator);
}
}
}
注意事项
-
安全性:IOKit-sys大部分操作都是
unsafe
的,需要开发者自行确保内存和线程安全。 -
错误处理:所有IOKit函数都返回kern_return_t,应检查返回值是否为KERN_SUCCESS。
-
资源管理:使用IOObjectRelease释放获取的对象,避免内存泄漏。
-
权限:某些操作可能需要root权限或特定的entitlements。
-
线程:IOKit操作通常应在主线程执行。
高级功能
- 直接内存访问:通过IOConnectCallMethod与内核扩展通信
- 电源管理:监控和处理设备电源状态变化
- 热插拔检测:实时检测设备连接/断开事件
IOKit-sys
为Rust开发者提供了强大的macOS硬件交互能力,但需要谨慎使用以避免系统稳定性问题。