#ifdef HAVE_CFPLUGIN
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/kext/OSKext.h>
#if 0 // for local logging
#include <asl.h>
void __iocfpluginlog(const char *format, ...);
#endif
CFUUIDRef gIOCFPlugInInterfaceID = NULL;
typedef struct LookUUIDContextStruct {
const void * result;
CFUUIDRef key;
} LookUUIDContext;
static void
_IOGetWithUUIDKey(const void *key, const void * value, void *ctx)
{
LookUUIDContext * context = (LookUUIDContext *) ctx;
CFUUIDRef uuid;
uuid = CFUUIDCreateFromString(NULL, (CFStringRef)key);
if( uuid) {
if( CFEqual( uuid, context->key))
context->result = value;
CFRelease(uuid);
}
}
static CFURLRef
_CreateIfReachable( CFStringRef thePath )
{
CFURLRef pathURL = NULL;
pathURL = CFURLCreateWithFileSystemPath(NULL, thePath,
kCFURLPOSIXPathStyle,
TRUE);
if (pathURL) {
if (CFURLResourceIsReachable(pathURL, NULL) == false) {
CFRelease( pathURL );
pathURL = NULL;
}
}
return(pathURL);
}
static kern_return_t
IOFindPlugIns( io_service_t service,
CFUUIDRef pluginType,
CFArrayRef * factories, CFArrayRef * plists )
{
CFURLRef pluginURL = NULL; CFPlugInRef onePlugin = NULL;
CFBundleRef bundle;
CFDictionaryRef plist;
CFDictionaryRef matching;
CFDictionaryRef pluginTypes = NULL; CFMutableStringRef pluginPath = NULL; LookUUIDContext context;
CFStringRef pluginName = NULL; boolean_t matches;
kern_return_t kr = kIOReturnSuccess;
*factories = 0;
*plists = 0;
do {
pluginPath = CFStringCreateMutable( kCFAllocatorDefault, 0 );
if ( pluginPath == NULL ) {
continue;
}
pluginTypes = IORegistryEntryCreateCFProperty( service, CFSTR(kIOCFPlugInTypesKey),
kCFAllocatorDefault, kNilOptions );
if ( pluginTypes == NULL ) {
continue;
}
if (CFDictionaryGetTypeID() != CFGetTypeID(pluginTypes)) {
continue;
}
context.key = pluginType;
context.result = 0;
CFDictionaryApplyFunction( pluginTypes, &_IOGetWithUUIDKey, &context);
pluginName = (CFStringRef) context.result;
if ( pluginName == NULL ) {
continue;
}
#if 0 //
const char * myPtr;
myPtr = CFStringGetCStringPtr(pluginName, kCFStringEncodingMacRoman);
__iocfpluginlog("%s pluginName \"%s\" \n", __func__,
myPtr ? myPtr : "no name");
#endif
if ( CFStringGetCharacterAtIndex(pluginName, 0) == '/' ) {
CFStringAppend(pluginPath, pluginName);
pluginURL = _CreateIfReachable(pluginPath);
if ( pluginURL ) {
onePlugin = CFPlugInCreate(NULL, pluginURL);
CFRelease( pluginURL );
pluginURL = NULL;
if ( onePlugin ) {
continue;
}
}
}
CFArrayRef extensionsFolderURLs = OSKextGetSystemExtensionsFolderURLs();
CFIndex count = CFArrayGetCount(extensionsFolderURLs);
for (CFIndex i = 0; i < count; i++) {
CFURLRef directoryURL = CFArrayGetValueAtIndex(extensionsFolderURLs, i);
pluginURL = CFURLCreateCopyAppendingPathComponent(NULL, directoryURL, pluginName, TRUE);
if (pluginURL) {
onePlugin = CFPlugInCreate(NULL, pluginURL);
CFRelease(pluginURL);
pluginURL = NULL;
if (onePlugin) {
break;
}
}
}
} while ( FALSE );
#if 0
const char * myPtr;
myPtr = CFStringGetCStringPtr(pluginPath, kCFStringEncodingMacRoman);
__iocfpluginlog("%s pluginPath \"%s\" \n", __func__,
myPtr ? myPtr : "no name");
#endif
if ( onePlugin
&& (bundle = CFPlugInGetBundle(onePlugin))
&& (plist = CFBundleGetInfoDictionary(bundle))
&& (matching = (CFDictionaryRef)
CFDictionaryGetValue(plist, CFSTR("Personality")))) {
kr = IOServiceMatchPropertyTable( service, matching, &matches );
if ( kr != kIOReturnSuccess )
matches = FALSE;
} else {
matches = TRUE;
}
if ( matches ) {
if ( onePlugin ) {
*factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(pluginType, onePlugin);
}
}
if ( pluginPath )
CFRelease( pluginPath );
if ( pluginTypes )
CFRelease( pluginTypes );
#if 0
__iocfpluginlog("%s kr %d \n", __func__, kr);
#endif
return( kr );
}
kern_return_t
IOCreatePlugInInterfaceForService(io_service_t service,
CFUUIDRef pluginType, CFUUIDRef interfaceType,
IOCFPlugInInterface *** theInterface, SInt32 * theScore)
{
CFDictionaryRef plist = 0;
CFArrayRef plists;
CFArrayRef factories;
CFMutableArrayRef candidates;
CFMutableArrayRef scores;
CFIndex index;
CFIndex insert;
CFUUIDRef factoryID;
kern_return_t kr;
SInt32 score;
IOCFPlugInInterface ** interface;
Boolean haveOne;
kr = IOFindPlugIns( service, pluginType,
&factories, &plists );
if( KERN_SUCCESS != kr) {
if (factories) CFRelease(factories);
if (plists) CFRelease(plists);
return( kr );
}
if ((KERN_SUCCESS != kr)
|| (factories == NULL)
|| (0 == CFArrayGetCount(factories))) {
if (factories) CFRelease(factories);
if (plists) CFRelease(plists);
return( kIOReturnUnsupported );
}
candidates = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
scores = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
if (candidates && scores) {
CFIndex numfactories = CFArrayGetCount(factories);
for ( index = 0; index < numfactories; index++ ) {
IUnknownVTbl ** iunknown;
factoryID = (CFUUIDRef) CFArrayGetValueAtIndex(factories, index);
iunknown = (IUnknownVTbl **)
CFPlugInInstanceCreate(NULL, factoryID, pluginType);
if (!iunknown) {
continue;
}
(*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(interfaceType),
(LPVOID *)&interface);
(*iunknown)->Release(iunknown);
if (!interface) {
continue;
}
if (plists)
plist = (CFDictionaryRef) CFArrayGetValueAtIndex( plists, index );
score = 0; kr = (*interface)->Probe(interface, plist, service, &score);
if (kIOReturnSuccess == kr) {
CFIndex numscores = CFArrayGetCount(scores);
for (insert = 0; insert < numscores; insert++) {
if (score > (SInt32) ((intptr_t) CFArrayGetValueAtIndex(scores, insert)))
break;
}
CFArrayInsertValueAtIndex(candidates, insert, (void *) interface);
CFArrayInsertValueAtIndex(scores, insert, (void *) (intptr_t) score);
} else
(*interface)->Release(interface);
}
}
CFIndex candidatecount = CFArrayGetCount(candidates);
for (haveOne = false, index = 0;
index < candidatecount;
index++) {
Boolean freeIt;
if (plists)
plist = (CFDictionaryRef) CFArrayGetValueAtIndex(plists, index );
interface = (IOCFPlugInInterface **)
CFArrayGetValueAtIndex(candidates, index );
if (!haveOne) {
haveOne = (kIOReturnSuccess == (*interface)->Start(interface, plist, service));
freeIt = !haveOne;
if (haveOne) {
*theInterface = interface;
*theScore = (SInt32) (intptr_t)
CFArrayGetValueAtIndex(scores, index );
}
} else
freeIt = true;
if (freeIt)
(*interface)->Release(interface);
}
if (factories)
CFRelease(factories);
if (plists)
CFRelease(plists);
if (candidates)
CFRelease(candidates);
if (scores)
CFRelease(scores);
return (haveOne ? kIOReturnSuccess : kIOReturnNoResources);
}
kern_return_t
IODestroyPlugInInterface(IOCFPlugInInterface ** interface)
{
kern_return_t err;
err = (*interface)->Stop(interface);
(*interface)->Release(interface);
return( err );
}
kern_return_t
IOCreatePlugInInterfaces(CFUUIDRef pluginType, CFUUIDRef interfaceType);
#if 0 // local logging
void __iocfpluginlog(const char *format, ...)
{
va_list args;
va_start(args, format);
asl_vlog(NULL, NULL, ASL_LEVEL_CRIT, format, args);
va_end(args);
}
#endif
#endif