如何在macOS上通过编程弹出USB设备?Intel设备IOkit问题求助
在macOS上实现USB设备弹出的实用方案
1. IOkit相关的替代方案
你之前的问题出在直接从USB接口层找BSD名称——BSD名称属于块存储设备层(而非USB接口层),所以需要从USB设备节点出发,遍历找到对应的块存储类节点:
- 实现步骤:
- 用
IOServiceMatching(kIOUSBDeviceClassName)或kIOUSBHostDeviceClassName匹配目标VID/PID的USB设备; - 从该USB设备节点递归遍历注册表(
kIOServicePlane),查找类名为kIOBlockStorageDeviceClassName的子节点; - 在块存储节点上调用
IORegistryEntryCreateCFProperty获取kIOBSDNameKey。
- 用
示例代码片段:
// 假设已找到匹配VID/PID的usbDevice对象 CFTypeRef bsdName = NULL; io_iterator_t iter; IORegistryEntryCreateIterator(usbDevice, kIOServicePlane, kIORegistryIterateRecursively, &iter); io_service_t service; while ((service = IOIteratorNext(iter))) { CFStringRef className = IOObjectCopyClass(service); if (CFEqual(className, CFSTR(kIOBlockStorageDeviceClassName))) { bsdName = IORegistryEntryCreateCFProperty(service, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0); IOObjectRelease(service); break; } IOObjectRelease(service); } IOObjectRelease(iter); if (bsdName) { // 得到BSD名称,比如"disk2s1" CFRelease(bsdName); }
2. 使用系统调用/系统API实现弹出
方案A:调用diskutil命令
直接通过系统调用执行diskutil eject命令,前提是已拿到设备的BSD路径(如/dev/diskX):
#include <stdlib.h> int ejectUSB(const char *bsdPath) { char cmd[256]; snprintf(cmd, sizeof(cmd), "diskutil eject %s", bsdPath); return system(cmd); }
方案B:使用DiskArbitration框架(推荐)
这是系统官方的磁盘操作API,比直接调用命令更可靠,无需直接操作IOkit:
#include <DiskArbitration/DiskArbitration.h> void ejectDiskWithBSDName(const char *bsdName) { DASessionRef session = DASessionCreate(kCFAllocatorDefault); if (!session) return; DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, bsdName); if (disk) { DADiskEject(disk, kDADiskEjectOptionDefault, NULL, NULL, NULL); CFRelease(disk); } CFRelease(session); }
3. 不依赖IOkit的实现思路
方案A:解析ioreg命令输出
通过调用ioreg -p IOUSB -l -w 0命令,解析输出提取目标VID/PID对应的BSD名称,再调用弹出命令:
- 核心逻辑:
- 执行
ioreg命令并捕获输出; - 找到包含目标VID(如
idVendor = 0x1234)和PID(idProduct = 0x5678)的USB设备; - 从该设备的子节点中提取
IOBlockStorageDevice对应的BSD Name字段; - 拼接成
/dev/[BSD名称]路径,执行diskutil eject。
- 执行
方案B:通过挂载点关联设备
如果USB设备已挂载到/Volumes下,可通过stat获取挂载点的设备ID,结合diskutil获取BSD路径后弹出:
#include <sys/stat.h> // 假设挂载点为"/Volumes/MyUSB" struct stat st; if (stat("/Volumes/MyUSB", &st) == 0) { char cmd[256]; snprintf(cmd, sizeof(cmd), "diskutil info -plist %d:%d | grep -A1 BSDName | awk -F'>' '{print $2}' | awk -F'<' '{print $1}'", major(st.st_dev), minor(st.st_dev)); // 解析cmd输出得到BSD名称,再执行弹出操作 }
内容的提问来源于stack exchange,提问作者puris
相关产品推荐
相关产品推荐

