BLInterpretEFIXMLRepresentationAsDevice.c [plain text]
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFUnserialize.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/IOBSD.h>
#include "bless.h"
#include "bless_private.h"
#if USE_DISKARBITRATION
#include <DiskArbitration/DiskArbitration.h>
#endif
static int checkForMatch(BLContextPtr context, CFDictionaryRef dict,
char *bsdName);
static CFUUIDRef copyVolUUIDFromDiskArb(BLContextPtr context,
CFStringRef bsdName);
int BLInterpretEFIXMLRepresentationAsDevice(BLContextPtr context,
CFStringRef xmlString,
char *bsdName)
{
CFArrayRef efiArray = NULL;
CFIndex count, i;
char buffer[1024];
int foundDevice = 0;
if(!CFStringGetCString(xmlString, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
return 1;
}
efiArray = IOCFUnserialize(buffer,
kCFAllocatorDefault,
0,
NULL);
if(efiArray == NULL) {
contextprintf(context, kBLLogLevelError, "Could not unserialize string\n");
return 2;
}
if(CFGetTypeID(efiArray) != CFArrayGetTypeID()) {
CFRelease(efiArray);
contextprintf(context, kBLLogLevelError, "Bad type in XML string\n");
return 2;
}
count = CFArrayGetCount(efiArray);
for(i=0; i < count; i++) {
CFDictionaryRef dict = CFArrayGetValueAtIndex(efiArray, i);
if(CFGetTypeID(dict) != CFDictionaryGetTypeID()) {
CFRelease(efiArray);
contextprintf(context, kBLLogLevelError, "Bad type in XML string\n");
return 2;
}
if(checkForMatch(context, dict, bsdName)) {
foundDevice = 1;
break;
}
}
CFRelease(efiArray);
if(!foundDevice) {
contextprintf(context, kBLLogLevelVerbose, "Could not find disk device for string\n");
return 4;
}
return 0;
}
static int checkForMatch(BLContextPtr context, CFDictionaryRef dict,
char *bsdName)
{
CFStringRef fsuuid;
CFUUIDRef uuid = NULL;
io_service_t service;
int foundDevice = 0;
fsuuid = CFDictionaryGetValue(dict, CFSTR("BLVolumeUUID"));
if(fsuuid && CFGetTypeID(fsuuid) == CFStringGetTypeID()) {
uuid = CFUUIDCreateFromString(kCFAllocatorDefault, fsuuid);
if(uuid == NULL) {
contextprintf(context, kBLLogLevelVerbose, "Bad Volume UUID\n");
}
}
if(uuid) {
CFStringRef lastBSDName = CFDictionaryGetValue(dict, CFSTR("BLLastBSDName"));
if(lastBSDName && CFGetTypeID(lastBSDName) == CFStringGetTypeID()) {
CFUUIDRef dauuid = NULL;
dauuid = copyVolUUIDFromDiskArb(context, lastBSDName);
if(dauuid && CFEqual(uuid, dauuid)) {
CFStringGetCString(lastBSDName, bsdName,
MNAMELEN, kCFStringEncodingUTF8);
contextprintf(context, kBLLogLevelVerbose, "Found device: %s\n", bsdName);
foundDevice = 1;
CFRelease(dauuid);
}
}
}
if (!foundDevice) {
CFDictionaryRef iomatch = CFDictionaryGetValue(dict, CFSTR("IOMatch"));
if(iomatch && CFGetTypeID(iomatch) == CFDictionaryGetTypeID()) {
CFRetain(iomatch); service = IOServiceGetMatchingService(kIOMasterPortDefault,iomatch);
if(service != IO_OBJECT_NULL) {
CFStringRef name = NULL;
if(!IOObjectConformsTo(service,kIOMediaClass)) {
contextprintf(context, kBLLogLevelVerbose, "found service but it is not a media object\n");
} else {
name = IORegistryEntryCreateCFProperty(service,
CFSTR(kIOBSDNameKey),
kCFAllocatorDefault,
0);
if(name && CFGetTypeID(name) == CFStringGetTypeID()) {
if(uuid) {
CFUUIDRef dauuid = NULL;
dauuid = copyVolUUIDFromDiskArb(context, name);
if(dauuid && CFEqual(uuid, dauuid)) {
foundDevice = 1;
CFRelease(dauuid);
} else {
foundDevice = 0;
}
} else {
foundDevice = 1;
}
if(foundDevice) {
CFStringGetCString(name, bsdName, MNAMELEN,kCFStringEncodingUTF8);
contextprintf(context, kBLLogLevelVerbose, "Found device: %s\n", bsdName);
}
}
if(name) CFRelease(name);
}
IOObjectRelease(service);
}
}
}
if(uuid) {
CFRelease(uuid);
}
if(foundDevice) {
return 1;
} else {
return 0;
}
}
static CFUUIDRef copyVolUUIDFromDiskArb(BLContextPtr context,
CFStringRef bsdName)
{
CFUUIDRef dauuid = NULL;
#if USE_DISKARBITRATION
DASessionRef session = NULL;
DADiskRef dadisk = NULL;
char lastBSDNameCString[MNAMELEN];
CFStringGetCString(bsdName, lastBSDNameCString,
sizeof(lastBSDNameCString),kCFStringEncodingUTF8);
session = DASessionCreate(kCFAllocatorDefault);
if(session) {
dadisk = DADiskCreateFromBSDName(kCFAllocatorDefault, session,
lastBSDNameCString);
if(dadisk) {
CFDictionaryRef descrip = DADiskCopyDescription(dadisk);
if(descrip) {
dauuid = CFDictionaryGetValue(descrip, kDADiskDescriptionVolumeUUIDKey);
if(dauuid)
CFRetain(dauuid);
CFRelease(descrip);
}
CFRelease(dadisk);
}
CFRelease(session);
}
#endif // USE_DISKARBITRATION
return dauuid;
}