如何从Mac硬盘中获取序列号?

14

是否有一种简单的方法可以使用API获取Mac中所有硬盘的序列号?

基本上,我正在寻找一个硬盘的唯一标识符,以便我可以确定该硬盘是否被我的应用程序使用(或引用)过。

如果有其他解决方案,请告诉我。

注:我需要这个解决方案适用于10.4及以上版本。

8个回答

12

我不确定"AppleUSBEHCI"是否是要查找的正确内容,但你可以使用IOKit框架检索这种数据:

#include <IOKit/IOKitLib.h>
#include <Cocoa/Cocoa.h>

kern_return_t   kr;
io_iterator_t   io_objects;
io_service_t    io_service;

kr = IOServiceGetMatchingServices(kIOMasterPortDefault,
            IOServiceNameMatching("AppleUSBEHCI"), &io_objects);

if(kr != KERN_SUCCESS)
    exit(1);

while((io_service= IOIteratorNext(io_objects)))
{
    kr = IORegistryEntryCreateCFProperties(io_service, &service_properties, kCFAllocatorDefault, kNilOptions);
    if(kr == KERN_SUCCESS)
    {
        NSDictionary * m = (NSDictionary *)service_properties;
        NSLog(@"%@", m);
        CFRelease(service_properties);
    }

    io_iterator_t   iter;
    //handle kr error
    kr = IORegistryEntryGetChildIterator(io_service, kIOServicePlane, &iter);

    io_registry_entry_t     child;
    while( (child = IOIteratorNext( iter )))
    {
        kr = IORegistryEntryCreateCFProperties(child, &child_props,  kCFAllocatorDefault, kNilOptions );
        NSLog(@"Child props: %@", child_props);
        //release child_props
    }

    IOObjectRelease(io_service);
}

IOObjectRelease(io_objects);

在继续使用IOKit的路径之前,您可能需要尝试mouviciel的答案。对于连接到USB的设备,请使用IOServiceNameMatching("AppleUSBEHCI"),然后使用IORegistryEntryGetChildIterator(io_service,kIOServicePlane,&iter)迭代遍历其所有子项。 - diciu
我很感激你的帮助。我尝试了mouviciel的解决方案,但没有起作用。当我尝试使用IORegistryEntryGetChildIterator时,它返回错误(268435459),我只是在IOServiceGetMatchingServices之后调用了它,不确定我错过了什么。 - Girish Kolari
你可能在不合适的迭代器上调用了IORegistryEntryGetChildIterator函数。我已经编辑了我的答案,以说明如何迭代ioregistryentry的子项。请注意,我已经使用USB存储设备进行了测试 - 硬盘可能会以不同的方式出现。在编写生产代码之前,您需要阅读一些关于IOKit的资料。 - diciu
它起作用了,你是对的,我在迭代器上调用了IORegistryEntryGetChildIterator。在进入生产之前,我会考虑阅读IOKit的建议。感谢你的帮助。 - Girish Kolari
有没有办法在这个过程中获取“BSD名称:”。我可以在系统配置文件中看到BSD名称,但是在“child_props”中看不到这个名称。我能得到一些帮助吗?基本上,我正在尝试将序列号与驱动器(BSD名称-因为它是唯一的)进行映射。 - Girish Kolari
显示剩余3条评论

9

通过命令行:

ioreg -rd1 -w0 -c AppleAHCIDiskDriver | grep Serial

这会为您提供内置硬盘的序列号。


更新:AppleAHCIDiskDriver在较新的机器上不再使用,因此这将为空。也许可以考虑使用AppleANS2Controller。 - Alex M

6
我认为最好获取卷UUID(例如在磁盘实用工具中显示)。 可以使用Disk Arbitration框架获取UUID,该框架比IOKit高级一些,更易于使用。 使用DADiskCreateFromBSDName创建DADiskRef,并使用DADiskCopyDescription获取信息字典,查找键kDADiskDescriptionMediaUUIDKey。可以通过statfs获取有关安装点等的信息。 话虽如此,只需调用带有选项-plist的命令行实用程序diskutil即可以plist格式获取信息。

样例代码 FSMegaInfo 也许可以指导如何获取更多关于磁盘的信息。


感谢提供宝贵的信息。据我理解,UUID是在系统中生成的,不确定是否可以被视为唯一的。在我的系统中,我无法看到设备的UUID。 - Girish Kolari
UUID是“通用唯一标识符”的缩写,它是唯一的。例如,它用于控制在/etc/fstab中挂载什么。 另外,很奇怪你看不到UUID。在你的机器上,diskutil info /dev/disk0s2返回什么?在列表中看不到Volume UUID条目吗?你可能需要将上面的/disk0s2更改为实际拥有的内容。首先使用diskutil list进行检查。 - Yuji
一个卷标识别符(Volume ID)从概念上与磁盘标识符(Drive ID)有许多不同之处,一个磁盘可以有多个卷,一个磁盘的卷不一定需要被挂载,卷可以被添加和删除,因此即使磁盘保持不变,其ID也可能会改变。 - valexa

3
以下将列出SATA总线上的串行号。目前你无法知道它是哪个设备,但你可以通过一些脚本/解析来实现。我使用了“sed”来删除所有空格,“awk”来仅隔离序列号,以防您不熟悉:
$ system_profiler SPSerialATADataType -detailLevel medium | grep Serial | sed -e 's/[\<\>\"\ ]//g' | -F':' '{print $2}'

2
我猜你也会觉得这个有用: -> $ system_profiler SPSerialATADataType -detailLevel medium | grep -e "Serial" -e "Model" | awk -F': ' '{print $2}' - Robert Jansson
更新:新机器上带有NVME驱动器的SPSerialATADataType不存在。 - Alex M

2
驱动器ID可以从IORegistry中获取,具体如下:
  • 内部驱动器:在“设备特征”中的IOAHCIBlockStorageDevice string属性“序列号”中,例如:(WD-WCAV5D1345345)

  • USB驱动器:在“USB串行号”中的IOUSBDevice string属性中,例如:(5743415654564561373734)

  • FireWire驱动器:在“协议特性”中的IOReducedBlockServices number属性“GUID”中,例如:(407345709348650)

  • Thunderbolt驱动器:??

这些ID是持久的,这意味着连接到不同机器的相同外部驱动器将显示相同的ID。

1

请查看IOKit

在您的Mac上有两个方便的工具可以了解它的可能性:

  • ioreg,一个命令行工具
  • IORegistryExplorer,带有GUI的相同工具。

0

这是一个非常古老的帖子,也是第一个搜索结果,因此我会添加另一种有用的方法,该方法依赖于安装Homebrew和smartmontools

安装homebrew,然后...

brew install smartmontools

你可以运行
smartctl -x disk0s3 | grep "Serial Number"

你需要使用diskutil list命令来查找磁盘ID。

-1
也许你可以在硬盘上放置一个隐藏文件,让你的应用程序使用?这就是苹果的Time Machine的做法。

好的建议,如果从硬盘获取一些信息,我可以考虑这个解决方案。如果文件被删除了,在我的应用程序中就无法识别它了。 - Girish Kolari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接