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 36extern "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 49extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys); 50extern dev_t mdevlookup(int devid); 51extern void mdevremoveall(void); 52extern void di_root_ramfile(IORegistryEntry * entry); 53 54kern_return_t 55IOKitBSDInit( void ) 56{ 57 IOService::publishResource("IOBSD"); 58 59 return( kIOReturnSuccess ); 60} 61 62void 63IOServicePublishResource( const char * property, boolean_t value ) 64{ 65 if ( value) 66 IOService::publishResource( property, kOSBooleanTrue ); 67 else 68 IOService::getResourceService()->removeProperty( property ); 69} 70 71boolean_t 72IOServiceWaitForMatchingResource( 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 97boolean_t 98IOCatalogueMatchingDriversPresent( 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 125OSDictionary * 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 153OSDictionary * IOUUIDMatching( void ) 154{ 155 return IOService::resourceMatching( "boot-uuid-media" ); 156} 157 158OSDictionary * 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 212static 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 265OSDictionary * 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 308static int didRam = 0; 309static int rootMountTries = 0; 310 311kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize, 312 dev_t * root, u_int32_t * oflags ) 313{ 314 mach_timespec_t t; 315 IOService * service; 316 IORegistryEntry * regEntry; 317 OSDictionary * matching = 0; 318 OSString * iostr; 319 OSNumber * off; 320 OSData * data = 0; 321 322 UInt32 flags = 0; 323 int mnr, mjr; 324 const char * mediaProperty = 0; 325 char * rdBootVar; 326 enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; 327 char * str; 328 const char * look = 0; 329 int len; 330 bool debugInfoPrintedOnce = false; 331 const char * uuidStr = NULL; 332 333 static int mountAttempts = 0; 334 335 int xchar, dchar; 336 337 338 if( mountAttempts++) 339 IOSleep( 5 * 1000 ); 340 341 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar ); 342 if( !str) 343 return( kIOReturnNoMemory ); 344 rdBootVar = str + kMaxPathBuf; 345 346 if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) 347 && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) 348 rdBootVar[0] = 0; 349 350 do { 351 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { 352 di_root_ramfile(regEntry); 353 data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" )); 354 if (data) { 355 matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy())); 356 if (matching) { 357 continue; 358 } 359 } 360 361 data = (OSData *) regEntry->getProperty( "boot-uuid" ); 362 if( data) { 363 uuidStr = (const char*)data->getBytesNoCopy(); 364 OSString *uuidString = OSString::withCString( uuidStr ); 365 366 // match the boot-args boot-uuid processing below 367 if( uuidString) { 368 IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr); 369 IOService::publishResource( "boot-uuid", uuidString ); 370 uuidString->release(); 371 matching = IOUUIDMatching(); 372 mediaProperty = "boot-uuid-media"; 373 regEntry->release(); 374 continue; 375 } else { 376 uuidStr = NULL; 377 } 378 } 379 regEntry->release(); 380 } 381 } while( false ); 382 383// 384// See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device. 385// It will become /dev/mdx, where x is 0-f. 386// 387 388 if(!didRam) { /* Have we already build this ram disk? */ 389 didRam = 1; /* Remember we did this */ 390 if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) { /* Find the map node */ 391 data = (OSData *)regEntry->getProperty("RAMDisk"); /* Find the ram disk, if there */ 392 if(data) { /* We found one */ 393 UInt32 *ramdParms = 0; 394 ramdParms = (UInt32 *)data->getBytesNoCopy(); /* Point to the ram disk base and size */ 395 (void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */ 396 } 397 regEntry->release(); /* Toss the entry */ 398 } 399 } 400 401// 402// Now check if we are trying to root on a memory device 403// 404 405 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { 406 dchar = xchar = rdBootVar[2]; /* Get the actual device */ 407 if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0'; /* If digit, convert */ 408 else { 409 xchar = xchar & ~' '; /* Fold to upper case */ 410 if((xchar >= 'A') && (xchar <= 'F')) { /* Is this a valid digit? */ 411 xchar = (xchar & 0xF) + 9; /* Convert the hex digit */ 412 dchar = dchar | ' '; /* Fold to lower case */ 413 } 414 else xchar = -1; /* Show bogus */ 415 } 416 if(xchar >= 0) { /* Do we have a valid memory device name? */ 417 *root = mdevlookup(xchar); /* Find the device number */ 418 if(*root >= 0) { /* Did we find one? */ 419 420 rootName[0] = 'm'; /* Build root name */ 421 rootName[1] = 'd'; /* Build root name */ 422 rootName[2] = dchar; /* Build root name */ 423 rootName[3] = 0; /* Build root name */ 424 IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root)); 425 *oflags = 0; /* Show that this is not network */ 426 goto iofrootx; /* Join common exit... */ 427 } 428 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar); /* Not there */ 429 } 430 } 431 432 if( (!matching) && rdBootVar[0] ) { 433 // by BSD name 434 look = rdBootVar; 435 if( look[0] == '*') 436 look++; 437 438 if ( strncmp( look, "en", strlen( "en" )) == 0 ) { 439 matching = IONetworkNamePrefixMatching( "en" ); 440 } else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) { 441 char *uuid; 442 OSString *uuidString; 443 444 uuid = (char *)IOMalloc( kMaxBootVar ); 445 446 if ( uuid ) { 447 if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) { 448 panic( "rd=uuid but no boot-uuid=<value> specified" ); 449 } 450 uuidString = OSString::withCString( uuid ); 451 if ( uuidString ) { 452 IOService::publishResource( "boot-uuid", uuidString ); 453 uuidString->release(); 454 IOLog( "\nWaiting for boot volume with UUID %s\n", uuid ); 455 matching = IOUUIDMatching(); 456 mediaProperty = "boot-uuid-media"; 457 } 458 IOFree( uuid, kMaxBootVar ); 459 } 460 } else { 461 matching = IOBSDNameMatching( look ); 462 } 463 } 464 465 if( !matching) { 466 OSString * astring; 467 // Match any HFS media 468 469 matching = IOService::serviceMatching( "IOMedia" ); 470 astring = OSString::withCStringNoCopy("Apple_HFS"); 471 if ( astring ) { 472 matching->setObject("Content", astring); 473 astring->release(); 474 } 475 } 476 477 if( true && matching) { 478 OSSerialize * s = OSSerialize::withCapacity( 5 ); 479 480 if( matching->serialize( s )) { 481 IOLog( "Waiting on %s\n", s->text() ); 482 s->release(); 483 } 484 } 485 486 do { 487 t.tv_sec = ROOTDEVICETIMEOUT; 488 t.tv_nsec = 0; 489 matching->retain(); 490 service = IOService::waitForService( matching, &t ); 491 rootMountTries++; 492 493 /* Give up after a while. */ 494 if(rootMountTries == 30) 495 panic("Gave up trying to mount root"); 496 497 if( (!service) || (mountAttempts == 10)) { 498 PE_display_icon( 0, "noroot"); 499 IOLog( "Still waiting for root device\n" ); 500 if( !debugInfoPrintedOnce) { 501 debugInfoPrintedOnce = true; 502 if( gIOKitDebug & kIOLogDTree) { 503 IOLog("\nDT plane:\n"); 504 IOPrintPlane( gIODTPlane ); 505 } 506 if( gIOKitDebug & kIOLogServiceTree) { 507 IOLog("\nService plane:\n"); 508 IOPrintPlane( gIOServicePlane ); 509 } 510 if( gIOKitDebug & kIOLogMemory) 511 IOPrintMemory(); 512 } 513 } 514 } while( !service); 515 matching->release(); 516 517 if ( service && mediaProperty ) { 518 service = (IOService *)service->getProperty(mediaProperty); 519 } 520 521 mjr = 0; 522 mnr = 0; 523 524 // If the IOService we matched to is a subclass of IONetworkInterface, 525 // then make sure it has been registered with BSD and has a BSD name 526 // assigned. 527 528 if ( service 529 && service->metaCast( "IONetworkInterface" ) 530 && !IORegisterNetworkInterface( service ) ) 531 { 532 service = 0; 533 } 534 535 if( service) { 536 537 len = kMaxPathBuf; 538 service->getPath( str, &len, gIOServicePlane ); 539 IOLog( "Got boot device = %s\n", str ); 540 541 iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 542 if( iostr) 543 strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize ); 544 off = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 545 if( off) 546 mjr = off->unsigned32BitValue(); 547 off = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 548 if( off) 549 mnr = off->unsigned32BitValue(); 550 551 if( service->metaCast( "IONetworkInterface" )) 552 flags |= 1; 553 554 } else { 555 556 IOLog( "Wait for root failed\n" ); 557 strlcpy( rootName, "en0", rootNameSize ); 558 flags |= 1; 559 } 560 561 IOLog( "BSD root: %s", rootName ); 562 if( mjr) 563 IOLog(", major %d, minor %d\n", mjr, mnr ); 564 else 565 IOLog("\n"); 566 567 *root = makedev( mjr, mnr ); 568 *oflags = flags; 569 570 IOFree( str, kMaxPathBuf + kMaxBootVar ); 571 572iofrootx: 573 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) { 574#if 0 575 IOService::getPlatform()->waitQuiet(); 576#endif 577 if( gIOKitDebug & kIOLogDTree) { 578 IOLog("\nDT plane:\n"); 579 IOPrintPlane( gIODTPlane ); 580 } 581 if( gIOKitDebug & kIOLogServiceTree) { 582 IOLog("\nService plane:\n"); 583 IOPrintPlane( gIOServicePlane ); 584 } 585 if( gIOKitDebug & kIOLogMemory) 586 IOPrintMemory(); 587 } 588 589 return( kIOReturnSuccess ); 590} 591 592void IOSecureBSDRoot(const char * rootName) 593{ 594#if CONFIG_EMBEDDED 595 IOReturn result; 596 IOPlatformExpert *pe; 597 const OSSymbol *functionName = OSSymbol::withCStringNoCopy("SecureRootName"); 598 599 while ((pe = IOService::getPlatform()) == 0) IOSleep(1 * 1000); 600 601 // Returns kIOReturnNotPrivileged is the root device is not secure. 602 // Returns kIOReturnUnsupported if "SecureRootName" is not implemented. 603 result = pe->callPlatformFunction(functionName, false, (void *)rootName, (void *)0, (void *)0, (void *)0); 604 605 functionName->release(); 606 607 if (result == kIOReturnNotPrivileged) mdevremoveall(); 608#endif 609} 610 611void * 612IOBSDRegistryEntryForDeviceTree(char * path) 613{ 614 return (IORegistryEntry::fromPath(path, gIODTPlane)); 615} 616 617void 618IOBSDRegistryEntryRelease(void * entry) 619{ 620 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 621 622 if (regEntry) 623 regEntry->release(); 624 return; 625} 626 627const void * 628IOBSDRegistryEntryGetData(void * entry, char * property_name, 629 int * packet_length) 630{ 631 OSData * data; 632 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 633 634 data = (OSData *) regEntry->getProperty(property_name); 635 if (data) { 636 *packet_length = data->getLength(); 637 return (data->getBytesNoCopy()); 638 } 639 return (NULL); 640} 641 642kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout ) 643{ 644 IOService * resources; 645 OSString * string; 646 647 resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), ( timeout.tv_sec || timeout.tv_nsec ) ? &timeout : 0 ); 648 if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT; 649 650 string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey ); 651 if ( string == 0 ) return KERN_NOT_SUPPORTED; 652 653 uuid_parse( string->getCStringNoCopy( ), uuid ); 654 655 return KERN_SUCCESS; 656} 657 658kern_return_t IOBSDGetPlatformSerialNumber( char *serial_number_str, u_int32_t len ) 659{ 660 OSDictionary * platform_dict; 661 IOService *platform; 662 OSString * string; 663 664 if (len < 1) { 665 return 0; 666 } 667 serial_number_str[0] = '\0'; 668 669 platform_dict = IOService::serviceMatching( "IOPlatformExpertDevice" ); 670 if (platform_dict == NULL) { 671 return KERN_NOT_SUPPORTED; 672 } 673 674 platform = IOService::waitForService( platform_dict ); 675 if (platform) { 676 string = ( OSString * ) platform->getProperty( kIOPlatformSerialNumberKey ); 677 if ( string == 0 ) { 678 return KERN_NOT_SUPPORTED; 679 } else { 680 strlcpy( serial_number_str, string->getCStringNoCopy( ), len ); 681 } 682 } 683 684 return KERN_SUCCESS; 685} 686 687dev_t IOBSDGetMediaWithUUID( const char *uuid_cstring, char *bsd_name, int bsd_name_len, int timeout) 688{ 689 dev_t dev = 0; 690 OSDictionary *dictionary; 691 OSString *uuid_string; 692 693 if (bsd_name_len < 1) { 694 return 0; 695 } 696 bsd_name[0] = '\0'; 697 698 dictionary = IOService::serviceMatching( "IOMedia" ); 699 if( dictionary ) { 700 uuid_string = OSString::withCString( uuid_cstring ); 701 if( uuid_string ) { 702 IOService *service; 703 mach_timespec_t tv = { timeout, 0 }; // wait up to "timeout" seconds for the device 704 705 dictionary->setObject( "UUID", uuid_string ); 706 dictionary->retain(); 707 service = IOService::waitForService( dictionary, &tv ); 708 if( service ) { 709 OSNumber *dev_major = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 710 OSNumber *dev_minor = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 711 OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 712 713 if( iostr) 714 strlcpy( bsd_name, iostr->getCStringNoCopy(), bsd_name_len ); 715 716 if ( dev_major && dev_minor ) 717 dev = makedev( dev_major->unsigned32BitValue(), dev_minor->unsigned32BitValue() ); 718 } 719 uuid_string->release(); 720 } 721 dictionary->release(); 722 } 723 724 return dev; 725} 726 727 728void IOBSDIterateMediaWithContent(const char *content_uuid_cstring, int (*func)(const char *bsd_dev_name, const char *uuid_str, void *arg), void *arg) 729{ 730 OSDictionary *dictionary; 731 OSString *content_uuid_string; 732 733 dictionary = IOService::serviceMatching( "IOMedia" ); 734 if( dictionary ) { 735 content_uuid_string = OSString::withCString( content_uuid_cstring ); 736 if( content_uuid_string ) { 737 IOService *service; 738 OSIterator *iter; 739 740 dictionary->setObject( "Content", content_uuid_string ); 741 dictionary->retain(); 742 743 iter = IOService::getMatchingServices(dictionary); 744 while (iter && (service = (IOService *)iter->getNextObject())) { 745 if( service ) { 746 OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 747 OSString *uuidstr = (OSString *) service->getProperty( "UUID" ); 748 const char *uuid; 749 750 if( iostr) { 751 if (uuidstr) { 752 uuid = uuidstr->getCStringNoCopy(); 753 } else { 754 uuid = "00000000-0000-0000-0000-000000000000"; 755 } 756 757 // call the callback 758 if (func && func(iostr->getCStringNoCopy(), uuid, arg) == 0) { 759 break; 760 } 761 } 762 } 763 } 764 if (iter) 765 iter->release(); 766 767 content_uuid_string->release(); 768 } 769 dictionary->release(); 770 } 771} 772 773 774int IOBSDIsMediaEjectable( const char *cdev_name ) 775{ 776 int ret = 0; 777 OSDictionary *dictionary; 778 OSString *dev_name; 779 780 if (strncmp(cdev_name, "/dev/", 5) == 0) { 781 cdev_name += 5; 782 } 783 784 dictionary = IOService::serviceMatching( "IOMedia" ); 785 if( dictionary ) { 786 dev_name = OSString::withCString( cdev_name ); 787 if( dev_name ) { 788 IOService *service; 789 mach_timespec_t tv = { 5, 0 }; // wait up to "timeout" seconds for the device 790 791 dictionary->setObject( kIOBSDNameKey, dev_name ); 792 dictionary->retain(); 793 service = IOService::waitForService( dictionary, &tv ); 794 if( service ) { 795 OSBoolean *ejectable = (OSBoolean *) service->getProperty( "Ejectable" ); 796 797 if( ejectable ) { 798 ret = (int)ejectable->getValue(); 799 } 800 801 } 802 dev_name->release(); 803 } 804 dictionary->release(); 805 } 806 807 return ret; 808} 809 810} /* extern "C" */ 811