1/* 2 * Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * BLDeviceNeedsBooter.c 25 * bless 26 * 27 * Created by Shantonu Sen on 2/7/05. 28 * Copyright 2005-2007 Apple Inc. All Rights Reserved. 29 * 30 * $Id: BLDeviceNeedsBooter.c,v 1.8 2006/02/20 22:49:57 ssen Exp $ 31 * 32 */ 33 34#include <stdlib.h> 35#include <unistd.h> 36 37#include <mach/mach_error.h> 38 39#include <IOKit/IOKitLib.h> 40#include <IOKit/IOBSD.h> 41#include <IOKit/IOKitKeys.h> 42#include <IOKit/storage/IOMedia.h> 43 44#include <CoreFoundation/CoreFoundation.h> 45 46#include <sys/param.h> 47 48#include "bless.h" 49#include "bless_private.h" 50 51// based on the partition type, deduce whether OpenFirmware needs 52// an auxiliary HFS+ filesystem on an Apple_Boot partition. Doesn't 53// apply to RAID or non-OF systems 54int BLDeviceNeedsBooter(BLContextPtr context, const char * device, 55 int32_t *needsBooter, 56 int32_t *isBooter, 57 io_service_t *booterPartition) 58{ 59 char wholename[MAXPATHLEN], bootername[MAXPATHLEN]; 60 io_service_t booter = 0, maindev = 0; 61 uint32_t partnum; 62 int ret; 63 CFStringRef content = NULL; 64 CFBooleanRef isWhole = NULL; 65 66 67 *needsBooter = 0; 68 *isBooter = 0; 69 *booterPartition = 0; 70 71 ret = BLGetIOServiceForDeviceName(context, (char *)device + 5, &maindev); 72 if(ret) { 73 contextprintf(context, kBLLogLevelError, "Can't find IOService for %s\n", device + 5 ); 74 return 3; 75 } 76 77 isWhole = IORegistryEntryCreateCFProperty( maindev, CFSTR(kIOMediaWholeKey), 78 kCFAllocatorDefault, 0); 79 80 if(isWhole == NULL || CFGetTypeID(isWhole) !=CFBooleanGetTypeID()) { 81 contextprintf(context, kBLLogLevelError, "Wrong type of IOKit entry for kIOMediaWholeKey\n" ); 82 if(isWhole) CFRelease(isWhole); 83 IOObjectRelease(maindev); 84 return 4; 85 } 86 87 if(CFEqual(isWhole, kCFBooleanTrue)) { 88 contextprintf(context, kBLLogLevelVerbose, "Device IS whole\n" ); 89 CFRelease(isWhole); 90 IOObjectRelease(maindev); 91 return 0; 92 } else { 93 contextprintf(context, kBLLogLevelVerbose, "Device IS NOT whole\n" ); 94 CFRelease(isWhole); 95 } 96 97 // Okay, it's partitioned. There might be helper partitions, though... 98 content = IORegistryEntryCreateCFProperty(maindev, CFSTR(kIOMediaContentKey), 99 kCFAllocatorDefault, 0); 100 101 if(content == NULL || CFGetTypeID(content) != CFStringGetTypeID()) { 102 contextprintf(context, kBLLogLevelError, "Wrong type of IOKit entry for kIOMediaContentKey\n" ); 103 if(content) CFRelease(content); 104 IOObjectRelease(maindev); 105 return 4; 106 } 107 108 109 if(CFStringCompare(content, CFSTR("Apple_HFS"), 0) == kCFCompareEqualTo 110 || CFStringCompare(content, CFSTR("48465300-0000-11AA-AA11-00306543ECAC"), 0) == kCFCompareEqualTo) { 111 contextprintf(context, kBLLogLevelVerbose, "Apple_HFS partition. No external loader\n" ); 112 // it's an HFS partition. no loader needed 113 CFRelease(content); 114 IOObjectRelease(maindev); 115 return 0; 116 } 117 118 if(CFStringCompare(content, CFSTR("Apple_Boot_RAID"), 0) 119 == kCFCompareEqualTo) { 120 contextprintf(context, kBLLogLevelVerbose, "Apple_Boot_RAID partition. No external loader\n" ); 121 // it's an old style RAID partition. no loader needed 122 CFRelease(content); 123 IOObjectRelease(maindev); 124 return 0; 125 } 126 127 if(CFStringCompare(content, CFSTR("Apple_Boot"), 0) == kCFCompareEqualTo) { 128 contextprintf(context, kBLLogLevelVerbose, "Apple_Boot partition is an external loader\n" ); 129 // it's an loader itself 130 CFRelease(content); 131 *isBooter = 1; 132 *booterPartition = maindev; 133 134 return 0; 135 } 136 137 IOObjectRelease(maindev); 138 CFRelease(content); 139 140 // if we got this far, it's partitioned media that needs a booter. check for it 141 contextprintf(context, kBLLogLevelVerbose, "NOT Apple_HFS, Apple_Boot_RAID, or Apple_Boot partition.\n"); 142 143 // check if partition is Apple_HFS 144 ret = BLGetParentDevice(context, device, wholename, &partnum); 145 if(ret) { 146 contextprintf(context, kBLLogLevelError, "Could not determine partition for %s\n", device); 147 return 2; 148 } 149 150 if(partnum == 1) { 151 // partition is of the form disk1s1. No booter at disk1s0 152 contextprintf(context, kBLLogLevelVerbose, "Skipping search for booter for %s\n", device ); 153 return 0; 154 } 155 156 // devname now points to "disk1s3" 157 sprintf(bootername, "%ss%u", wholename + 5, partnum - 1); 158 159 contextprintf(context, kBLLogLevelVerbose, "Looking for external loader at %s\n", bootername ); 160 161 ret = BLGetIOServiceForDeviceName(context, bootername, &booter); 162 if(ret) { 163 contextprintf(context, kBLLogLevelError, "Can't find IOService for %s\n", bootername ); 164 return 3; 165 } 166 167 content = IORegistryEntryCreateCFProperty(booter, CFSTR(kIOMediaContentKey), 168 kCFAllocatorDefault, 0); 169 170 if(content == NULL || CFGetTypeID(content) != CFStringGetTypeID()) { 171 contextprintf(context, kBLLogLevelError, "Wrong type of IOKit entry for kIOMediaContentKey\n" ); 172 if(content) CFRelease(content); 173 IOObjectRelease(booter); 174 return 4; 175 } 176 177 178 if(CFStringCompare(content, CFSTR("Apple_Boot"), 0) 179 == kCFCompareEqualTo) { 180 contextprintf(context, kBLLogLevelVerbose, "Found Apple_Boot partition\n" ); 181 // it's an HFS partition. no loader needed 182 CFRelease(content); 183 *needsBooter = 1; 184 *booterPartition = booter; 185 return 0; 186 } 187 188 IOObjectRelease(booter); 189 CFRelease(content); 190 191 // we needed a partition, but we couldn't find it 192 193 return 6; 194} 195