1/* 2 * Copyright (c) 2001-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 * BLGetParentDevice.c 25 * bless 26 * 27 * Created by Shantonu Sen <ssen@apple.com> on Mon Jun 25 2001. 28 * Copyright (c) 2001-2007 Apple Inc. All Rights Reserved. 29 * 30 * $Id: BLGetParentDevice.c,v 1.19 2006/02/20 22:49:56 ssen Exp $ 31 * 32 */ 33 34#include <stdlib.h> 35#include <stdio.h> 36#include <unistd.h> 37#include <sys/stat.h> 38#include <sys/param.h> 39#include <sys/mount.h> 40 41#import <mach/mach_error.h> 42 43#import <IOKit/IOKitLib.h> 44#import <IOKit/IOBSD.h> 45#import <IOKit/storage/IOMedia.h> 46#import <IOKit/storage/IOPartitionScheme.h> 47 48#include <CoreFoundation/CoreFoundation.h> 49 50#include "bless.h" 51#include "bless_private.h" 52 53int BLGetParentDevice(BLContextPtr context, const char * partitionDev, 54 char * parentDev, 55 uint32_t *partitionNum) { 56 57 return BLGetParentDeviceAndPartitionType(context, partitionDev, parentDev, partitionNum, NULL); 58} 59 60 61int BLGetParentDeviceAndPartitionType(BLContextPtr context, const char * partitionDev, 62 char * parentDev, 63 uint32_t *partitionNum, 64 BLPartitionType *partitionType) { 65 66 int result = 0; 67 kern_return_t kret; 68 io_iterator_t services = MACH_PORT_NULL; 69 io_iterator_t parents = MACH_PORT_NULL; 70 io_registry_entry_t service = MACH_PORT_NULL; 71 io_iterator_t grandparents = MACH_PORT_NULL; 72 io_registry_entry_t service2 = MACH_PORT_NULL; 73 io_object_t obj = MACH_PORT_NULL; 74 CFNumberRef pn = NULL; 75 CFStringRef content = NULL; 76 77 char par[MNAMELEN]; 78 79 parentDev[0] = '\0'; 80 81 kret = IOServiceGetMatchingServices(kIOMasterPortDefault, 82 IOBSDNameMatching(kIOMasterPortDefault, 83 0, 84 (char *)partitionDev + 5), 85 &services); 86 if (kret != KERN_SUCCESS) { 87 result = 3; 88 goto finish; 89 } 90 91 // Should only be one IOKit object for this volume. (And we only want one.) 92 obj = IOIteratorNext(services); 93 if (!obj) { 94 result = 4; 95 goto finish; 96 } 97 98 // we have the IOMedia for the partition. 99 100 pn = (CFNumberRef)IORegistryEntryCreateCFProperty(obj, CFSTR(kIOMediaPartitionIDKey), 101 kCFAllocatorDefault, 0); 102 103 if(pn == NULL) { 104 result = 4; 105 goto finish; 106 } 107 108 if (CFGetTypeID(pn) != CFNumberGetTypeID()) { 109 result = 5; 110 goto finish; 111 } 112 113 CFNumberGetValue(pn, kCFNumberSInt32Type, partitionNum); 114 115 kret = IORegistryEntryGetParentIterator (obj, kIOServicePlane, 116 &parents); 117 if (kret) { 118 result = 6; 119 goto finish; 120 /* We'll never loop forever. */ 121 } 122 123 while ( (service = IOIteratorNext(parents)) != 0 ) { 124 125 kret = IORegistryEntryGetParentIterator (service, kIOServicePlane, 126 &grandparents); 127 IOObjectRelease(service); 128 service = MACH_PORT_NULL; 129 130 if (kret) { 131 result = 6; 132 goto finish; 133 /* We'll never loop forever. */ 134 } 135 136 while ( (service2 = IOIteratorNext(grandparents)) != 0 ) { 137 138 if (content) { 139 CFRelease(content); 140 content = NULL; 141 } 142 143 if (!IOObjectConformsTo(service2, "IOMedia")) { 144 IOObjectRelease(service2); 145 service2 = MACH_PORT_NULL; 146 continue; 147 } 148 149 content = (CFStringRef) 150 IORegistryEntryCreateCFProperty(service2, 151 CFSTR(kIOMediaContentKey), 152 kCFAllocatorDefault, 0); 153 154 155 if(CFGetTypeID(content) != CFStringGetTypeID()) { 156 result = 2; 157 goto finish; 158 } 159 160 if(CFStringCompare(content, CFSTR("Apple_partition_scheme"), 0) 161 == kCFCompareEqualTo) { 162 if(partitionType) *partitionType = kBLPartitionType_APM; 163 } else if(CFStringCompare(content, CFSTR("FDisk_partition_scheme"), 0) 164 == kCFCompareEqualTo) { 165 if(partitionType) *partitionType = kBLPartitionType_MBR; 166 } else if(CFStringCompare(content, CFSTR("GUID_partition_scheme"), 0) 167 == kCFCompareEqualTo) { 168 if(partitionType) *partitionType = kBLPartitionType_GPT; 169 } else { 170 IOObjectRelease(service2); 171 service2 = MACH_PORT_NULL; 172 CFRelease(content); 173 content = NULL; 174 continue; 175 } 176 177 CFRelease(content); 178 179 content = IORegistryEntryCreateCFProperty(service2, CFSTR(kIOBSDNameKey), 180 kCFAllocatorDefault, 0); 181 182 if(CFGetTypeID(content) != CFStringGetTypeID()) { 183 result = 3; 184 goto finish; 185 } 186 187 if(!CFStringGetCString(content, par, MNAMELEN, kCFStringEncodingASCII)) { 188 result = 4; 189 goto finish; 190 } 191 192 CFRelease(content); 193 content = NULL; 194 195 sprintf(parentDev, "/dev/%s",par); 196 break; 197 } 198 199 if(parentDev[0] == '\0') { 200 break; 201 } 202 } 203 204 if(parentDev[0] == '\0') { 205 // nothing found 206 result = 8; 207 goto finish; 208 } 209 210finish: 211 if (services != MACH_PORT_NULL) IOObjectRelease(services); 212 if (parents != MACH_PORT_NULL) IOObjectRelease(parents); 213 if (service != MACH_PORT_NULL) IOObjectRelease(service); 214 if (grandparents != MACH_PORT_NULL) IOObjectRelease(grandparents); 215 if (service2 != MACH_PORT_NULL) IOObjectRelease(service2); 216 if (obj != MACH_PORT_NULL) IOObjectRelease(obj); 217 if (pn) CFRelease(pn); 218 if (content) CFRelease(content); 219 220 return result; 221} 222