2  * Copyright (c) 1998-2008 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  28 #include <IOKit/IOBSD.h> 
  29 #include <IOKit/IOLib.h> 
  30 #include <IOKit/IOService.h> 
  31 #include <IOKit/IODeviceTreeSupport.h> 
  32 #include <IOKit/IOKitKeys.h> 
  33 #include <IOKit/IOPlatformExpert.h> 
  37 #include <pexpert/pexpert.h> 
  38 #include <kern/clock.h> 
  39 #include <uuid/uuid.h> 
  41 // how long to wait for matching root device, secs 
  43 #define ROOTDEVICETIMEOUT       120 
  45 #define ROOTDEVICETIMEOUT       60 
  48 extern dev_t 
mdevadd(int devid
, ppnum_t base
, unsigned int size
, int phys
); 
  49 extern dev_t 
mdevlookup(int devid
); 
  50 extern void mdevremoveall(void); 
  55     IOService::publishResource("IOBSD"); 
  57     return( kIOReturnSuccess 
); 
  60 OSDictionary 
* IOBSDNameMatching( const char * name 
) 
  63     const OSSymbol 
*    str 
= 0; 
  67         dict 
= IOService::serviceMatching( gIOServiceKey 
); 
  70         str 
= OSSymbol::withCString( name 
); 
  73         dict
->setObject( kIOBSDNameKey
, (OSObject 
*) str 
); 
  88 OSDictionary 
* IOUUIDMatching( void ) 
  90     return IOService::resourceMatching( "boot-uuid-media" ); 
  94 OSDictionary 
* IOCDMatching( void ) 
  99     dict 
= IOService::serviceMatching( "IOMedia" ); 
 101         IOLog("Unable to find IOMedia\n"); 
 105     str 
= OSSymbol::withCString( "CD_ROM_Mode_1" ); 
 111     dict
->setObject( "Content Hint", (OSObject 
*)str 
); 
 116 OSDictionary 
* IONetworkMatching(  const char * path
, 
 117                                    char * buf
, int maxLen 
) 
 119     OSDictionary 
*      matching 
= 0; 
 128         len 
= strlen( kIODeviceTreePlane 
":" ); 
 133         strlcpy( buf
, kIODeviceTreePlane 
":", len 
+ 1 ); 
 136         // remove parameters following ':' from the path 
 137         skip 
= strchr( path
, ':'); 
 145         strlcpy( comp
, path
, len 
+ 1 ); 
 147         matching 
= IOService::serviceMatching( "IONetworkInterface" ); 
 150         dict 
= IOService::addLocation( matching 
); 
 154         str 
= OSString::withCString( buf 
); 
 157         dict
->setObject( kIOPathMatchKey
, str 
); 
 170 OSDictionary 
* IONetworkNamePrefixMatching( const char * prefix 
) 
 172     OSDictionary 
*       matching
; 
 173     OSDictionary 
*   propDict 
= 0; 
 174     const OSSymbol 
* str      
= 0; 
 175         char networkType
[128]; 
 178         matching 
= IOService::serviceMatching( "IONetworkInterface" ); 
 182         propDict 
= OSDictionary::withCapacity(1); 
 186         str 
= OSSymbol::withCString( prefix 
); 
 190         propDict
->setObject( "IOInterfaceNamePrefix", (OSObject 
*) str 
); 
 194                 // see if we're contrained to netroot off of specific network type 
 195                 if(PE_parse_boot_argn( "network-type", networkType
, 128 )) 
 197                         str 
= OSSymbol::withCString( networkType 
); 
 200                                 propDict
->setObject( "IONetworkRootType", str
); 
 206         if ( matching
->setObject( gIOPropertyMatchKey
, 
 207                                   (OSObject 
*) propDict 
) != true ) 
 217     if ( matching 
) matching
->release(); 
 218     if ( propDict 
) propDict
->release(); 
 219     if ( str      
) str
->release(); 
 224 static bool IORegisterNetworkInterface( IOService 
* netif 
) 
 226     // A network interface is typically named and registered 
 227     // with BSD after receiving a request from a user space 
 228     // "namer". However, for cases when the system needs to 
 229     // root from the network, this registration task must be 
 230     // done inside the kernel and completed before the root 
 231     // device is handed to BSD. 
 236     OSDictionary 
