1 /* 2 * Copyright (c) 1998-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 #include <IOKit/IOBSD.h> 29 #include <IOKit/IOLib.h> 30 #include <IOKit/IOService.h> 31 #include <IOKit/IOCatalogue.h> 32 #include <IOKit/IODeviceTreeSupport.h> 33 #include <IOKit/IOKitKeys.h> 34 #include <IOKit/IOPlatformExpert.h> 35 36 extern "C" { 37 38 #include <pexpert/pexpert.h> 39 #include <kern/clock.h> 40 #include <uuid/uuid.h> 41 42 // how long to wait for matching root device, secs 43 #if DEBUG 44 #define ROOTDEVICETIMEOUT 120 45 #else 46 #define ROOTDEVICETIMEOUT 60 47 #endif 48 49 extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys); 50 extern dev_t mdevlookup(int devid); 51 extern void mdevremoveall(void); 52 extern void di_root_ramfile(IORegistryEntry * entry); 53 54 kern_return_t 55 IOKitBSDInit( void ) 56 { 57 IOService::publishResource("IOBSD"); 58 59 return( kIOReturnSuccess ); 60 } 61 62 void 63 IOServicePublishResource( const char * property, boolean_t value ) 64 { 65 if ( value) 66 IOService::publishResource( property, kOSBooleanTrue ); 67 else 68 IOService::getResourceService()->removeProperty( property ); 69 } 70 71 boolean_t 72 IOServiceWaitForMatchingResource( const char * property, uint64_t timeout ) 73 { 74 OSDictionary * dict = 0; 75 IOService * match = 0; 76 boolean_t found = false; 77 78 do { 79 80 dict = IOService::resourceMatching( property ); 81 if( !dict) 82 continue; 83 match = IOService::waitForMatchingService( dict, timeout ); 84 if ( match) 85 found = true; 86 87 } while( false ); 88 89 if( dict) 90 dict->release(); 91 if( match) 92 match->release(); 93 94 return( found ); 95 } 96 97 boolean_t 98 IOCatalogueMatchingDriversPresent( const char * property ) 99 { 100 OSDictionary * dict = 0; 101 OSOrderedSet * set = 0; 102 SInt32 generationCount = 0; 103 boolean_t found = false; 104 105 do { 106 107 dict = OSDictionary::withCapacity(1); 108 if( !dict) 109 continue; 110 dict->setObject( property, kOSBooleanTrue ); 111 set = gIOCatalogue->findDrivers( dict, &generationCount ); 112 if ( set && (set->getCount() > 0)) 113 found = true; 114 115 } while( false ); 116 117 if( dict) 118 dict->release(); 119 if( set) 120 set->release(); 121 122 return( found ); 123 } 124 125 OSDictionary * IOBSDNameMatching( const char * name ) 126 { 127 OSDictionary * dict; 128 const OSSymbol * str = 0; 129 130 do { 131 132 dict = IOService::serviceMatching( gIOServiceKey ); 133 if( !dict) 134 continue; 135 str = OSSymbol::withCString( name ); 136 if( !str) 137 continue; 138 dict->setObject( kIOBSDNameKey, (OSObject *) str ); 139 str->release(); 140 141 return( dict ); 142 143 } while( false ); 144 145 if( dict) 146 dict->release(); 147 if( str) 148 str->release(); 149 150 return( 0 ); 151 } 152 153 OSDictionary * IOUUIDMatching( void ) 154 { 155 return IOService::resourceMatching( "boot-uuid-media" ); 156 } 157 158 OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) 159 { 160 OSDictionary * matching; 161 OSDictionary * propDict = 0; 162 const OSSymbol * str = 0; 163 char networkType[128]; 164 165 do { 166 matching = IOService::serviceMatching( "IONetworkInterface" ); 167 if ( matching == 0 ) 168 continue; 169 170 propDict = OSDictionary::withCapacity(1); 171 if ( propDict == 0 ) 172 continue; 173 174 str = OSSymbol::withCString( prefix ); 175 if ( str == 0 ) 176 continue; 177 178 propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str ); 179 str->release(); 180 str = 0; 181 182 // see if we're contrained to netroot off of specific network type 183 if(PE_parse_boot_argn( "network-type", networkType, 128 )) 184 { 185 str = OSSymbol::withCString( networkType ); 186 if(str) 187 { 188 propDict->setObject( "IONetworkRootType", str); 189 str->release(); 190 str = 0; 191 } 192 } 193 194 if ( matching->setObject( gIOPropertyMatchKey, 195 (OSObject *) propDict ) != true ) 196 continue; 197 198 propDict->release(); 199 propDict = 0; 200 201 return( matching ); 202 203 } while ( false ); 204 205 if ( matching ) matching->release(); 206 if ( propDict ) propDict->release(); 207 if ( str ) str->release(); 208 209 return( 0 ); 210 } 211 212 static bool IORegisterNetworkInterface( IOService * netif ) 213 { 214 // A network interface is typically named and registered 215 // with BSD after receiving a request from a user space 216 // "namer". However, for cases when the system needs to 217 // root from the network, this registration task must be 218 // done inside the kernel and completed before the root 219 // device is handed to BSD. 220 221 IOService * stack; 222 OSNumber * zero = 0; 223 OSString * path = 0; 224 OSDictionary * dict = 0; 225 char * pathBuf = 0; 226 int len; 227 enum { kMaxPathLen = 512 }; 228 229 do { 230 stack = IOService::waitForService( 231 IOService::serviceMatching("IONetworkStack") ); 232 if ( stack == 0 ) break; 233 234 dict = OSDictionary::withCapacity(3); 235 if ( dict == 0 ) break; 236 237 zero = OSNumber::withNumber((UInt64) 0, 32); 238 if ( zero == 0 ) break; 239 240 pathBuf = (char *) IOMalloc( kMaxPathLen ); 241 if ( pathBuf == 0 ) break; 242 243 len = kMaxPathLen; 244 if ( netif->getPath( pathBuf, &len, gIOServicePlane ) 245 == false ) break; 246 247 path = OSString::withCStringNoCopy( pathBuf ); 248 if ( path == 0 ) break; 249 250 dict->setObject( "IOInterfaceUnit", zero ); 251 dict->setObject( kIOPathMatchKey, path ); 252 253 stack->setProperties( dict ); 254 } 255 while ( false ); 256 257 if ( zero ) zero->release(); 258 if ( path ) path->release(); 259 if ( dict ) dict->release(); 260 if ( pathBuf ) IOFree(pathBuf, kMaxPathLen); 261 262 return ( netif->getProperty( kIOBSDNameKey ) != 0 ); 263 } 264 265 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen ) 266 { 267 OSDictionary * matching; 268 OSString * str; 269 char * comp; 270 int len; 271 272 do { 273 274 len = strlen( kIODeviceTreePlane ":" ); 275 maxLen -= len; 276 if( maxLen <= 0) 277 continue; 278 279 strlcpy( buf, kIODeviceTreePlane ":", len + 1 ); 280 comp = buf + len; 281 282 len = strlen( path ); 283 maxLen -= len; 284 if( maxLen <= 0) 285 continue; 286 strlcpy( comp, path, len + 1 ); 287 288 matching = OSDictionary::withCapacity( 1 ); 289 if( !matching) 290 continue; 291 292 str = OSString::withCString( buf ); 293 if( !str) 294 continue; 295 matching->setObject( kIOPathMatchKey, str ); 296 str->release(); 297 298 return( matching ); 299 300 } while( false ); 301 302 if( matching) 303 matching->release(); 304 305 return( 0 ); 306 } 307 308 static int didRam = 0; 309 310 kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize, 311 dev_t * root, u_int32_t * oflags ) 312 { 313 mach_timespec_t t; 314 IOService * service; 315 IORegistryEntry * regEntry; 316 OSDictionary * matching = 0; 317 OSString * iostr; 318 OSNumber * off; 319 OSData * data = 0; 320 321 UInt32 flags = 0; 322 int mnr, mjr; 323 const char * mediaProperty = 0; 324 char * rdBootVar; 325 enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; 326 char * str; 327 const char * look = 0; 328 int len; 329 bool debugInfoPrintedOnce = false; 330 const char * uuidStr = NULL; 331 332 static int mountAttempts = 0; 333 334 int xchar, dchar; 335 336 337 if( mountAttempts++) 338 IOSleep( 5 * 1000 ); 339 340 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar ); 341 if( !str) 342 return( kIOReturnNoMemory ); 343 rdBootVar = str + kMaxPathBuf; 344 345 if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) 346 && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) 347 rdBootVar[0] = 0; 348 349 do { 350 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { 351 di_root_ramfile(regEntry); 352 data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" )); 353 if (data) { 354 matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy())); 355 if (matching) { 356 continue; 357 } 358 } 359 360 data = (OSData *) regEntry->getProperty( "boot-uuid" ); 361 if( data) { 362 uuidStr = (const char*)data->getBytesNoCopy(); 363 OSString *uuidString = OSString::withCString( uuidStr ); 364 365 // match the boot-args boot-uuid processing below 366 if( uuidString) { 367 IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr); 368 IOService::publishResource( "boot-uuid", uuidString ); 369 uuidString->release(); 370 matching = IOUUIDMatching(); 371 mediaProperty = "boot-uuid-media"; 372 regEntry->release(); 373 continue; 374 } else { 375 uuidStr = NULL; 376 } 377 } 378 regEntry->release(); 379 } 380 } while( false ); 381 382 // 383 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device. 384 // It will become /dev/mdx, where x is 0-f. 385 // 386 387 if(!didRam) { /* Have we already build this ram disk? */ 388 didRam = 1; /* Remember we did this */ 389 if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) { /* Find the map node */ 390 data = (OSData *)regEntry->getProperty("RAMDisk"); /* Find the ram disk, if there */ 391 if(data) { /* We found one */ 392 UInt32 *ramdParms = 0; 393 ramdParms = (UInt32 *)data->getBytesNoCopy(); /* Point to the ram disk base and size */ 394 (void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */ 395 } 396 regEntry->release(); /* Toss the entry */ 397 } 398 } 399 400 // 401 // Now check if we are trying to root on a memory device 402 // 403 404 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { 405 dchar = xchar = rdBootVar[2]; /* Get the actual device */ 406 if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0'; /* If digit, convert */ 407 else { 408 xchar = xchar & ~' '; /* Fold to upper case */ 409 if((xchar >= 'A') && (xchar <= 'F')) { /* Is this a valid digit? */ 410 xchar = (xchar & 0xF) + 9; /* Convert the hex digit */ 411 dchar = dchar | ' '; /* Fold to lower case */ 412 } 413 else xchar = -1; /* Show bogus */ 414 } 415 if(xchar >= 0) { /* Do we have a valid memory device name? */ 416 *root = mdevlookup(xchar); /* Find the device number */ 417 if(*root >= 0) { /* Did we find one? */ 418 419 rootName[0] = 'm'; /* Build root name */ 420 rootName[1] = 'd'; /* Build root name */ 421 rootName[2] = dchar; /* Build root name */ 422 rootName[3] = 0; /* Build root name */ 423 IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root)); 424 *oflags = 0; /* Show that this is not network */ 425 goto iofrootx; /* Join common exit... */ 426 } 427 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar); /* Not there */ 428 } 429 } 430 431 if( (!matching) && rdBootVar[0] ) { 432 // by BSD name 433 look = rdBootVar; 434 if( look[0] == '*') 435 look++; 436 437 if ( strncmp( look, "en", strlen( "en" )) == 0 ) { 438 matching = IONetworkNamePrefixMatching( "en" ); 439 } else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) { 440 char *uuid; 441 OSString *uuidString; 442 443 uuid = (char *)IOMalloc( kMaxBootVar ); 444 445 if ( uuid ) { 446 if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) { 447 panic( "rd=uuid but no boot-uuid=<value> specified" ); 448 } 449 uuidString = OSString::withCString( uuid ); 450 if ( uuidString ) { 451 IOService::publishResource( "boot-uuid", uuidString ); 452 uuidString->release(); 453 IOLog( "\nWaiting for boot volume with UUID %s\n", uuid ); 454 matching = IOUUIDMatching(); 455 mediaProperty = "boot-uuid-media"; 456 } 457 IOFree( uuid, kMaxBootVar ); 458 } 459 } else { 460 matching = IOBSDNameMatching( look ); 461 } 462 } 463 464 if( !matching) { 465 OSString * astring; 466 // Match any HFS media 467 468 matching = IOService::serviceMatching( "IOMedia" ); 469 astring = OSString::withCStringNoCopy("Apple_HFS"); 470 if ( astring ) { 471 matching->setObject("Content", astring); 472 astring->release(); 473 } 474 } 475 476 if( true && matching) { 477 OSSerialize * s = OSSerialize::withCapacity( 5 ); 478 479 if( matching->serialize( s )) { 480 IOLog( "Waiting on %s\n", s->text() ); 481 s->release(); 482 } 483 } 484 485 do { 486 t.tv_sec = ROOTDEVICETIMEOUT; 487 t.tv_nsec = 0; 488 matching->retain(); 489 service = IOService::waitForService( matching, &t ); 490 if( (!service) || (mountAttempts == 10)) { 491 PE_display_icon( 0, "noroot"); 492 IOLog( "Still waiting for root device\n" ); 493 494 if( !debugInfoPrintedOnce) { 495 debugInfoPrintedOnce = true; 496 if( gIOKitDebug & kIOLogDTree) { 497 IOLog("\nDT plane:\n"); 498 IOPrintPlane( gIODTPlane ); 499 } 500 if( gIOKitDebug & kIOLogServiceTree) { 501 IOLog("\nService plane:\n"); 502 IOPrintPlane( gIOServicePlane ); 503 } 504 if( gIOKitDebug & kIOLogMemory) 505 IOPrintMemory(); 506 } 507 } 508 } while( !service); 509 matching->release(); 510 511 if ( service && mediaProperty ) { 512 service = (IOService *)service->getProperty(mediaProperty); 513 } 514 515 mjr = 0; 516 mnr = 0; 517 518 // If the IOService we matched to is a subclass of IONetworkInterface, 519 // then make sure it has been registered with BSD and has a BSD name 520 // assigned. 521 522 if ( service 523 && service->metaCast( "IONetworkInterface" ) 524 && !IORegisterNetworkInterface( service ) ) 525 { 526 service = 0; 527 } 528 529 if( service) { 530 531 len = kMaxPathBuf; 532 service->getPath( str, &len, gIOServicePlane ); 533 IOLog( "Got boot device = %s\n", str ); 534 535 iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 536 if( iostr) 537 strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize ); 538 off = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 539 if( off) 540 mjr = off->unsigned32BitValue(); 541 off = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 542 if( off) 543 mnr = off->unsigned32BitValue(); 544 545 if( service->metaCast( "IONetworkInterface" )) 546 flags |= 1; 547 548 } else { 549 550 IOLog( "Wait for root failed\n" ); 551 strlcpy( rootName, "en0", rootNameSize ); 552 flags |= 1; 553 } 554 555 IOLog( "BSD root: %s", rootName ); 556 if( mjr) 557 IOLog(", major %d, minor %d\n", mjr, mnr ); 558 else 559 IOLog("\n"); 560 561 *root = makedev( mjr, mnr ); 562 *oflags = flags; 563 564 IOFree( str, kMaxPathBuf + kMaxBootVar ); 565 566 iofrootx: 567 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) { 568 569 IOService::getPlatform()->waitQuiet(); 570 if( gIOKitDebug & kIOLogDTree) { 571 IOLog("\nDT plane:\n"); 572 IOPrintPlane( gIODTPlane ); 573 } 574 if( gIOKitDebug & kIOLogServiceTree) { 575 IOLog("\nService plane:\n"); 576 IOPrintPlane( gIOServicePlane ); 577 } 578 if( gIOKitDebug & kIOLogMemory) 579 IOPrintMemory(); 580 } 581 582 return( kIOReturnSuccess ); 583 } 584 585 void IOSecureBSDRoot(const char * rootName) 586 { 587 #if CONFIG_EMBEDDED 588 IOReturn result; 589 IOPlatformExpert *pe; 590 const OSSymbol *functionName = OSSymbol::withCStringNoCopy("SecureRootName"); 591 592 while ((pe = IOService::getPlatform()) == 0) IOSleep(1 * 1000); 593 594 // Returns kIOReturnNotPrivileged is the root device is not secure. 595 // Returns kIOReturnUnsupported if "SecureRootName" is not implemented. 596 result = pe->callPlatformFunction(functionName, false, (void *)rootName, (void *)0, (void *)0, (void *)0); 597 598 functionName->release(); 599 600 if (result == kIOReturnNotPrivileged) mdevremoveall(); 601 #endif 602 } 603 604 void * 605 IOBSDRegistryEntryForDeviceTree(char * path) 606 { 607 return (IORegistryEntry::fromPath(path, gIODTPlane)); 608 } 609 610 void 611 IOBSDRegistryEntryRelease(void * entry) 612 { 613 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 614 615 if (regEntry) 616 regEntry->release(); 617 return; 618 } 619 620 const void * 621 IOBSDRegistryEntryGetData(void * entry, char * property_name, 622 int * packet_length) 623 { 624 OSData * data; 625 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 626 627 data = (OSData *) regEntry->getProperty(property_name); 628 if (data) { 629 *packet_length = data->getLength(); 630 return (data->getBytesNoCopy()); 631 } 632 return (NULL); 633 } 634 635 kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout ) 636 { 637 IOService * resources; 638 OSString * string; 639 640 resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), ( timeout.tv_sec || timeout.tv_nsec ) ? &timeout : 0 ); 641 if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT; 642 643 string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey ); 644 if ( string == 0 ) return KERN_NOT_SUPPORTED; 645 646 uuid_parse( string->getCStringNoCopy( ), uuid ); 647 648 return KERN_SUCCESS; 649 } 650 651 kern_return_t IOBSDGetPlatformSerialNumber( char *serial_number_str, u_int32_t len ) 652 { 653 OSDictionary * platform_dict; 654 IOService *platform; 655 OSString * string; 656 657 if (len < 1) { 658 return 0; 659 } 660 serial_number_str[0] = '\0'; 661 662 platform_dict = IOService::serviceMatching( "IOPlatformExpertDevice" ); 663 if (platform_dict == NULL) { 664 return KERN_NOT_SUPPORTED; 665 } 666 667 platform = IOService::waitForService( platform_dict ); 668 if (platform) { 669 string = ( OSString * ) platform->getProperty( kIOPlatformSerialNumberKey ); 670 if ( string == 0 ) { 671 return KERN_NOT_SUPPORTED; 672 } else { 673 strlcpy( serial_number_str, string->getCStringNoCopy( ), len ); 674 } 675 } 676 677 return KERN_SUCCESS; 678 } 679 680 dev_t IOBSDGetMediaWithUUID( const char *uuid_cstring, char *bsd_name, int bsd_name_len, int timeout) 681 { 682 dev_t dev = 0; 683 OSDictionary *dictionary; 684 OSString *uuid_string; 685 686 if (bsd_name_len < 1) { 687 return 0; 688 } 689 bsd_name[0] = '\0'; 690 691 dictionary = IOService::serviceMatching( "IOMedia" ); 692 if( dictionary ) { 693 uuid_string = OSString::withCString( uuid_cstring ); 694 if( uuid_string ) { 695 IOService *service; 696 mach_timespec_t tv = { timeout, 0 }; // wait up to "timeout" seconds for the device 697 698 dictionary->setObject( "UUID", uuid_string ); 699 dictionary->retain(); 700 service = IOService::waitForService( dictionary, &tv ); 701 if( service ) { 702 OSNumber *dev_major = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 703 OSNumber *dev_minor = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 704 OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 705 706 if( iostr) 707 strlcpy( bsd_name, iostr->getCStringNoCopy(), bsd_name_len ); 708 709 if ( dev_major && dev_minor ) 710 dev = makedev( dev_major->unsigned32BitValue(), dev_minor->unsigned32BitValue() ); 711 } 712 uuid_string->release(); 713 } 714 dictionary->release(); 715 } 716 717 return dev; 718 } 719 720 721 void IOBSDIterateMediaWithContent(const char *content_uuid_cstring, int (*func)(const char *bsd_dev_name, const char *uuid_str, void *arg), void *arg) 722 { 723 OSDictionary *dictionary; 724 OSString *content_uuid_string; 725 726 dictionary = IOService::serviceMatching( "IOMedia" ); 727 if( dictionary ) { 728 content_uuid_string = OSString::withCString( content_uuid_cstring ); 729 if( content_uuid_string ) { 730 IOService *service; 731 OSIterator *iter; 732 733 dictionary->setObject( "Content", content_uuid_string ); 734 dictionary->retain(); 735 736 iter = IOService::getMatchingServices(dictionary); 737 while (iter && (service = (IOService *)iter->getNextObject())) { 738 if( service ) { 739 OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 740 OSString *uuidstr = (OSString *) service->getProperty( "UUID" ); 741 const char *uuid; 742 743 if( iostr) { 744 if (uuidstr) { 745 uuid = uuidstr->getCStringNoCopy(); 746 } else { 747 uuid = "00000000-0000-0000-0000-000000000000"; 748 } 749 750 // call the callback 751 if (func && func(iostr->getCStringNoCopy(), uuid, arg) == 0) { 752 break; 753 } 754 } 755 } 756 } 757 if (iter) 758 iter->release(); 759 760 content_uuid_string->release(); 761 } 762 dictionary->release(); 763 } 764 } 765 766 767 int IOBSDIsMediaEjectable( const char *cdev_name ) 768 { 769 int ret = 0; 770 OSDictionary *dictionary; 771 OSString *dev_name; 772 773 if (strncmp(cdev_name, "/dev/", 5) == 0) { 774 cdev_name += 5; 775 } 776 777 dictionary = IOService::serviceMatching( "IOMedia" ); 778 if( dictionary ) { 779 dev_name = OSString::withCString( cdev_name ); 780 if( dev_name ) { 781 IOService *service; 782 mach_timespec_t tv = { 5, 0 }; // wait up to "timeout" seconds for the device 783 784 dictionary->setObject( kIOBSDNameKey, dev_name ); 785 dictionary->retain(); 786 service = IOService::waitForService( dictionary, &tv ); 787 if( service ) { 788 OSBoolean *ejectable = (OSBoolean *) service->getProperty( "Ejectable" ); 789 790 if( ejectable ) { 791 ret = (int)ejectable->getValue(); 792 } 793 794 } 795 dev_name->release(); 796 } 797 dictionary->release(); 798 } 799 800 return ret; 801 } 802 803 } /* extern "C" */ 804