BLGetDeviceForOpenFirmwarePath.c [plain text]
#import <mach/mach_error.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/IOBSD.h>
#import <IOKit/IOKitKeys.h>
#import <IOKit/storage/IOMedia.h>
#import <CoreFoundation/CoreFoundation.h>
#include <string.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include "bless.h"
#include "bless_private.h"
#undef SUPPORT_RAID
#define SUPPORT_RAID 0
#if SUPPORT_RAID
#import <IOKit/storage/RAID/AppleRAIDUserLib.h>
static int findRAIDForMember(BLContextPtr context, mach_port_t iokitPort, char * mntfrm);
static int isRAIDPath(BLContextPtr context, mach_port_t iokitPort, io_service_t member,
CFDictionaryRef raidEntry);
#endif
extern int getPNameAndPType(BLContextPtr context,
char * target,
char * pname,
char * ptype);
int BLGetDeviceForOpenFirmwarePath(BLContextPtr context, const char * ofstring, char * mntfrm) {
kern_return_t kret;
mach_port_t ourIOKitPort;
char newof[1024];
char targetPName[MAXPATHLEN];
char targetPType[MAXPATHLEN];
int ret;
char *comma = NULL;;
strcpy(newof, ofstring);
comma = strrchr(newof, ',');
if(comma == NULL) { return 1;
}
*comma = '\0';
if((kret = IOMasterPort(bootstrap_port, &ourIOKitPort)) != KERN_SUCCESS) {
return 2;
}
strcpy(mntfrm, "/dev/");
kret = IOServiceOFPathToBSDName(ourIOKitPort,
newof,
mntfrm + 5);
contextprintf(context, kBLLogLevelVerbose, "bsd name is %s\n", mntfrm );
ret = getPNameAndPType(context, mntfrm+5, targetPName, targetPType);
if(ret) {
contextprintf(context, kBLLogLevelVerbose, "Could not get partition type for %s\n", mntfrm );
return 3;
}
contextprintf(context, kBLLogLevelVerbose, "Partition name is %s. Partition type is %s\n", targetPName, targetPType);
#if 0
if(strcmp("Apple_Boot", targetPType) != 0 && strcmp("Apple_Boot_RAID", targetPType) != 0) {
contextprintf(context, kBLLogLevelVerbose, "No external booter needed\n");
return 0;
}
char parentDev[MNAMELEN];
uint32_t slice = 0;
BLPartitionType partitionType = 0;
contextprintf(context, kBLLogLevelVerbose, "Looking for root partition\n");
if(strcmp("Apple_Boot", targetPType) == 0) {
ret = BLGetParentDeviceAndPartitionType(context,mntfrm,
parentDev,
&slice,
&partitionType);
if(ret) {
contextprintf(context, kBLLogLevelVerbose, "Could not get information about partition map for %s\n", mntfrm);
return 3;
}
slice += 1; sprintf(mntfrm, "%ss%u", parentDev, slice);
contextprintf(context, kBLLogLevelVerbose, "Now looking at %s\n", mntfrm);
}
ret = getPNameAndPType(context, mntfrm+5, targetPName, targetPType);
if(ret) {
contextprintf(context, kBLLogLevelVerbose, "Could not get partition type for %s\n", mntfrm );
return 3;
}
contextprintf(context, kBLLogLevelVerbose, "Partition name is %s. Partition type is %s\n", targetPName, targetPType);
if(strcmp("Apple_Boot", targetPType) == 0) {
contextprintf(context, kBLLogLevelError, "Apple_Boot followed by another Apple_Boot\n");
return 4;
}
if(strcmp("Apple_HFS", targetPType) == 0) {
contextprintf(context, kBLLogLevelError, "Apple_HFS does not require an Apple_Boot\n");
return 4;
}
#if SUPPORT_RAID
if(strcmp("Apple_RAID", targetPType) == 0 || strcmp("Apple_Boot_RAID", targetPType) == 0) {
contextprintf(context, kBLLogLevelVerbose, "%s is an Apple_RAID. Looking for exported volume\n", mntfrm);
ret = findRAIDForMember(context, ourIOKitPort, mntfrm);
if(ret) {
contextprintf(context, kBLLogLevelError, "Couldn't find appropriate RAID volume for %s\n", mntfrm);
return 4;
}
}
#endif
#endif // 0
return 0;
}
#if SUPPORT_RAID
static int findRAIDForMember(BLContextPtr context, mach_port_t iokitPort, char * mntfrm)
{
kern_return_t kret;
io_service_t member;
io_iterator_t raiditer;
io_service_t raidservice;
CFMutableDictionaryRef matching = NULL;
CFMutableDictionaryRef props = NULL;
int foundRAID = 0;
int errnum;
errnum = BLGetIOServiceForDeviceName(context, mntfrm+5, &member);
if(errnum) {
contextprintf(context, kBLLogLevelError, "Could not find IOKit entry for %s\n" , mntfrm+5);
return 4;
}
contextprintf(context, kBLLogLevelVerbose, "Found service for %s\n", mntfrm+5);
matching = IOServiceMatching(kIOMediaClass);
props = CFDictionaryCreateMutable(kCFAllocatorDefault,0,&kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(props, CFSTR(kAppleRAIDIsRAIDKey), kCFBooleanTrue);
CFDictionaryAddValue(props, CFSTR(kIOMediaLeafKey), kCFBooleanTrue);
CFDictionaryAddValue(matching, CFSTR(kIOPropertyMatchKey), props);
CFRelease(props);
kret = IOServiceGetMatchingServices(iokitPort, matching, &raiditer);
if(kret != KERN_SUCCESS) {
contextprintf(context, kBLLogLevelVerbose, "Could find any RAID devices on the system\n");
return 2;
}
while((raidservice = IOIteratorNext(raiditer))) {
CFTypeRef data = NULL;
contextprintf(context, kBLLogLevelVerbose, "Checking if member is part of RAID %x\n", raidservice);
data = IORegistryEntrySearchCFProperty( raidservice,
kIOServicePlane,
CFSTR(kIOBootDeviceKey),
kCFAllocatorDefault,
kIORegistryIterateRecursively|
kIORegistryIterateParents);
if(data == NULL) {
IOObjectRelease(raidservice);
raidservice = 0;
continue;
}
if(CFGetTypeID(data) == CFArrayGetTypeID()) {
CFIndex i, count = CFArrayGetCount(data);
for(i=0; i < count && !foundRAID; i++) {
CFDictionaryRef ent = CFArrayGetValueAtIndex((CFArrayRef)data,i);
if(isRAIDPath(context, iokitPort, member, ent)) {
foundRAID = 1;
CFRelease(data);
break;
}
}
if(foundRAID) break;
} else if(CFGetTypeID(data) == CFDictionaryGetTypeID()) {
if(isRAIDPath(context, iokitPort, member, (CFDictionaryRef)data)) {
foundRAID = 1;
CFRelease(data);
break;
}
} else {
contextprintf(context, kBLLogLevelError, "Invalid RAID boot data\n" );
CFRelease(data);
IOObjectRelease(raidservice);
raidservice = 0;
continue;
}
IOObjectRelease(raidservice);
}
IOObjectRelease(raiditer);
if(foundRAID) {
CFStringRef name = (CFStringRef)IORegistryEntryCreateCFProperty(
raidservice,
CFSTR(kIOBSDNameKey),
kCFAllocatorDefault,
0);
if(!CFStringGetCString(name, mntfrm+5, MAXPATHLEN-5, kCFStringEncodingUTF8)) {
CFRelease(name);
IOObjectRelease(raidservice);
return 1;
}
CFRelease(name);
IOObjectRelease(raidservice);
contextprintf(context, kBLLogLevelVerbose, "RAID device is %s\n", mntfrm );
return 0;
}
return 5;
}
static int isRAIDPath(BLContextPtr context, mach_port_t iokitPort, io_service_t member,
CFDictionaryRef raidEntry)
{
CFStringRef path;
io_string_t cpath;
io_service_t service;
path = CFDictionaryGetValue(raidEntry, CFSTR(kIOBootDevicePathKey));
if(path == NULL) return 0;
if(!CFStringGetCString(path,cpath,sizeof(cpath),kCFStringEncodingUTF8))
return 0;
contextprintf(context, kBLLogLevelVerbose, "Comparing member to %s", cpath);
service = IORegistryEntryFromPath(iokitPort, cpath);
if(service == 0) {
contextprintf(context, kBLLogLevelVerbose, "\nCould not find service\n");
return 0;
}
if(IOObjectIsEqualTo(service, member)) {
contextprintf(context, kBLLogLevelVerbose, "\tEQUAL\n");
IOObjectRelease(service);
return 1;
} else {
contextprintf(context, kBLLogLevelVerbose, "\tNOT EQUAL\n");
}
IOObjectRelease(service);
return 0;
}
#endif // SUPPORT_RAID