1/* 2 * Copyright (c) 2006-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 * BLInterpretEFIXMLRepresentationAsLegacyDevice.c 25 * bless 26 * 27 * Created by Shantonu Sen on 2/8/06. 28 * Copyright 2006-2007 Apple Inc. All Rights Reserved. 29 * 30 */ 31 32#include <IOKit/IOKitLib.h> 33#include <IOKit/IOCFUnserialize.h> 34#include <IOKit/storage/IOMedia.h> 35#include <IOKit/IOBSD.h> 36 37#include <sys/mount.h> 38#include <stdbool.h> 39 40#include "bless.h" 41#include "bless_private.h" 42 43static int findMatch(BLContextPtr context, CFStringRef legacyType, 44 CFStringRef xmlString, char *bsdName, int bsdNameLen); 45 46int BLInterpretEFIXMLRepresentationAsLegacyDevice(BLContextPtr context, 47 CFStringRef xmlString, 48 char *bsdName, 49 int bsdNameLen) 50{ 51 CFArrayRef efiArray = NULL; 52 CFIndex count, i; 53 int ret; 54 char buffer[1024]; 55 int foundLegacyPath = 0; 56 CFStringRef legacyType = NULL; 57 58 if(!BLSupportsLegacyMode(context)) { 59 contextprintf(context, kBLLogLevelVerbose, "Legacy mode not supported on this system\n"); 60 return 1; 61 } 62 63 if(!CFStringGetCString(xmlString, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { 64 return 1; 65 } 66 67 efiArray = IOCFUnserialize(buffer, 68 kCFAllocatorDefault, 69 0, 70 NULL); 71 if(efiArray == NULL) { 72 contextprintf(context, kBLLogLevelError, "Could not unserialize string\n"); 73 return 2; 74 } 75 76 if(CFGetTypeID(efiArray) != CFArrayGetTypeID()) { 77 CFRelease(efiArray); 78 contextprintf(context, kBLLogLevelError, "Bad type in XML string\n"); 79 return 2; 80 } 81 82 // for each entry, see if there's a volume UUID, or if IOMatch works 83 count = CFArrayGetCount(efiArray); 84 for(i=0; i < count; i++) { 85 CFDictionaryRef dict = CFArrayGetValueAtIndex(efiArray, i); 86 CFStringRef compType; 87 88 if(CFGetTypeID(dict) != CFDictionaryGetTypeID()) { 89 CFRelease(efiArray); 90 contextprintf(context, kBLLogLevelError, "Bad type in XML string\n"); 91 return 2; 92 } 93 94 compType = CFDictionaryGetValue(dict, CFSTR("IOEFIDevicePathType")); 95 if(compType && CFEqual(compType, CFSTR("MediaFirmwareVolumeFilePath"))) { 96 CFStringRef guid; 97 98 guid = CFDictionaryGetValue(dict, CFSTR("Guid")); 99 if(guid && CFEqual(guid, CFSTR("2B0585EB-D8B8-49A9-8B8C-E21B01AEF2B7"))) { 100 foundLegacyPath = 1; 101 continue; 102 } 103 } 104 105 legacyType = CFDictionaryGetValue(dict, CFSTR("IOEFIBootOption")); 106 if(legacyType && CFGetTypeID(legacyType) == CFStringGetTypeID()) { 107 CFRetain(legacyType); 108 } else { 109 legacyType = NULL; 110 } 111 112 } 113 114 if(!foundLegacyPath || !legacyType) { 115 contextprintf(context, kBLLogLevelVerbose, "Boot option is not a legacy device\n"); 116 return 4; 117 } else { 118 contextprintf(context, kBLLogLevelVerbose, "Boot option is a legacy device\n"); 119 } 120 121 ret = findMatch(context, legacyType, xmlString, bsdName, bsdNameLen); 122 if(ret) { 123 contextprintf(context, kBLLogLevelVerbose, "Could not find device for legacy type\n"); 124 return 5; 125 } 126 127 CFRelease(legacyType); 128 129 return 0; 130} 131 132 133static int findMatch(BLContextPtr context, CFStringRef legacyType, 134 CFStringRef xmlString, char *bsdName, int bsdNameLen) 135{ 136 char legacyCStr[256]; 137 int numfs, i; 138 int ret; 139 size_t bufsize; 140 struct statfs *buf; 141 bool foundMatch = false; 142 143 if(CFStringGetCString(legacyType, legacyCStr, sizeof(legacyCStr), kCFStringEncodingUTF8)) { 144 contextprintf(context, kBLLogLevelVerbose, "Searching for legacy type '%s'\n", legacyCStr); 145 } 146 147 numfs = getfsstat(NULL, 0, MNT_NOWAIT); 148 if(numfs < 0) { 149 contextprintf(context, kBLLogLevelError, "Could not get list of filesystems\n"); 150 return 1; 151 } 152 153 bufsize = numfs*sizeof(buf[0]); 154 buf = (struct statfs *)calloc(bufsize, sizeof(char)); 155 if(buf == NULL) { 156 return 2; 157 } 158 159 numfs = getfsstat(buf, bufsize, MNT_NOWAIT); 160 if(numfs < 0) { 161 contextprintf(context, kBLLogLevelError, "Could not get list of filesystems\n"); 162 return 1; 163 } 164 165 for(i=0; i < numfs; i++) { 166 struct statfs *sb = &buf[i]; 167 CFStringRef newXML = NULL; 168 169 if(!(sb->f_flags & MNT_LOCAL)) 170 continue; 171 172 if(0 != strncmp(sb->f_mntfromname, "/dev/", 5)) 173 continue; 174 175 contextprintf(context, kBLLogLevelVerbose, "filesystem[%d] '%s' => '%s'\n", 176 i, sb->f_mntfromname, sb->f_mntonname); 177 178 ret = BLCreateEFIXMLRepresentationForLegacyDevice(context, 179 sb->f_mntfromname + 5, 180 &newXML); 181 if(ret) { 182 contextprintf(context, kBLLogLevelVerbose, "Ignoring '%s'\n", 183 sb->f_mntfromname); 184 continue; 185 } 186 187 if(CFEqual(newXML, xmlString)) { 188 // this is a match 189 // see if it's a filesystem that gets priority 190 191 192 if(0 == strcmp("ntfs", sb->f_fstypename) 193 || 0 == strcmp("msdos", sb->f_fstypename)) { 194 195 strlcpy(bsdName, sb->f_mntfromname + 5, bsdNameLen); 196 CFRelease(newXML); 197 foundMatch = true; 198 break; 199 } 200 201 if(!foundMatch) { 202 // we don't have anything else, so go for it 203 strlcpy(bsdName, sb->f_mntfromname + 5, bsdNameLen); 204 foundMatch = true; 205 } else { 206 // no better than existing match 207 } 208 209 } 210 211 CFRelease(newXML); 212 213 } 214 215 free(buf); 216 217 if(!foundMatch) 218 return 3; 219 220 contextprintf(context, kBLLogLevelVerbose, "Matching legacy device '%s'\n", 221 bsdName); 222 223 224 return 0; 225 226} 227