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 #include <IOKit/IOUserClient.h> 36 37 extern "C" { 38 39 #include <pexpert/pexpert.h> 40 #include <kern/clock.h> 41 #include <uuid/uuid.h> 42 #include <sys/vnode_internal.h> 43 #include <sys/mount.h> 44 45 // how long to wait for matching root device, secs 46 #if DEBUG 47 #define ROOTDEVICETIMEOUT 120 48 #else 49 #define ROOTDEVICETIMEOUT 60 50 #endif 51 52 int panic_on_exception_triage = 0; 53 54 extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys); 55 extern dev_t mdevlookup(int devid); 56 extern void mdevremoveall(void); 57 extern void di_root_ramfile(IORegistryEntry * entry); 58 59 60 #if DEVELOPMENT 61 #define IOPOLLED_COREFILE 1 62 // no sizing 63 #define kIOCoreDumpSize 0ULL 64 #define kIOCoreDumpFreeSize 0ULL 65 #else 66 #define IOPOLLED_COREFILE 0 67 #endif 68 69 70 #if IOPOLLED_COREFILE 71 static bool 72 NewKernelCoreMedia(void * target, void * refCon, 73 IOService * newService, 74 IONotifier * notifier); 75 #endif /* IOPOLLED_COREFILE */ 76 77 78 kern_return_t 79 IOKitBSDInit( void ) 80 { 81 IOService::publishResource("IOBSD"); 82 83 return( kIOReturnSuccess ); 84 } 85 86 void 87 IOServicePublishResource( const char * property, boolean_t value ) 88 { 89 if ( value) 90 IOService::publishResource( property, kOSBooleanTrue ); 91 else 92 IOService::getResourceService()->removeProperty( property ); 93 } 94 95 boolean_t 96 IOServiceWaitForMatchingResource( const char * property, uint64_t timeout ) 97 { 98 OSDictionary * dict = 0; 99 IOService * match = 0; 100 boolean_t found = false; 101 102 do { 103 104 dict = IOService::resourceMatching( property ); 105 if( !dict) 106 continue; 107 match = IOService::waitForMatchingService( dict, timeout ); 108 if ( match) 109 found = true; 110 111 } while( false ); 112 113 if( dict) 114 dict->release(); 115 if( match) 116 match->release(); 117 118 return( found ); 119 } 120 121 boolean_t 122 IOCatalogueMatchingDriversPresent( const char * property ) 123 { 124 OSDictionary * dict = 0; 125 OSOrderedSet * set = 0; 126 SInt32 generationCount = 0; 127 boolean_t found = false; 128 129 do { 130 131 dict = OSDictionary::withCapacity(1); 132 if( !dict) 133 continue; 134 dict->setObject( property, kOSBooleanTrue ); 135 set = gIOCatalogue->findDrivers( dict, &generationCount ); 136 if ( set && (set->getCount() > 0)) 137 found = true; 138 139 } while( false ); 140 141 if( dict) 142 dict->release(); 143 if( set) 144 set->release(); 145 146 return( found ); 147 } 148 149 OSDictionary * IOBSDNameMatching( const char * name ) 150 { 151 OSDictionary * dict; 152 const OSSymbol * str = 0; 153 154 do { 155 156 dict = IOService::serviceMatching( gIOServiceKey ); 157 if( !dict) 158 continue; 159 str = OSSymbol::withCString( name ); 160 if( !str) 161 continue; 162 dict->setObject( kIOBSDNameKey, (OSObject *) str ); 163 str->release(); 164 165 return( dict ); 166 167 } while( false ); 168 169 if( dict) 170 dict->release(); 171 if( str) 172 str->release(); 173 174 return( 0 ); 175 } 176 177 OSDictionary * IOUUIDMatching( void ) 178 { 179 return IOService::resourceMatching( "boot-uuid-media" ); 180 } 181 182 OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) 183 { 184 OSDictionary * matching; 185 OSDictionary * propDict = 0; 186 const OSSymbol * str = 0; 187 char networkType[128]; 188 189 do { 190 matching = IOService::serviceMatching( "IONetworkInterface" ); 191 if ( matching == 0 ) 192 continue; 193 194 propDict = OSDictionary::withCapacity(1); 195 if ( propDict == 0 ) 196 continue; 197 198 str = OSSymbol::withCString( prefix ); 199 if ( str == 0 ) 200 continue; 201 202 propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str ); 203 str->release(); 204 str = 0; 205 206 // see if we're contrained to netroot off of specific network type 207 if(PE_parse_boot_argn( "network-type", networkType, 128 )) 208 { 209 str = OSSymbol::withCString( networkType ); 210 if(str) 211 { 212 propDict->setObject( "IONetworkRootType", str); 213 str->release(); 214 str = 0; 215 } 216 } 217 218 if ( matching->setObject( gIOPropertyMatchKey, 219 (OSObject *) propDict ) != true ) 220 continue; 221 222 propDict->release(); 223 propDict = 0; 224 225 return( matching ); 226 227 } while ( false ); 228 229 if ( matching ) matching->release(); 230 if ( propDict ) propDict->release(); 231 if ( str ) str->release(); 232 233 return( 0 ); 234 } 235 236 static bool IORegisterNetworkInterface( IOService * netif ) 237 { 238 // A network interface is typically named and registered 239 // with BSD after receiving a request from a user space 240 // "namer". However, for cases when the system needs to 241 // root from the network, this registration task must be 242 // done inside the kernel and completed before the root 243 // device is handed to BSD. 244 245 IOService * stack; 246 OSNumber * zero = 0; 247 OSString * path = 0; 248 OSDictionary * dict = 0; 249 char * pathBuf = 0; 250 int len; 251 enum { kMaxPathLen = 512 }; 252 253 do { 254 stack = IOService::waitForService( 255 IOService::serviceMatching("IONetworkStack") ); 256 if ( stack == 0 ) break; 257 258 dict = OSDictionary::withCapacity(3); 259 if ( dict == 0 ) break; 260 261 zero = OSNumber::withNumber((UInt64) 0, 32); 262 if ( zero == 0 ) break; 263 264 pathBuf = (char *) IOMalloc( kMaxPathLen ); 265 if ( pathBuf == 0 ) break; 266 267 len = kMaxPathLen; 268 if ( netif->getPath( pathBuf, &len, gIOServicePlane ) 269 == false ) break; 270 271 path = OSString::withCStringNoCopy( pathBuf ); 272 if ( path == 0 ) break; 273 274 dict->setObject( "IOInterfaceUnit", zero ); 275 dict->setObject( kIOPathMatchKey, path ); 276 277 stack->setProperties( dict ); 278 } 279 while ( false ); 280 281 if ( zero ) zero->release(); 282 if ( path ) path->release(); 283 if ( dict ) dict->release(); 284 if ( pathBuf ) IOFree(pathBuf, kMaxPathLen); 285 286 return ( netif->getProperty( kIOBSDNameKey ) != 0 ); 287 } 288 289 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen ) 290 { 291 OSDictionary * matching = NULL; 292 OSString * str; 293 char * comp; 294 int len; 295 296 do { 297 298 len = strlen( kIODeviceTreePlane ":" ); 299 maxLen -= len; 300 if( maxLen <= 0) 301 continue; 302 303 strlcpy( buf, kIODeviceTreePlane ":", len + 1 ); 304 comp = buf + len; 305 306 len = strlen( path ); 307 maxLen -= len; 308 if( maxLen <= 0) 309 continue; 310 strlcpy( comp, path, len + 1 ); 311 312 matching = OSDictionary::withCapacity( 1 ); 313 if( !matching) 314 continue; 315 316 str = OSString::withCString( buf ); 317 if( !str) 318 continue; 319 matching->setObject( kIOPathMatchKey, str ); 320 str->release(); 321 322 return( matching ); 323 324 } while( false ); 325 326 if( matching) 327 matching->release(); 328 329 return( 0 ); 330 } 331 332 static int didRam = 0; 333 enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; 334 335 kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize, 336 dev_t * root, u_int32_t * oflags ) 337 { 338 mach_timespec_t t; 339 IOService * service; 340 IORegistryEntry * regEntry; 341 OSDictionary * matching = 0; 342 OSString * iostr; 343 OSNumber * off; 344 OSData * data = 0; 345 346 UInt32 flags = 0; 347 int mnr, mjr; 348 const char * mediaProperty = 0; 349 char * rdBootVar; 350 char * str; 351 const char * look = 0; 352 int len; 353 bool debugInfoPrintedOnce = false; 354 const char * uuidStr = NULL; 355 356 static int mountAttempts = 0; 357 358 int xchar, dchar; 359 360 361 if( mountAttempts++) 362 IOSleep( 5 * 1000 ); 363 364 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar ); 365 if( !str) 366 return( kIOReturnNoMemory ); 367 rdBootVar = str + kMaxPathBuf; 368 369 if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) 370 && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) 371 rdBootVar[0] = 0; 372 373 do { 374 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { 375 di_root_ramfile(regEntry); 376 data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" )); 377 if (data) { 378 matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy())); 379 if (matching) { 380 continue; 381 } 382 } 383 384 data = (OSData *) regEntry->getProperty( "boot-uuid" ); 385 if( data) { 386 uuidStr = (const char*)data->getBytesNoCopy(); 387 OSString *uuidString = OSString::withCString( uuidStr ); 388 389 // match the boot-args boot-uuid processing below 390 if( uuidString) { 391 IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr); 392 IOService::publishResource( "boot-uuid", uuidString ); 393 uuidString->release(); 394 matching = IOUUIDMatching(); 395 mediaProperty = "boot-uuid-media"; 396 regEntry->release(); 397 continue; 398 } else { 399 uuidStr = NULL; 400 } 401 } 402 regEntry->release(); 403 } 404 } while( false ); 405 406 // 407 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device. 408 // It will become /dev/mdx, where x is 0-f. 409 // 410 411 if(!didRam) { /* Have we already build this ram disk? */ 412 didRam = 1; /* Remember we did this */ 413 if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) { /* Find the map node */ 414 data = (OSData *)regEntry->getProperty("RAMDisk"); /* Find the ram disk, if there */ 415 if(data) { /* We found one */ 416 uintptr_t *ramdParms; 417 ramdParms = (uintptr_t *)data->getBytesNoCopy(); /* Point to the ram disk base and size */ 418 (void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */ 419 } 420 regEntry->release(); /* Toss the entry */ 421 } 422 } 423 424 // 425 // Now check if we are trying to root on a memory device 426 // 427 428 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { 429 dchar = xchar = rdBootVar[2]; /* Get the actual device */ 430 if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0'; /* If digit, convert */ 431 else { 432 xchar = xchar & ~' '; /* Fold to upper case */ 433 if((xchar >= 'A') && (xchar <= 'F')) { /* Is this a valid digit? */ 434 xchar = (xchar & 0xF) + 9; /* Convert the hex digit */ 435 dchar = dchar | ' '; /* Fold to lower case */ 436 } 437 else xchar = -1; /* Show bogus */ 438 } 439 if(xchar >= 0) { /* Do we have a valid memory device name? */ 440 *root = mdevlookup(xchar); /* Find the device number */ 441 if(*root >= 0) { /* Did we find one? */ 442 443 rootName[0] = 'm'; /* Build root name */ 444 rootName[1] = 'd'; /* Build root name */ 445 rootName[2] = dchar; /* Build root name */ 446 rootName[3] = 0; /* Build root name */ 447 IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root)); 448 *oflags = 0; /* Show that this is not network */ 449 goto iofrootx; /* Join common exit... */ 450 } 451 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar); /* Not there */ 452 } 453 } 454 455 if( (!matching) && rdBootVar[0] ) { 456 // by BSD name 457 look = rdBootVar; 458 if( look[0] == '*') 459 look++; 460 461 if ( strncmp( look, "en", strlen( "en" )) == 0 ) { 462 matching = IONetworkNamePrefixMatching( "en" ); 463 } else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) { 464 char *uuid; 465 OSString *uuidString; 466 467 uuid = (char *)IOMalloc( kMaxBootVar ); 468 469 if ( uuid ) { 470 if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) { 471 panic( "rd=uuid but no boot-uuid=<value> specified" ); 472 } 473 uuidString = OSString::withCString( uuid ); 474 if ( uuidString ) { 475 IOService::publishResource( "boot-uuid", uuidString ); 476 uuidString->release(); 477 IOLog( "\nWaiting for boot volume with UUID %s\n", uuid ); 478 matching = IOUUIDMatching(); 479 mediaProperty = "boot-uuid-media"; 480 } 481 IOFree( uuid, kMaxBootVar ); 482 } 483 } else { 484 matching = IOBSDNameMatching( look ); 485 } 486 } 487 488 if( !matching) { 489 OSString * astring; 490 // Match any HFS media 491 492 matching = IOService::serviceMatching( "IOMedia" ); 493 astring = OSString::withCStringNoCopy("Apple_HFS"); 494 if ( astring ) { 495 matching->setObject("Content", astring); 496 astring->release(); 497 } 498 } 499 500 if( gIOKitDebug & kIOWaitQuietBeforeRoot ) { 501 IOLog( "Waiting for matching to complete\n" ); 502 IOService::getPlatform()->waitQuiet(); 503 } 504 505 if( true && matching) { 506 OSSerialize * s = OSSerialize::withCapacity( 5 ); 507 508 if( matching->serialize( s )) { 509 IOLog( "Waiting on %s\n", s->text() ); 510 s->release(); 511 } 512 } 513 514 do { 515 t.tv_sec = ROOTDEVICETIMEOUT; 516 t.tv_nsec = 0; 517 matching->retain(); 518 service = IOService::waitForService( matching, &t ); 519 if( (!service) || (mountAttempts == 10)) { 520 PE_display_icon( 0, "noroot"); 521 IOLog( "Still waiting for root device\n" ); 522 523 if( !debugInfoPrintedOnce) { 524 debugInfoPrintedOnce = true; 525 if( gIOKitDebug & kIOLogDTree) { 526 IOLog("\nDT plane:\n"); 527 IOPrintPlane( gIODTPlane ); 528 } 529 if( gIOKitDebug & kIOLogServiceTree) { 530 IOLog("\nService plane:\n"); 531 IOPrintPlane( gIOServicePlane ); 532 } 533 if( gIOKitDebug & kIOLogMemory) 534 IOPrintMemory(); 535 } 536 } 537 } while( !service); 538 matching->release(); 539 540 if ( service && mediaProperty ) { 541 service = (IOService *)service->getProperty(mediaProperty); 542 } 543 544 mjr = 0; 545 mnr = 0; 546 547 // If the IOService we matched to is a subclass of IONetworkInterface, 548 // then make sure it has been registered with BSD and has a BSD name 549 // assigned. 550 551 if ( service 552 && service->metaCast( "IONetworkInterface" ) 553 && !IORegisterNetworkInterface( service ) ) 554 { 555 service = 0; 556 } 557 558 if( service) { 559 560 len = kMaxPathBuf; 561 service->getPath( str, &len, gIOServicePlane ); 562 IOLog( "Got boot device = %s\n", str ); 563 564 iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 565 if( iostr) 566 strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize ); 567 off = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 568 if( off) 569 mjr = off->unsigned32BitValue(); 570 off = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 571 if( off) 572 mnr = off->unsigned32BitValue(); 573 574 if( service->metaCast( "IONetworkInterface" )) 575 flags |= 1; 576 577 } else { 578 579 IOLog( "Wait for root failed\n" ); 580 strlcpy( rootName, "en0", rootNameSize ); 581 flags |= 1; 582 } 583 584 IOLog( "BSD root: %s", rootName ); 585 if( mjr) 586 IOLog(", major %d, minor %d\n", mjr, mnr ); 587 else 588 IOLog("\n"); 589 590 *root = makedev( mjr, mnr ); 591 *oflags = flags; 592 593 IOFree( str, kMaxPathBuf + kMaxBootVar ); 594 595 iofrootx: 596 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) { 597 598 IOService::getPlatform()->waitQuiet(); 599 if( gIOKitDebug & kIOLogDTree) { 600 IOLog("\nDT plane:\n"); 601 IOPrintPlane( gIODTPlane ); 602 } 603 if( gIOKitDebug & kIOLogServiceTree) { 604 IOLog("\nService plane:\n"); 605 IOPrintPlane( gIOServicePlane ); 606 } 607 if( gIOKitDebug & kIOLogMemory) 608 IOPrintMemory(); 609 } 610 611 return( kIOReturnSuccess ); 612 } 613 614 bool IORamDiskBSDRoot(void) 615 { 616 char rdBootVar[kMaxBootVar]; 617 if (PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) 618 || PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) { 619 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { 620 return true; 621 } 622 } 623 return false; 624 } 625 626 void IOSecureBSDRoot(const char * rootName) 627 { 628 } 629 630 void * 631 IOBSDRegistryEntryForDeviceTree(char * path) 632 { 633 return (IORegistryEntry::fromPath(path, gIODTPlane)); 634 } 635 636 void 637 IOBSDRegistryEntryRelease(void * entry) 638 { 639 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 640 641 if (regEntry) 642 regEntry->release(); 643 return; 644 } 645 646 const void * 647 IOBSDRegistryEntryGetData(void * entry, char * property_name, 648 int * packet_length) 649 { 650 OSData * data; 651 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 652 653 data = (OSData *) regEntry->getProperty(property_name); 654 if (data) { 655 *packet_length = data->getLength(); 656 return (data->getBytesNoCopy()); 657 } 658 return (NULL); 659 } 660 661 kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout ) 662 { 663 IOService * resources; 664 OSString * string; 665 666 resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), ( timeout.tv_sec || timeout.tv_nsec ) ? &timeout : 0 ); 667 if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT; 668 669 string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey ); 670 if ( string == 0 ) return KERN_NOT_SUPPORTED; 671 672 uuid_parse( string->getCStringNoCopy( ), uuid ); 673 674 return KERN_SUCCESS; 675 } 676 677 kern_return_t IOBSDGetPlatformSerialNumber( char *serial_number_str, u_int32_t len ) 678 { 679 OSDictionary * platform_dict; 680 IOService *platform; 681 OSString * string; 682 683 if (len < 1) { 684 return 0; 685 } 686 serial_number_str[0] = '\0'; 687 688 platform_dict = IOService::serviceMatching( "IOPlatformExpertDevice" ); 689 if (platform_dict == NULL) { 690 return KERN_NOT_SUPPORTED; 691 } 692 693 platform = IOService::waitForService( platform_dict ); 694 if (platform) { 695 string = ( OSString * ) platform->getProperty( kIOPlatformSerialNumberKey ); 696 if ( string == 0 ) { 697 return KERN_NOT_SUPPORTED; 698 } else { 699 strlcpy( serial_number_str, string->getCStringNoCopy( ), len ); 700 } 701 } 702 703 return KERN_SUCCESS; 704 } 705 706 void IOBSDIterateMediaWithContent(const char *content_uuid_cstring, int (*func)(const char *bsd_dev_name, const char *uuid_str, void *arg), void *arg) 707 { 708 OSDictionary *dictionary; 709 OSString *content_uuid_string; 710 711 dictionary = IOService::serviceMatching( "IOMedia" ); 712 if( dictionary ) { 713 content_uuid_string = OSString::withCString( content_uuid_cstring ); 714 if( content_uuid_string ) { 715 IOService *service; 716 OSIterator *iter; 717 718 dictionary->setObject( "Content", content_uuid_string ); 719 dictionary->retain(); 720 721 iter = IOService::getMatchingServices(dictionary); 722 while (iter && (service = (IOService *)iter->getNextObject())) { 723 if( service ) { 724 OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 725 OSString *uuidstr = (OSString *) service->getProperty( "UUID" ); 726 const char *uuid; 727 728 if( iostr) { 729 if (uuidstr) { 730 uuid = uuidstr->getCStringNoCopy(); 731 } else { 732 uuid = "00000000-0000-0000-0000-000000000000"; 733 } 734 735 // call the callback 736 if (func && func(iostr->getCStringNoCopy(), uuid, arg) == 0) { 737 break; 738 } 739 } 740 } 741 } 742 if (iter) 743 iter->release(); 744 745 content_uuid_string->release(); 746 } 747 dictionary->release(); 748 } 749 } 750 751 752 int IOBSDIsMediaEjectable( const char *cdev_name ) 753 { 754 int ret = 0; 755 OSDictionary *dictionary; 756 OSString *dev_name; 757 758 if (strncmp(cdev_name, "/dev/", 5) == 0) { 759 cdev_name += 5; 760 } 761 762 dictionary = IOService::serviceMatching( "IOMedia" ); 763 if( dictionary ) { 764 dev_name = OSString::withCString( cdev_name ); 765 if( dev_name ) { 766 IOService *service; 767 mach_timespec_t tv = { 5, 0 }; // wait up to "timeout" seconds for the device 768 769 dictionary->setObject( kIOBSDNameKey, dev_name ); 770 dictionary->retain(); 771 service = IOService::waitForService( dictionary, &tv ); 772 if( service ) { 773 OSBoolean *ejectable = (OSBoolean *) service->getProperty( "Ejectable" ); 774 775 if( ejectable ) { 776 ret = (int)ejectable->getValue(); 777 } 778 779 } 780 dev_name->release(); 781 } 782 dictionary->release(); 783 } 784 785 return ret; 786 } 787 788 } /* extern "C" */ 789 790 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 791 792 #include <sys/conf.h> 793 #include <sys/vnode.h> 794 #include <sys/vnode_internal.h> 795 #include <sys/fcntl.h> 796 #include <IOKit/IOPolledInterface.h> 797 #include <IOKit/IOBufferMemoryDescriptor.h> 798 799 IOPolledFileIOVars * gIOPolledCoreFileVars; 800 801 #if IOPOLLED_COREFILE 802 803 static IOReturn 804 IOOpenPolledCoreFile(const char * filename) 805 { 806 IOReturn err; 807 unsigned int debug; 808 809 if (gIOPolledCoreFileVars) return (kIOReturnBusy); 810 if (!IOPolledInterface::gMetaClass.getInstanceCount()) return (kIOReturnUnsupported); 811 812 debug = 0; 813 PE_parse_boot_argn("debug", &debug, sizeof (debug)); 814 if (DB_DISABLE_LOCAL_CORE & debug) return (kIOReturnUnsupported); 815 816 err = IOPolledFileOpen(filename, kIOCoreDumpSize, kIOCoreDumpFreeSize, 817 NULL, 0, 818 &gIOPolledCoreFileVars, NULL, NULL, 0); 819 if (kIOReturnSuccess != err) return (err); 820 821 err = IOPolledFilePollersSetup(gIOPolledCoreFileVars, kIOPolledPreflightCoreDumpState); 822 if (kIOReturnSuccess != err) 823 { 824 IOPolledFileClose(&gIOPolledCoreFileVars, NULL, NULL, 0, 0, 0); 825 } 826 827 return (err); 828 } 829 830 static void 831 IOClosePolledCoreFile(void) 832 { 833 IOPolledFilePollersClose(gIOPolledCoreFileVars, kIOPolledPostflightState); 834 IOPolledFileClose(&gIOPolledCoreFileVars, NULL, NULL, 0, 0, 0); 835 } 836 837 static thread_call_t gIOOpenPolledCoreFileTC; 838 static IONotifier * gIOPolledCoreFileNotifier; 839 static IONotifier * gIOPolledCoreFileInterestNotifier; 840 841 static IOReturn 842 KernelCoreMediaInterest(void * target, void * refCon, 843 UInt32 messageType, IOService * provider, 844 void * messageArgument, vm_size_t argSize ) 845 { 846 if (kIOMessageServiceIsTerminated == messageType) 847 { 848 gIOPolledCoreFileInterestNotifier->remove(); 849 gIOPolledCoreFileInterestNotifier = 0; 850 IOClosePolledCoreFile(); 851 } 852 853 return (kIOReturnSuccess); 854 } 855 856 static void 857 OpenKernelCoreMedia(thread_call_param_t p0, thread_call_param_t p1) 858 { 859 IOService * newService; 860 OSString * string; 861 char filename[16]; 862 863 newService = (IOService *) p1; 864 do 865 { 866 if (gIOPolledCoreFileVars) break; 867 string = OSDynamicCast(OSString, newService->getProperty(kIOBSDNameKey)); 868 if (!string) break; 869 snprintf(filename, sizeof(filename), "/dev/%s", string->getCStringNoCopy()); 870 if (kIOReturnSuccess != IOOpenPolledCoreFile(filename)) break; 871 gIOPolledCoreFileInterestNotifier = newService->registerInterest( 872 gIOGeneralInterest, &KernelCoreMediaInterest, NULL, 0); 873 } 874 while (false); 875 876 newService->release(); 877 } 878 879 static bool 880 NewKernelCoreMedia(void * target, void * refCon, 881 IOService * newService, 882 IONotifier * notifier) 883 { 884 do 885 { 886 if (gIOPolledCoreFileVars) break; 887 if (!gIOOpenPolledCoreFileTC) break; 888 newService = newService->getProvider(); 889 if (!newService) break; 890 newService->retain(); 891 thread_call_enter1(gIOOpenPolledCoreFileTC, newService); 892 } 893 while (false); 894 895 return (false); 896 } 897 898 #endif /* IOPOLLED_COREFILE */ 899 900 extern "C" void 901 IOBSDMountChange(struct mount * mp, uint32_t op) 902 { 903 #if IOPOLLED_COREFILE 904 905 OSDictionary * bsdMatching; 906 OSDictionary * mediaMatching; 907 OSString * string; 908 909 if (!gIOPolledCoreFileNotifier) do 910 { 911 if (!gIOOpenPolledCoreFileTC) gIOOpenPolledCoreFileTC = thread_call_allocate(&OpenKernelCoreMedia, NULL); 912 bsdMatching = IOService::serviceMatching("IOMediaBSDClient"); 913 if (!bsdMatching) break; 914 mediaMatching = IOService::serviceMatching("IOMedia"); 915 string = OSString::withCStringNoCopy("5361644D-6163-11AA-AA11-00306543ECAC"); 916 if (!string || !mediaMatching) break; 917 mediaMatching->setObject("Content", string); 918 string->release(); 919 bsdMatching->setObject(gIOParentMatchKey, mediaMatching); 920 mediaMatching->release(); 921 922 gIOPolledCoreFileNotifier = IOService::addMatchingNotification( 923 gIOFirstMatchNotification, bsdMatching, 924 &NewKernelCoreMedia, NULL, NULL, -1000); 925 } 926 while (false); 927 928 #endif /* IOPOLLED_COREFILE */ 929 } 930 931 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 932 933 extern "C" boolean_t 934 IOTaskHasEntitlement(task_t task, const char * entitlement) 935 { 936 OSObject * obj; 937 obj = IOUserClient::copyClientEntitlement(task, entitlement); 938 if (!obj) return (false); 939 obj->release(); 940 return (obj != kOSBooleanFalse); 941 } 942 943