// first look up the media object, then create a // custom matching dictionary that should be persistent // from boot to boot int addMatchingInfoForBSDName(BLContextPtr context, mach_port_t masterPort, CFMutableDictionaryRef dict, const char *bsdName, bool shortForm) { io_service_t media = IO_OBJECT_NULL, checkMedia = IO_OBJECT_NULL; CFStringRef uuid = NULL; CFMutableDictionaryRef propDict = NULL; kern_return_t kret; CFStringRef lastBSDName = NULL; lastBSDName = CFStringCreateWithCString(kCFAllocatorDefault, bsdName, kCFStringEncodingUTF8); propDict = IOBSDNameMatching(masterPort, 0, bsdName); CFDictionarySetValue(propDict, CFSTR(kIOProviderClassKey), CFSTR(kIOMediaClass)); media = IOServiceGetMatchingService(masterPort, propDict); propDict = NULL; if(media == IO_OBJECT_NULL) { contextprintf(context, kBLLogLevelError, "Could not find object for %s\n", bsdName); CFRelease(lastBSDName); return 1; } uuid = IORegistryEntryCreateCFProperty(media, CFSTR(kIOMediaUUIDKey), kCFAllocatorDefault, 0); if(uuid == NULL) { CFUUIDRef fsuuid = NULL; CFStringRef fsuuidstr = NULL; io_string_t path; #if USE_DISKARBITRATION DASessionRef session = NULL; DADiskRef dadisk = NULL; contextprintf(context, kBLLogLevelVerbose, "IOMedia %s does not have a partition %s\n", bsdName, kIOMediaUUIDKey); session = DASessionCreate(kCFAllocatorDefault); if(session) { dadisk = DADiskCreateFromIOMedia(kCFAllocatorDefault, session, media); if(dadisk) { CFDictionaryRef descrip = DADiskCopyDescription(dadisk); if(descrip) { fsuuid = CFDictionaryGetValue(descrip, kDADiskDescriptionVolumeUUIDKey); if(fsuuid) CFRetain(fsuuid); CFRelease(descrip); } CFRelease(dadisk); } CFRelease(session); } #endif // USE_DISKARBITRATION if(fsuuid) { char fsuuidCString[64]; fsuuidstr = CFUUIDCreateString(kCFAllocatorDefault, fsuuid); CFStringGetCString(fsuuidstr,fsuuidCString,sizeof(fsuuidCString),kCFStringEncodingUTF8); contextprintf(context, kBLLogLevelVerbose, "DADiskRef %s has Volume UUID %s\n", bsdName, fsuuidCString); CFRelease(fsuuid); } else { contextprintf(context, kBLLogLevelVerbose, "IOMedia %s does not have a Volume UUID\n", bsdName); } // we have a volume UUID, but our primary matching mechanism will be the device path kret = IORegistryEntryGetPath(media, kIODeviceTreePlane,path); if(kret) { contextprintf(context, kBLLogLevelVerbose, "IOMedia %s does not have device tree path\n", bsdName); propDict = IOServiceMatching(kIOMediaClass); CFDictionaryAddValue(propDict, CFSTR(kIOBSDNameKey), lastBSDName); // add UUID as hint if(fsuuidstr) CFDictionaryAddValue(dict, CFSTR("BLVolumeUUID"), fsuuidstr); } else { CFStringRef blpath = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8); contextprintf(context, kBLLogLevelVerbose, "IOMedia %s has path %s\n", bsdName, path); propDict = IOServiceMatching(kIOMediaClass); CFDictionaryAddValue(propDict, CFSTR(kIOPathMatchKey), blpath); CFRelease(blpath); // add UUID as hint if(fsuuidstr) CFDictionaryAddValue(dict, CFSTR("BLVolumeUUID"), fsuuidstr); CFDictionaryAddValue(dict, CFSTR("BLLastBSDName"), lastBSDName); } if(fsuuidstr) { CFRelease(fsuuidstr); } } else { CFMutableDictionaryRef propMatch; contextprintf(context, kBLLogLevelVerbose, "IOMedia %s has UUID %s\n", bsdName, BLGetCStringDescription(uuid)); propMatch = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(propMatch, CFSTR(kIOMediaUUIDKey), uuid); propDict = IOServiceMatching(kIOMediaClass); CFDictionaryAddValue(propDict, CFSTR(kIOPropertyMatchKey), propMatch); CFRelease(propMatch); // add a hint to the top-level dict CFDictionaryAddValue(dict, CFSTR("BLLastBSDName"), lastBSDName); CFRelease(uuid); } // verify the dictionary matches CFRetain(propDict); // consumed below checkMedia = IOServiceGetMatchingService(masterPort, propDict); if(IO_OBJECT_NULL == checkMedia || !IOObjectIsEqualTo(media, checkMedia)) { contextprintf(context, kBLLogLevelVerbose, "Inconsistent registry entries for %s\n", bsdName); if(IO_OBJECT_NULL != checkMedia) IOObjectRelease(checkMedia); IOObjectRelease(media); CFRelease(lastBSDName); CFRelease(propDict); return 2; } IOObjectRelease(checkMedia); IOObjectRelease(media); CFDictionaryAddValue(dict, CFSTR("IOMatch"), propDict); CFRelease(lastBSDName); CFRelease(propDict); if(shortForm) { CFDictionaryAddValue(dict, CFSTR("IOEFIShortForm"), kCFBooleanTrue); } return 0; }
void genIOMediaDevice(const io_service_t& device, std::vector<std::string>& whole_devices, QueryData& results) { Row r; // Get the device properties CFMutableDictionaryRef properties; IORegistryEntryCreateCFProperties( device, &properties, kCFAllocatorDefault, kNilOptions); r["uuid"] = getIOKitProperty(properties, "UUID"); r["name"] = "/dev/" + getIOKitProperty(properties, "BSD Name"); r["size"] = getIOKitProperty(properties, "Size"); auto type = getIOKitProperty(properties, "Whole"); if (type == "1") { // The "Whole" property applies to the entire disk entry, not partitions. whole_devices.push_back(r["name"]); } else { // Otherwise search the list of whole disks to find the node parent. for (const auto& parent : whole_devices) { if (r.at("name").find(parent) == 0) { r["parent"] = parent; } } } // This is the IOKit name, which is the device's label. io_name_t name; auto kr = IORegistryEntryGetName(device, name); if (kr == KERN_SUCCESS && (char*)name != nullptr) { r["label"] = std::string(name); } // Remaining details come from the Disk Arbitration service. DASessionRef session = DASessionCreate(kCFAllocatorDefault); CFDictionaryRef details; if (session != nullptr) { auto disk = DADiskCreateFromIOMedia(kCFAllocatorDefault, session, device); if (disk != nullptr) { details = DADiskCopyDescription(disk); if (details != nullptr) { r["vendor"] = getIOKitProperty((CFMutableDictionaryRef)details, "DADeviceVendor"); r["model"] = getIOKitProperty((CFMutableDictionaryRef)details, "DADeviceModel"); r["type"] = getIOKitProperty((CFMutableDictionaryRef)details, "DADeviceProtocol"); CFRelease(details); } CFRelease(disk); } CFRelease(session); } results.push_back(r); CFRelease(properties); }