xref: /xnu-11215/iokit/bsddev/IOKitBSDInit.cpp (revision 8dd02465)
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