【问题标题】:What is the best way to get BSD drive names on macOS (Swift)?在 macOS (Swift) 上获取 BSD 驱动器名称的最佳方法是什么?
【发布时间】:2022-10-23 18:51:25
【问题描述】:

在不使用磁盘工具CLI 包装器?

不想使用任何包装纸与 CLI 界面交互,因为这种交互方式相当减缓不可靠

这是为什么我不喜欢使用 CLI 包装器的一个例子
(相比'DiskUtil CLI Wrapper 已用时间。''磁盘仲裁时间已过')

为我的问题实施解决方案的最佳方法是什么?
使用来自的数据IOReg?
如果是,我如何获得使用它的连接设备的 BSD 名称列表?

这是我想要得到的一个例子:

["disk0", "disk0s1", "disk0s2", "disk0s3", "disk1", "disk1s1", "disk1s2", "disk1s3", "disk1s4", "disk2", "disk2s1", "disk2s2", "disk3", "disk3s1", "disk3s1s1", "disk3s2", "disk3s3", "disk3s4", "disk3s5", "disk3s6", "disk4", "disk4s1", "disk4s2", "disk5", "disk5s1", "disk5s2", "disk6", "disk6s1", "disk6s2", "disk10", "disk10s1", "disk10s2", "disk11", "disk11s1"]

目前,我有以下内容:

static func getMountedBSDNames() -> [String] {
    guard let session = DASessionCreate(nil) else { return [] }
    guard let mountedVolumeURLs = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil) else { return [] }
    
    var BSDNames: [String] = []
    
    for volumeURL in mountedVolumeURLs {
        if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volumeURL as CFURL), let BSDName = DADiskGetBSDName(disk) {
            BSDNames.append(
                String(cString: BSDName)
            )
        }
    }
    
    return BSDNames
}

但在这种情况下,仅安装正在返回。
我什至希望那里有那些,那是被弹出

【问题讨论】:

    标签: swift macos cocoa iokit diskarbitration


    【解决方案1】:

    我使用 IOReg 查找方法达到了预期的结果:

    经过时间

    func getDriveBSDNames() -> [String] {
        var iterator: io_iterator_t = 0
    
        let matching: CFDictionary = IOServiceMatching(kIOServicePlane)
    
        // Use 'kIOMasterPortDefault' for macOS older than 12.0 Monterey
        IOServiceGetMatchingServices(kIOMainPortDefault, matching, &iterator)
        var child: io_object_t = IOIteratorNext(iterator)
        
        var BSDNames: [String] = []
        while child > 0 {
            if let BSDNameAnyObject = IORegistryEntryCreateCFProperty(child, "BSD Name" as CFString, kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)) {
                
                if let BSDNameString = (BSDNameAnyObject.takeRetainedValue() as? String), BSDNameString.starts(with: "disk") {
                    BSDNames.append(
                        BSDNameString
                    )
                }
            }
            
            child = IOIteratorNext(iterator)
        }
        
        return BSDNames
    }
    

    在这种情况下,还需要使用以下方法过滤结果的输出:
    BSDNameString.starts(with: "disk")
    (否则会添加一些不必要的设备,如en0、anpi0、llw0等)

    【讨论】:

    • 我认为您最终可能会在使用此方法的结果列表中使用同样具有 BSD 名称的串行端口。至少,将"IOStorage" 传递给IOServiceMatching() 而不是"IOService"(这也应该可以提高性能)。
    【解决方案2】:

    请注意,虽然磁盘仲裁框架没有同步枚举所有磁盘的功能,但它确实通过注册磁盘外观回调来有效地支持异步枚举。根据您的用例,这可能有用也可能没用 - 当为用户提供交互式设备列表时,这通常正是您想要的,因为您会自动收到新添加设备的通知。

    抱歉,我不使用 Swift,但以下 C 代码应该很容易理解,以便在其他语言中提出类似的东西。

    #include <DiskArbitration/DiskArbitration.h>
    #include <stdio.h>
    
    static void disk_appeared(DADiskRef disk, void* context)
    {
        printf("%s
    ", DADiskGetBSDName(disk) ?: "(null)");
    }
    
    int main()
    {
        DASessionRef session = DASessionCreate(kCFAllocatorDefault);
        DASessionSetDispatchQueue(session, dispatch_get_main_queue());
        DARegisterDiskAppearedCallback(session, NULL, disk_appeared, NULL /*context*/);
        dispatch_main();
    }
    

    请注意,对于没有 BSD 名称的 APFS 快照也会调用回调,因此 DADiskGetBSDName 返回 NULL 并且您必须进行一些过滤。

    【讨论】:

      猜你喜欢
      • 2010-09-13
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-13
      • 1970-01-01
      • 2010-11-19
      • 1970-01-01
      相关资源
      最近更新 更多