* dict    
= 0; 
 239     enum { kMaxPathLen 
= 512 }; 
 242         stack 
= IOService::waitForService( 
 243                 IOService::serviceMatching("IONetworkStack") ); 
 244         if ( stack 
== 0 ) break; 
 246         dict 
= OSDictionary::withCapacity(3); 
 247         if ( dict 
== 0 ) break; 
 249         zero 
= OSNumber::withNumber((UInt64
) 0, 32); 
 250         if ( zero 
== 0 ) break; 
 252         pathBuf 
= (char *) IOMalloc( kMaxPathLen 
); 
 253         if ( pathBuf 
== 0 ) break; 
 256         if ( netif
->getPath( pathBuf
, &len
, gIOServicePlane 
) 
 259         path 
= OSString::withCStringNoCopy( pathBuf 
); 
 260         if ( path 
== 0 ) break; 
 262         dict
->setObject( "IOInterfaceUnit", zero 
); 
 263         dict
->setObject( kIOPathMatchKey
,   path 
); 
 265         stack
->setProperties( dict 
); 
 269     if ( zero 
) zero
->release(); 
 270     if ( path 
) path
->release(); 
 271     if ( dict 
) dict
->release(); 
 272     if ( pathBuf 
) IOFree(pathBuf
, kMaxPathLen
); 
 274         return ( netif
->getProperty( kIOBSDNameKey 
) != 0 ); 
 277 OSDictionary 
* IODiskMatching( const char * path
, char * buf
, int maxLen 
) 
 288     // scan the tail of the path for "@unit:partition" 
 290         // Have to get the full path to the controller - an alias may 
 291         // tell us next to nothing, like "hd:8" 
 292         alias 
= IORegistryEntry::dealiasPath( &path
, gIODTPlane 
); 
 294         look 
= path 
+ strlen( path
); 
 296         while( look 
!= path
) { 
 297             if( *(--look
) == c
) { 
 299                     partition 
= strtol( look 
+ 1, 0, 0 ); 
 301                 } else if( c 
== '@') { 
 302                     unit 
= strtol( look 
+ 1, &comp
, 16 ); 
 305                         lun 
= strtol( comp 
+ 1, 0, 16 ); 
 309                 } else if( c 
== '/') { 
 315                 if( alias 
&& (look 
== path
)) { 
 317                 look 
= path 
+ strlen( path
); 
 321         if( c 
|| unit 
== -1 || partition 
== -1) 
 324         len 
= strlen( "{" kIOPathMatchKey 
"='" kIODeviceTreePlane 
":" ); 
 329         snprintf( buf
, len 
+ 1, "{" kIOPathMatchKey 
"='" kIODeviceTreePlane 
":" ); 
 333             len 
= strlen( alias 
); 
 338             strlcpy( comp
, alias
, len 
+ 1 ); 
 342         if ( (look 
- path
)) { 
 348             strlcpy( comp
, path
, len 
+ 1 ); 
 354             len 
= strlen( "/@hhhhhhhh,hhhhhhhh:dddddddddd';}" ); 
 359             snprintf( comp
, len 
+ 1, "/@%lx,%lx:%ld';}", unit
, lun
, partition 
); 
 363             len 
= strlen( "/@hhhhhhhh:dddddddddd';}" ); 
 368             snprintf( comp
, len 
+ 1, "/@%lx:%ld';}", unit
, partition 
); 
 371         return( OSDynamicCast(OSDictionary
, OSUnserialize( buf
, 0 )) ); 
 378 OSDictionary 
* IOOFPathMatching( const char * path
, char * buf
, int maxLen 
) 
 380     OSDictionary 
*      matching
; 
 385     /* need to look up path, get device type, 
 386         call matching help based on device type */ 
 388     matching 
= IODiskMatching( path
, buf
, maxLen 
); 
 394         len 
= strlen( kIODeviceTreePlane 
":" ); 
 399         strlcpy( buf
, kIODeviceTreePlane 
":", len 
+ 1 ); 
 402         len 
= strlen( path 
); 
 406         strlcpy( comp
, path
, len 
+ 1 ); 
 408         matching 
= OSDictionary::withCapacity( 1 ); 
 412         str 
= OSString::withCString( buf 
); 
 415         matching
->setObject( kIOPathMatchKey
, str 
); 
 428 IOService 
* IOFindMatchingChild( IOService 
* service 
) 
 430     // find a matching child service 
 431     IOService 
* child 
= 0; 
 432     OSIterator 
* iter 
= service
->getClientIterator(); 
 434         while( ( child 
= (IOService 
*) iter
->getNextObject() ) ) { 
 435             OSDictionary 
* dict 
= OSDictionary::withCapacity( 1 ); 
 440             const OSSymbol 
* str 
= OSSymbol::withCString( "Apple_HFS" ); 
 446             dict
->setObject( "Content", (OSObject 
*)str 
); 
 448             if ( child
->compareProperty( dict
, "Content" ) ) { 
 453             IOService 
* subchild 
= IOFindMatchingChild( child 
); 
 464 static int didRam 
= 0; 
 466 kern_return_t 
IOFindBSDRoot( char * rootName
, unsigned int rootNameSize
, 
 467                                 dev_t 
* root
, u_int32_t 
* oflags 
) 
 471     IORegistryEntry 
*   regEntry
; 
 472     OSDictionary 
*      matching 
= 0; 
 476     UInt32              
*ramdParms 
= 0; 
 480     bool                findHFSChild 
= false; 
 481     char *              mediaProperty 
= 0; 
 483     enum {              kMaxPathBuf 
= 512, kMaxBootVar 
= 128 }; 
 485     const char *        look 
= 0; 
 487     bool                forceNet 
= false; 
 488     bool                debugInfoPrintedOnce 
= false; 
 489     const char *        uuidStr 
= NULL
; 
 491     static int          mountAttempts 
= 0; 
 499     str 
= (char *) IOMalloc( kMaxPathBuf 
+ kMaxBootVar 
); 
 501         return( kIOReturnNoMemory 
); 
 502     rdBootVar 
= str 
+ kMaxPathBuf
; 
 504     if (!PE_parse_boot_argn("rd", rdBootVar
, kMaxBootVar 
) 
 505      && !PE_parse_boot_argn("rootdev", rdBootVar
, kMaxBootVar 
)) 
 509         if( (regEntry 
= IORegistryEntry::fromPath( "/chosen", gIODTPlane 
))) { 
 510             data 
= OSDynamicCast(OSData
, regEntry
->getProperty( "root-matching" )); 
 512                matching 
= OSDynamicCast(OSDictionary
, OSUnserializeXML((char *)data
->getBytesNoCopy())); 
 518             data 
= (OSData 
*) regEntry
->getProperty( "boot-uuid" ); 
 520                 uuidStr 
= (const char*)data
->getBytesNoCopy(); 
 521                 OSString 
*uuidString 
= OSString::withCString( uuidStr 
); 
 523                 // match the boot-args boot-uuid processing below 
 525                     IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr
); 
 526                     IOService::publishResource( "boot-uuid", uuidString 
); 
 527                     uuidString
->release(); 
 528                     matching 
= IOUUIDMatching(); 
 529                     mediaProperty 
= "boot-uuid-media"; 
 537             // else try for an OF Path 
 538             data 
= (OSData 
*) regEntry
->getProperty( "rootpath" ); 
 542         if( (regEntry 
= IORegistryEntry::fromPath( "/options", gIODTPlane 
))) { 
 543             data 
= (OSData 
*) regEntry
->getProperty( "boot-file" ); 
 549     if( data 
&& !uuidStr
) 
 550         look 
= (const char *) data
->getBytesNoCopy(); 
 552     if( rdBootVar
[0] == '*') { 
 553         look 
= rdBootVar 
+ 1; 
 556         if( (regEntry 
= IORegistryEntry::fromPath( "/", gIODTPlane 
))) { 
 557             forceNet 
= (0 != regEntry
->getProperty( "net-boot" )); 
 565 //      See if we have a RAMDisk property in /chosen/memory-map.  If so, make it into a device. 
 566 //      It will become /dev/mdx, where x is 0-f.  
 569         if(!didRam
) {                                                                                           /* Have we already build this ram disk? */ 
 570                 didRam 
= 1;                                                                                             /* Remember we did this */ 
 571                 if((regEntry 
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane 
))) {        /* Find the map node */ 
 572                         data 
= (OSData 
*)regEntry
->getProperty("RAMDisk");      /* Find the ram disk, if there */ 
 573                         if(data
) {                                                                                      /* We found one */ 
 575                                 ramdParms 
= (UInt32 
*)data
->getBytesNoCopy();   /* Point to the ram disk base and size */ 
 576                                 (void)mdevadd(-1, ml_static_ptovirt(ramdParms
[0]) >> 12, ramdParms
[1] >> 12, 0);        /* Initialize it and pass back the device number */ 
 578                         regEntry
->release();                                                            /* Toss the entry */ 
 583 //      Now check if we are trying to root on a memory device 
 586         if((rdBootVar
[0] == 'm') && (rdBootVar
[1] == 'd') && (rdBootVar
[3] == 0)) { 
 587                 dchar 
= xchar 
= rdBootVar
[2];                                                   /* Get the actual device */ 
 588                 if((xchar 
>= '0') && (xchar 
<= '9')) xchar 
= xchar 
- '0';       /* If digit, convert */ 
 590                         xchar 
= xchar 
& ~' ';                                                           /* Fold to upper case */ 
 591                         if((xchar 
>= 'A') && (xchar 
<= 'F')) {                          /* Is this a valid digit? */ 
 592                                 xchar 
= (xchar 
& 0xF) + 9;                                              /* Convert the hex digit */ 
 593                                 dchar 
= dchar 
| ' ';                                                    /* Fold to lower case */ 
 595                         else xchar 
= -1;                                                                        /* Show bogus */ 
 597                 if(xchar 
>= 0) {                                                                                /* Do we have a valid memory device name? */ 
 598                         *root 
= mdevlookup(xchar
);                                                      /* Find the device number */ 
 599                         if(*root 
>= 0) {                                                                        /* Did we find one? */ 
 601                                 rootName
[0] = 'm';                                                              /* Build root name */ 
 602                                 rootName
[1] = 'd';                                                              /* Build root name */ 
 603                                 rootName
[2] = dchar
;                                                    /* Build root name */ 
 604                                 rootName
[3] = 0;                                                                /* Build root name */ 
 605                                 IOLog("BSD root: %s, major %d, minor %d\n", rootName
, major(*root
), minor(*root
)); 
 606                                 *oflags 
= 0;                                                                    /* Show that this is not network */ 
 607                                 goto iofrootx
;                                                                  /* Join common exit... */ 
 609                         panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar
); /* Not there */ 
 614         // from OpenFirmware path 
 615         IOLog("From path: \"%s\", ", look
); 
 618             if( forceNet 
|| (0 == strncmp( look
, "enet", strlen( "enet" ))) ) { 
 619                 matching 
= IONetworkMatching( look
, str
, kMaxPathBuf 
); 
 621                 matching 
= IODiskMatching( look
, str
, kMaxPathBuf 
); 
 626       if( (!matching
) && rdBootVar
[0] ) { 
 632         if ( strncmp( look
, "en", strlen( "en" )) == 0 ) { 
 633             matching 
= IONetworkNamePrefixMatching( "en" ); 
 634         } else if ( strncmp( look
, "cdrom", strlen( "cdrom" )) == 0 ) { 
 635             matching 
= IOCDMatching(); 
 637         } else if ( strncmp( look
, "uuid", strlen( "uuid" )) == 0 ) { 
 639             OSString 
*uuidString
; 
 641             uuid 
= (char *)IOMalloc( kMaxBootVar 
); 
 644                 if (!PE_parse_boot_argn( "boot-uuid", uuid
, kMaxBootVar 
)) { 
 645                     panic( "rd=uuid but no boot-uuid=<value> specified" );  
 647                 uuidString 
= OSString::withCString( uuid 
); 
 649                     IOService::publishResource( "boot-uuid", uuidString 
); 
 650                     uuidString
->release(); 
 651                     IOLog( "\nWaiting for boot volume with UUID %s\n", uuid 
); 
 652                     matching 
= IOUUIDMatching(); 
 653                     mediaProperty 
= "boot-uuid-media"; 
 655                 IOFree( uuid
, kMaxBootVar 
); 
 658             matching 
= IOBSDNameMatching( look 
); 
 664         // Match any HFS media 
 666         matching 
= IOService::serviceMatching( "IOMedia" ); 
 667         astring 
= OSString::withCStringNoCopy("Apple_HFS"); 
 669             matching
->setObject("Content", astring
); 
 674     if( true && matching
) { 
 675         OSSerialize 
* s 
= OSSerialize::withCapacity( 5 ); 
 677         if( matching
->serialize( s 
)) { 
 678             IOLog( "Waiting on %s\n", s
->text() ); 
 684         t
.tv_sec 
= ROOTDEVICETIMEOUT
; 
 687         service 
= IOService::waitForService( matching
, &t 
); 
 688         if( (!service
) || (mountAttempts 
== 10)) { 
 689             PE_display_icon( 0, "noroot"); 
 690             IOLog( "Still waiting for root device\n" ); 
 692             if( !debugInfoPrintedOnce
) { 
 693                 debugInfoPrintedOnce 
= true; 
 694                 if( gIOKitDebug 
& kIOLogDTree
) { 
 695                     IOLog("\nDT plane:\n"); 
 696                     IOPrintPlane( gIODTPlane 
); 
 698                 if( gIOKitDebug 
& kIOLogServiceTree
) { 
 699                     IOLog("\nService plane:\n"); 
 700                     IOPrintPlane( gIOServicePlane 
); 
 702                 if( gIOKitDebug 
& kIOLogMemory
) 
 709     if ( service 
&& findHFSChild 
) { 
 713         // wait for children services to finish registering 
 715             timeoutNS 
= ROOTDEVICETIMEOUT
; 
 716             timeoutNS 
*= kSecondScale
; 
 718             if ( (service
->waitQuiet(timeoutNS
) ) == kIOReturnSuccess
) { 
 721                 IOLog( "Waiting for child registration\n" ); 
 724         // look for a subservice with an Apple_HFS child 
 725         IOService 
* subservice 
= IOFindMatchingChild( service 
); 
 726         if ( subservice 
) service 
= subservice
; 
 727     } else if ( service 
&& mediaProperty 
) { 
 728         service 
= (IOService 
*)service
->getProperty(mediaProperty
); 
 734     // If the IOService we matched to is a subclass of IONetworkInterface, 
 735     // then make sure it has been registered with BSD and has a BSD name 
 739     &&   service
->metaCast( "IONetworkInterface" ) 
 740     &&   !IORegisterNetworkInterface( service 
) ) 
 748         service
->getPath( str
, &len
, gIOServicePlane 
); 
 749         IOLog( "Got boot device = %s\n", str 
); 
 751         iostr 
= (OSString 
*) service
->getProperty( kIOBSDNameKey 
); 
 753             strlcpy( rootName
, iostr
->getCStringNoCopy(), rootNameSize 
); 
 754         off 
= (OSNumber 
*) service
->getProperty( kIOBSDMajorKey 
); 
 756             mjr 
= off
->unsigned32BitValue(); 
 757         off 
= (OSNumber 
*) service
->getProperty( kIOBSDMinorKey 
); 
 759             mnr 
= off
->unsigned32BitValue(); 
 761         if( service
->metaCast( "IONetworkInterface" )) 
 766         IOLog( "Wait for root failed\n" ); 
 767         strlcpy( rootName
, "en0", rootNameSize 
); 
 771     IOLog( "BSD root: %s", rootName 
); 
 773         IOLog(", major %d, minor %d\n", mjr
, mnr 
); 
 777     *root 
= makedev( mjr
, mnr 
); 
 780     IOFree( str
,  kMaxPathBuf 
+ kMaxBootVar 
); 
 783     if( (gIOKitDebug 
& (kIOLogDTree 
| kIOLogServiceTree 
| kIOLogMemory
)) && !debugInfoPrintedOnce
) { 
 785         IOService::getPlatform()->waitQuiet(); 
 786         if( gIOKitDebug 
& kIOLogDTree
) { 
 787             IOLog("\nDT plane:\n"); 
 788             IOPrintPlane( gIODTPlane 
); 
 790         if( gIOKitDebug 
& kIOLogServiceTree
) { 
 791             IOLog("\nService plane:\n"); 
 792             IOPrintPlane( gIOServicePlane 
); 
 794         if( gIOKitDebug 
& kIOLogMemory
) 
 798     return( kIOReturnSuccess 
); 
 801 void IOSecureBSDRoot(const char * rootName
) 
 805     IOPlatformExpert 
*pe
; 
 806     const OSSymbol   
*functionName 
= OSSymbol::withCStringNoCopy("SecureRootName"); 
 808     while ((pe 
= IOService::getPlatform()) == 0) IOSleep(1 * 1000); 
 810     // Returns kIOReturnNotPrivileged is the root device is not secure. 
 811     // Returns kIOReturnUnsupported if "SecureRootName" is not implemented. 
 812     result 
= pe
->callPlatformFunction(functionName
, false, (void *)rootName
, (void *)0, (void *)0, (void *)0); 
 814     functionName
->release(); 
 816     if (result 
== kIOReturnNotPrivileged
) mdevremoveall(); 
 821 IOBSDRegistryEntryForDeviceTree(char * path
) 
 823     return (IORegistryEntry::fromPath(path
, gIODTPlane
)); 
 827 IOBSDRegistryEntryRelease(void * entry
) 
 829     IORegistryEntry 
* regEntry 
= (IORegistryEntry 
*)entry
; 
 837 IOBSDRegistryEntryGetData(void * entry
, char * property_name
,  
 841     IORegistryEntry 
*   regEntry 
= (IORegistryEntry 
*)entry
; 
 843     data 
= (OSData 
*) regEntry
->getProperty(property_name
); 
 845         *packet_length 
= data
->getLength(); 
 846         return (data
->getBytesNoCopy()); 
 851 kern_return_t 
IOBSDGetPlatformUUID( uuid_t uuid
, mach_timespec_t timeout 
) 
 853     IOService 
* resources
; 
 856     resources 
= IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey 
), &timeout 
); 
 857     if ( resources 
== 0 ) return KERN_OPERATION_TIMED_OUT
; 
 859     string 
= ( OSString 
* ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey 
); 
 860     if ( string 
== 0 ) return KERN_NOT_SUPPORTED
; 
 862     uuid_parse( string
->getCStringNoCopy( ), uuid 
); 
 867 kern_return_t 
IOBSDGetPlatformSerialNumber( char *serial_number_str
, u_int32_t len 
) 
 869     OSDictionary 
* platform_dict
; 
 876     serial_number_str
[0] = '\0'; 
 878     platform_dict 
= IOService::serviceMatching( "IOPlatformExpertDevice" ); 
 879     if (platform_dict 
== NULL
) { 
 880             return KERN_NOT_SUPPORTED
; 
 883     platform 
= IOService::waitForService( platform_dict 
); 
 885             string 
= ( OSString 
* ) platform
->getProperty( kIOPlatformSerialNumberKey 
); 
 887                     return KERN_NOT_SUPPORTED
; 
 889                     strlcpy( serial_number_str
, string
->getCStringNoCopy( ), len 
); 
 896 dev_t 
IOBSDGetMediaWithUUID( const char *uuid_cstring
, char *bsd_name
, int bsd_name_len
, int timeout
) 
 899     OSDictionary 
*dictionary
; 
 900     OSString 
*uuid_string
; 
 902     if (bsd_name_len 
< 1) { 
 907     dictionary 
= IOService::serviceMatching( "IOMedia" ); 
 909         uuid_string 
= OSString::withCString( uuid_cstring 
); 
 912             mach_timespec_t tv 
= { timeout
, 0 };    // wait up to "timeout" seconds for the device 
 914             dictionary
->setObject( "UUID", uuid_string 
); 
 915             dictionary
->retain(); 
 916             service 
= IOService::waitForService( dictionary
, &tv 
); 
 918                 OSNumber 
*dev_major 
= (OSNumber 
*) service
->getProperty( kIOBSDMajorKey 
); 
 919                 OSNumber 
*dev_minor 
= (OSNumber 
*) service
->getProperty( kIOBSDMinorKey 
); 
 920                 OSString 
*iostr 
= (OSString 
*) service
->getProperty( kIOBSDNameKey 
); 
 923                     strlcpy( bsd_name
, iostr
->getCStringNoCopy(), bsd_name_len 
); 
 925                 if ( dev_major 
&& dev_minor 
) 
 926                     dev 
= makedev( dev_major
->unsigned32BitValue(), dev_minor
->unsigned32BitValue() ); 
 928             uuid_string
->release(); 
 930         dictionary
->release(); 
 937 void IOBSDIterateMediaWithContent(const char *content_uuid_cstring
, int (*func
)(const char *bsd_dev_name
, const char *uuid_str
, void *arg
), void *arg
) 
 939     OSDictionary 
*dictionary
; 
 940     OSString 
*content_uuid_string
; 
 942     dictionary 
= IOService::serviceMatching( "IOMedia" ); 
 944         content_uuid_string 
= OSString::withCString( content_uuid_cstring 
); 
 945         if( content_uuid_string 
) { 
 949             dictionary
->setObject( "Content", content_uuid_string 
); 
 950             dictionary
->retain(); 
 952             iter 
= IOService::getMatchingServices(dictionary
); 
 953             while (iter 
&& (service 
= (IOService 
*)iter
->getNextObject())) { 
 955                             OSString 
*iostr 
= (OSString 
*) service
->getProperty( kIOBSDNameKey 
); 
 956                             OSString 
*uuidstr 
= (OSString 
*) service
->getProperty( "UUID" ); 
 961                                             uuid 
= uuidstr
->getCStringNoCopy(); 
 963                                             uuid 
= "00000000-0000-0000-0000-000000000000"; 
 967                                     if (func 
&& func(iostr
->getCStringNoCopy(), uuid
, arg
) == 0) { 
 976             content_uuid_string
->release(); 
 978         dictionary
->release(); 
 983 int IOBSDIsMediaEjectable( const char *cdev_name 
) 
 986     OSDictionary 
*dictionary
; 
 989     if (strncmp(cdev_name
, "/dev/", 5) == 0) { 
 993     dictionary 
= IOService::serviceMatching( "IOMedia" ); 
 995         dev_name 
= OSString::withCString( cdev_name 
); 
 998             mach_timespec_t tv 
= { 5, 0 };    // wait up to "timeout" seconds for the device 
1000             dictionary
->setObject( kIOBSDNameKey
, dev_name 
); 
1001             dictionary
->retain(); 
1002             service 
= IOService::waitForService( dictionary
, &tv 
); 
1004                 OSBoolean 
*ejectable 
= (OSBoolean 
*) service
->getProperty( "Ejectable" ); 
1007                         ret 
= (int)ejectable
->getValue(); 
1011             dev_name
->release(); 
1013         dictionary
->release();