2

How can I retrieve following information programmatically in c++:

This is a terminal command in Mac OSX:

ioreg -c IOPlatformExpertDevice | awk '/board-id/ {print $4}' | awk -F '\"' '{print $2}'

I use IOKit library to retrieve information such as IOPlatformSerialNumber and PlatformUUID information. But I couldn't find any corresponding key for "board-id".

Elizafox
  • 1,316
  • 1
  • 8
  • 9
Riddhi Rathod
  • 115
  • 1
  • 10
  • As a least resort, you could use `pipe()` and the command line from your question. – πάντα ῥεῖ Jul 29 '16 at 19:00
  • 1
    @MarkSetchell Sorry, mistyped. – πάντα ῥεῖ Jul 29 '16 at 19:47
  • I did not want to use popen() to execute any command line statement from my code because its not that reliable. Suppose if I use some "awk" or "sed" utility along with command line statement to parse out the values I need, then I am making following huge assumptions: 1. Other users have these utilities on their machine 2. These utilities are valid and not some malicious code with same name as standard utilities. To prevent error on these cases, it is a good practice to use in-built system libraries and call them from product code whenever you can. Thanks for suggestions. – Riddhi Rathod Aug 17 '16 at 14:30

1 Answers1

2

If you have the io_service_t handle to the IOPlatformExpertDevice in your C++ code, you can use the IORegistryEntryCreateCFProperty() function to get the "board-id" property. Expect to receive a CFData object, but check for null and the correct type id to be sure. Then, use the usual CFData methods to extract the data in the form you want.

If you haven't got the IOService handle yet, you should be able to get there using either IOServiceGetMatchingService() (I'm hoping it's safe to assume there will only be one IOPlatformExpertDevice instance.), or using IORegistryGetRootEntry() to get the root, and walking the IORegistry graph to the platform expert device with IORegistryEntryGetChildEntry() or similar.

As the board-id property doesn't have a named symbolic constant, you'll just have to hardcode it:

CFTypeRef board_id_property = IORegistryEntryCreateCFProperty(
  platform_expert_device, CFSTR("board-id"), kCFAllocatorDefault, 0);

Note that property values can take different types, including CFNumber, CFBoolean, CFString, CFData, CFArray, and CFDictionary, and you need to be prepared to handle the case where the type doesn't match the one you expect, or when NULL is returned (if the property does not exist). Check the type using CFGetTypeID(), e.g.:

if (board_id_property != NULL && CFGetTypeID(board_id_property) == CFDataGetTypeID())
{
    CFDataRef board_id_data = (CFDataRef)board_id_property;
    // safe to use CFData* functions now
    ...

    CFRelease(board_id_property);
}
else
{
    // Unexpected, do error handling.
    ...

    if (board_id_property != NULL)
        CFRelease(board_id_property);
}
pmdj
  • 22,018
  • 3
  • 52
  • 103
  • I have io_service_t handle, but there is no key for "board-id" as there is one for kIOPlatformSerialNumberKey. – Riddhi Rathod Jul 31 '16 at 20:45
  • It's just a string, which seems to be hardcoded in various bits of OS X source code, without a symbolic constant. You'll just have to use the raw string. – pmdj Aug 01 '16 at 12:01
  • So I tried what you suggested i.e. using raw string. Next 2 attempts failed with error "-[__NSCFData _fastCharacterContents]: unrecognized selector sent to instance ...": IORegistryEntryCreateCFProperty(platformExpert, CFSTR("board-id"), kCFAllocatorDefault, 0) & IORegistryEntryCreateCFProperty(platformExpert, CFSTR("manufacturer"), kCFAllocatorDefault, 0). However, IORegistryEntryCreateCFProperty(platformExpert, CFSTR("IOPolledInterface"), kCFAllocatorDefault, 0) succeeds. When you run "ioreg -rd1 -c IOPlatformExpertDevice" terminal command there is difference in naming of these variables. – Riddhi Rathod Aug 17 '16 at 15:27
  • I think the properties with lower case naming are maybe under some different registry entry and not under io. This is just a mu guess, not sure though. – Riddhi Rathod Aug 17 '16 at 15:32
  • No, if you look at the source code, they're just the same as any other. The failures you're seeing are not coming from `IORegistryEntryCreateCFProperty`. I assume you're treating the returned property as a CFType other than the one it actually is. "board-id" and "manufacturer" are binary data, so the returned pointer will be a `CFDataRef`. (**Always** check it with `CFGetTypeID()` though!) The "IOPolledInterface" property is an SMCPolledInterface object, which is not serialisable, so resolves to a string. (`CFString`) Use the right accessors, and it should start working. – pmdj Aug 17 '16 at 16:40
  • 1
    Thank you so much, really appreciate your help. I followed your suggestion, retrieved CFDataRef and then converted to std::string for printing purposes and I get the exact same value as with terminal command. Why apple documentation is so bad, related to their system programming stuff! – Riddhi Rathod Aug 19 '16 at 01:40