// 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;
}
Ejemplo n.º 2
-1
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);
}