BLDeviceNeedsBooter.c [plain text]
#include <stdlib.h>
#include <unistd.h>
#include <mach/mach_error.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/storage/IOMedia.h>
#include <CoreFoundation/CoreFoundation.h>
#include <sys/param.h>
#include "bless.h"
#include "bless_private.h"
int BLDeviceNeedsBooter(BLContextPtr context, const char * device,
int32_t *needsBooter,
int32_t *isBooter,
io_service_t *booterPartition)
{
char wholename[MAXPATHLEN], bootername[MAXPATHLEN];
io_service_t booter = 0, maindev = 0;
uint32_t partnum;
int ret;
CFStringRef content = NULL;
CFBooleanRef isWhole = NULL;
*needsBooter = 0;
*isBooter = 0;
*booterPartition = 0;
ret = BLGetIOServiceForDeviceName(context, (char *)device + 5, &maindev);
if(ret) {
contextprintf(context, kBLLogLevelError, "Can't find IOService for %s\n", device + 5 );
return 3;
}
isWhole = IORegistryEntryCreateCFProperty( maindev, CFSTR(kIOMediaWholeKey),
kCFAllocatorDefault, 0);
if(isWhole == NULL || CFGetTypeID(isWhole) !=CFBooleanGetTypeID()) {
contextprintf(context, kBLLogLevelError, "Wrong type of IOKit entry for kIOMediaWholeKey\n" );
if(isWhole) CFRelease(isWhole);
IOObjectRelease(maindev);
return 4;
}
if(CFEqual(isWhole, kCFBooleanTrue)) {
contextprintf(context, kBLLogLevelVerbose, "Device IS whole\n" );
CFRelease(isWhole);
IOObjectRelease(maindev);
return 0;
} else {
contextprintf(context, kBLLogLevelVerbose, "Device IS NOT whole\n" );
CFRelease(isWhole);
}
content = IORegistryEntryCreateCFProperty(maindev, CFSTR(kIOMediaContentKey),
kCFAllocatorDefault, 0);
if(content == NULL || CFGetTypeID(content) != CFStringGetTypeID()) {
contextprintf(context, kBLLogLevelError, "Wrong type of IOKit entry for kIOMediaContentKey\n" );
if(content) CFRelease(content);
IOObjectRelease(maindev);
return 4;
}
if(CFStringCompare(content, CFSTR("Apple_HFS"), 0) == kCFCompareEqualTo
|| CFStringCompare(content, CFSTR("48465300-0000-11AA-AA11-00306543ECAC"), 0) == kCFCompareEqualTo) {
contextprintf(context, kBLLogLevelVerbose, "Apple_HFS partition. No external loader\n" );
CFRelease(content);
IOObjectRelease(maindev);
return 0;
}
if(CFStringCompare(content, CFSTR("Apple_Boot_RAID"), 0)
== kCFCompareEqualTo) {
contextprintf(context, kBLLogLevelVerbose, "Apple_Boot_RAID partition. No external loader\n" );
CFRelease(content);
IOObjectRelease(maindev);
return 0;
}
if(CFStringCompare(content, CFSTR("Apple_Boot"), 0) == kCFCompareEqualTo) {
contextprintf(context, kBLLogLevelVerbose, "Apple_Boot partition is an external loader\n" );
CFRelease(content);
*isBooter = 1;
*booterPartition = maindev;
return 0;
}
IOObjectRelease(maindev);
CFRelease(content);
contextprintf(context, kBLLogLevelVerbose, "NOT Apple_HFS, Apple_Boot_RAID, or Apple_Boot partition.\n");
ret = BLGetParentDevice(context, device, wholename, &partnum);
if(ret) {
contextprintf(context, kBLLogLevelError, "Could not determine partition for %s\n", device);
return 2;
}
if(partnum == 1) {
contextprintf(context, kBLLogLevelVerbose, "Skipping search for booter for %s\n", device );
return 0;
}
sprintf(bootername, "%ss%u", wholename + 5, partnum - 1);
contextprintf(context, kBLLogLevelVerbose, "Looking for external loader at %s\n", bootername );
ret = BLGetIOServiceForDeviceName(context, bootername, &booter);
if(ret) {
contextprintf(context, kBLLogLevelError, "Can't find IOService for %s\n", bootername );
return 3;
}
content = IORegistryEntryCreateCFProperty(booter, CFSTR(kIOMediaContentKey),
kCFAllocatorDefault, 0);
if(content == NULL || CFGetTypeID(content) != CFStringGetTypeID()) {
contextprintf(context, kBLLogLevelError, "Wrong type of IOKit entry for kIOMediaContentKey\n" );
if(content) CFRelease(content);
IOObjectRelease(booter);
return 4;
}
if(CFStringCompare(content, CFSTR("Apple_Boot"), 0)
== kCFCompareEqualTo) {
contextprintf(context, kBLLogLevelVerbose, "Found Apple_Boot partition\n" );
CFRelease(content);
*needsBooter = 1;
*booterPartition = booter;
return 0;
}
IOObjectRelease(booter);
CFRelease(content);
return 6;
}