1 #define CFRUNLOOP_NEW_API 1
5 #include <IOKit/IOKitLib.h>
6 #include <IOKit/IOKitServer.h>
7 #include <IOKit/IOCFSerialize.h>
8 #include <IOKit/IOCFURLAccess.h>
13 #include <sys/types.h>
14 #include <mach/mach.h>
15 #include <mach/mach_host.h>
16 #include <mach/bootstrap.h>
17 #include <mach/kmod.h>
20 #include <CoreFoundation/CFPriv.h> // for _CFRunLoopSetCurrent();
22 #define TIMER_PERIOD_S 10
23 #define LOOKAPPLENDRV 1
25 static Boolean gDebug
;
26 static void KEXTdaemonSignal(void);
28 // from kernserv/queue.h now kern/queue.h
31 * A generic doubly-linked list (queue).
35 struct queue_entry
*next
; /* next element */
36 struct queue_entry
*prev
; /* previous element */
39 typedef struct queue_entry
*queue_t
;
40 typedef struct queue_entry queue_head_t
;
41 typedef struct queue_entry queue_chain_t
;
42 typedef struct queue_entry
*queue_entry_t
;
47 * Initialize the given queue.
50 * queue_t q; \* MODIFIED *\
52 #define queue_init(q) ((q)->next = (q)->prev = q)
57 * Returns the first entry in the queue,
59 * queue_entry_t queue_first(q)
62 #define queue_first(q) ((q)->next)
67 * queue_entry_t queue_next(qc)
70 #define queue_next(qc) ((qc)->next)
75 * boolean_t queue_end(q, qe)
79 #define queue_end(q, qe) ((q) == (qe))
81 #define queue_empty(q) queue_end((q), queue_first(q))
86 * void queue_enter(q, elt, type, field)
89 * <type> is what's in our queue
90 * <field> is the chain field in (*<type>)
92 #define queue_enter(head, elt, type, field) \
94 if (queue_empty((head))) { \
95 (head)->next = (queue_entry_t) elt; \
96 (head)->prev = (queue_entry_t) elt; \
97 (elt)->field.next = head; \
98 (elt)->field.prev = head; \
101 register queue_entry_t prev; \
103 prev = (head)->prev; \
104 (elt)->field.prev = prev; \
105 (elt)->field.next = head; \
106 (head)->prev = (queue_entry_t)(elt); \
107 ((type)prev)->field.next = (queue_entry_t)(elt);\
112 * Macro: queue_field [internal use only]
114 * Find the queue_chain_t (or queue_t) for the
115 * given element (thing) in the given queue (head)
117 #define queue_field(head, thing, type, field) \
118 (((head) == (thing)) ? (head) : &((type)(thing))->field)
121 * Macro: queue_remove
123 * void queue_remove(q, qe, type, field)
124 * arguments as in queue_enter
126 #define queue_remove(head, elt, type, field) \
128 register queue_entry_t next, prev; \
130 next = (elt)->field.next; \
131 prev = (elt)->field.prev; \
133 queue_field((head), next, type, field)->prev = prev; \
134 queue_field((head), prev, type, field)->next = next; \
138 typedef struct _KEXTD
{
140 CFRunLoopRef _runloop
;
141 CFRunLoopSourceRef _signalsource
;
142 CFRunLoopSourceRef _kernelsource
;
143 CFMutableArrayRef _scanPaths
;
144 CFMutableArrayRef _unloaded
;
145 CFMutableArrayRef _helpers
;
146 queue_head_t _requestQ
;
147 PTLockRef _runloop_lock
;
148 PTLockRef _queue_lock
;
149 KEXTManagerRef _manager
;
150 mach_port_t _catPort
;
151 Boolean _initializing
;
154 Boolean _pollFileSystem
;
155 CFIndex _pollingPeriod
;
159 typedef struct _request
{
161 CFStringRef kmodname
;
162 CFStringRef kmodvers
;
166 typedef struct _KEXTDHelper
{
168 KEXTDHelperCallbacks cbs
;
171 CFDictionaryRef
_KEXTPersonalityGetProperties(KEXTPersonalityRef personality
);
172 static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd
, CFStringRef parentKey
);
173 static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd
, CFStringRef modName
);
174 const void * _KEXTPersonalityRetainCB(CFAllocatorRef allocator
, const void *ptr
);
175 void _KEXTPersonalityReleaseCB(CFAllocatorRef allocator
, const void *ptr
);
176 Boolean
_KEXTPersonalityEqualCB(const void *ptr1
, const void *ptr2
);
177 mach_port_t
_KEXTManagerGetMachPort(KEXTManagerRef manager
);
180 kmod_control(host_t host
,
182 kmod_control_flavor_t flavor
,
184 mach_msg_type_number_t
*dataCount
);
186 extern KEXTReturn
KERN2KEXTReturn(kern_return_t kr
);
188 static KEXTDRef _kextd
= NULL
;
190 static void logErrorFunction(const char * string
)
192 syslog(LOG_ERR
, string
);
196 static void logMessageFunction(const char * string
)
198 syslog(LOG_INFO
, string
);
203 static void ArrayMergeFunc(const void * val
, void * context
)
205 CFMutableArrayRef array
;
209 CFArrayAppendValue(array
, val
);
212 static void CFArrayMergeArray(CFMutableArrayRef array1
, CFArrayRef array2
)
216 if ( !array1
|| !array2
) {
220 range
= CFRangeMake(0, CFArrayGetCount(array2
));
221 CFArrayApplyFunction(array2
, range
, ArrayMergeFunc
, array1
);
224 static void CallHelperEvent(void * val
, void * context
[])
228 KEXTDHelper
* helper
;
233 event
= *(KEXTEvent
*)context
[1];
236 if ( helper
&& context
&& helper
->cbs
.EventOccurred
) {
237 helper
->cbs
.EventOccurred(event
, item
, kextd
);
241 static void ConfigsForBundles(const void * var
, void * context
[])
243 KEXTManagerRef manager
;
244 KEXTBundleRef bundle
;
245 CFMutableArrayRef array
;
248 bundle
= (KEXTBundleRef
)var
;
250 manager
= context
[0];
253 configs
= KEXTManagerCopyConfigsForBundle(manager
, bundle
);
255 CFArrayMergeArray(array
, configs
);
261 static inline KEXTBootlevel
_KEXTDGetBootlevel(KEXTPersonalityRef personality
)
263 KEXTBootlevel bootlevel
;
264 CFStringRef priority
;
265 CFStringRef category
;
267 bootlevel
= kKEXTBootlevelExempt
;
268 priority
= KEXTPersonalityGetProperty(personality
, CFSTR("BootPriority"));
270 category
= KEXTPersonalityGetProperty(personality
, CFSTR("DeviceCategory"));
272 return kKEXTBootlevelExempt
;
275 if ( CFEqual(category
, CFSTR("System Controller")) ) {
276 bootlevel
= kKEXTBootlevelRequired
;
278 else if ( CFEqual(category
, CFSTR("Bus Controller")) ) {
279 bootlevel
= kKEXTBootlevelFlexible
;
281 else if ( CFEqual(category
, CFSTR("Keyboard")) ) {
282 bootlevel
= kKEXTBootlevelSingleUser
;
284 else if ( CFEqual(category
, CFSTR("Input Device")) ) {
285 bootlevel
= kKEXTBootlevelExempt
;
287 else if ( CFEqual(category
, CFSTR("Pointing Device")) ) {
288 bootlevel
= kKEXTBootlevelExempt
;
290 else if ( CFEqual(category
, CFSTR("Mouse")) ) {
291 bootlevel
= kKEXTBootlevelRecovery
;
293 else if ( CFEqual(category
, CFSTR("Graphics Controller")) ) {
294 bootlevel
= kKEXTBootlevelRecovery
;
296 else if ( CFEqual(category
, CFSTR("Graphics Accelerator")) ) {
297 bootlevel
= kKEXTBootlevelExempt
;
299 else if ( CFEqual(category
, CFSTR("Video Device")) ) {
300 bootlevel
= kKEXTBootlevelExempt
;
302 else if ( CFEqual(category
, CFSTR("Disk Controller")) ) {
303 bootlevel
= kKEXTBootlevelFlexible
;
305 else if ( CFEqual(category
, CFSTR("Disk Media")) ) {
306 bootlevel
= kKEXTBootlevelFlexible
;
308 else if ( CFEqual(category
, CFSTR("Audio Controller")) ) {
309 bootlevel
= kKEXTBootlevelExempt
;
311 else if ( CFEqual(category
, CFSTR("Sound Device")) ) {
312 bootlevel
= kKEXTBootlevelExempt
;
314 else if ( CFEqual(category
, CFSTR("Network Controller")) ) {
315 bootlevel
= kKEXTBootlevelFlexible
;
321 if ( CFEqual(priority
, CFSTR("Exempt")) ) {
322 bootlevel
= kKEXTBootlevelExempt
;
324 else if ( CFEqual(priority
, CFSTR("Recovery")) ) {
325 bootlevel
= kKEXTBootlevelRecovery
;
327 else if ( CFEqual(priority
, CFSTR("Special")) ) {
328 bootlevel
= kKEXTBootlevelSingleUser
;
330 else if ( CFEqual(priority
, CFSTR("Flexible")) ) {
331 bootlevel
= kKEXTBootlevelFlexible
;
333 else if ( CFEqual(priority
, CFSTR("Required")) ) {
334 bootlevel
= kKEXTBootlevelRequired
;
340 static void ArrayAddToLoadList(void * val
, void * context
[])
342 KEXTPersonalityRef person
;
343 KEXTBootlevel bootlevel
;
344 CFMutableArrayRef unloaded
;
345 CFMutableArrayRef loadlist
;
349 if ( !val
|| !context
) {
355 unloaded
= context
[0];
356 loadlist
= context
[1];
357 bootlevel
= *(KEXTBootlevel
*)context
[2];
359 if ( bootlevel
!= kKEXTBootlevelNormal
) {
360 doAdd
= _KEXTDGetBootlevel(person
) & bootlevel
;
364 range
= CFRangeMake(0, CFArrayGetCount(loadlist
));
365 if ( !CFArrayContainsValue(loadlist
, range
, person
) ) {
366 CFArrayAppendValue(loadlist
, person
);
370 range
= CFRangeMake(0, CFArrayGetCount(unloaded
));
371 if ( !CFArrayContainsValue(unloaded
, range
, person
) ) {
372 CFArrayAppendValue(unloaded
, person
);
374 CFArrayAppendValue(unloaded
, person
);
378 static void signalhandler(int signal
)
380 if ( _kextd
&& (signal
== SIGHUP
) ) {
385 static KEXTReturn
_KEXTDInitSyslog(KEXTD
* k
)
387 openlog("kextd", LOG_PID
| LOG_NDELAY
, LOG_DAEMON
);
389 return kKEXTReturnSuccess
;
392 // This is called when authenticating a new bundle.
393 static KEXTReturn
_KEXTDAuthenticateBundleCB(CFURLRef url
, void * context
)
397 ret
= KEXTManagerAuthenticateURL(url
);
399 KEXTD
* k
= (KEXTD
*)context
;
401 CFStringRef urlString
;
406 urlString
= CFURLGetString(url
);
407 if ( CFStringGetCString(urlString
, name
, 256, kCFStringEncodingNonLossyASCII
) )
408 syslog(LOG_ERR
, "%s failed authentication.", name
);
410 event
= kKEXTEventBundleAuthenticationFailed
;
412 context2
[1] = &event
;
413 context2
[2] = (void *)url
;
415 range
= CFRangeMake(0, CFArrayGetCount(k
->_helpers
));
416 CFArrayApplyFunction(k
->_helpers
, range
, (CFArrayApplierFunction
)CallHelperEvent
, context2
);
422 // This is called when a new bundle has been found.
423 static Boolean
_KEXTDWillAddBundleCB(KEXTManagerRef manager
, KEXTBundleRef bundle
, void * context
)
425 KEXTD
* k
= (KEXTD
*)context
;
432 count
= CFArrayGetCount(k
->_helpers
);
433 for ( i
= 0; i
< count
; i
++ ) {
434 KEXTDHelper
* helper
;
436 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
440 if ( helper
->cbs
.BundleAdd
) {
441 ret
= helper
->cbs
.BundleAdd(bundle
, helper
->context
);
447 url
= KEXTBundleCopyURL(bundle
);
449 if ( k
->_beVerbose
&& ret
) {
453 cfstr
= CFURLGetString(url
);
454 if ( CFStringGetCString(cfstr
, str
, 256, kCFStringEncodingNonLossyASCII
) ) {
455 syslog(LOG_INFO
, "%s added.", str
);
459 // Remove any unloaded personalities from look-aside queue
460 // which are in this bundle.
461 _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef
)k
, KEXTBundleGetPrimaryKey(bundle
));
468 // This is called after a bundle has been added to the KEXTManager database.
469 static void _KEXTDWasAddedBundleCB(KEXTManagerRef manager
, KEXTBundleRef bundle
, void * context
)
472 KEXTBootlevel bootlevel
;
473 CFMutableArrayRef toload
;
480 k
= (KEXTD
*)context
;
481 if ( k
->_initializing
) {
485 bootlevel
= kKEXTBootlevelNormal
;
487 toload
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
492 context2
[0] = k
->_unloaded
;
493 context2
[1] = toload
;
494 context2
[2] = &bootlevel
;
497 // Create a list of all personalities and configurations
498 // and send it to the catalogue. First, get the unloaded
500 unloaded
= CFArrayCreateCopy(kCFAllocatorDefault
, k
->_unloaded
);
501 CFArrayRemoveAllValues(k
->_unloaded
);
503 range
= CFRangeMake(0, CFArrayGetCount(unloaded
));
504 CFArrayApplyFunction(unloaded
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context2
);
508 persons
= KEXTManagerCopyPersonalitiesForBundle(manager
, bundle
);
510 range
= CFRangeMake(0, CFArrayGetCount(persons
));
511 CFArrayApplyFunction(persons
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context2
);
515 configs
= KEXTManagerCopyConfigsForBundle(manager
, bundle
);
517 range
= CFRangeMake(0, CFArrayGetCount(configs
));
518 CFArrayApplyFunction(configs
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context2
);
523 // Send the list to IOCatalogue.
524 if ( CFArrayGetCount(toload
) > 0 ) {
525 KEXTManagerLoadPersonalities(k
->_manager
, toload
);
531 static void _KEXTDConfigWasAdded(KEXTManagerRef manager
, KEXTConfigRef config
, void * context
)
535 if ( !manager
|| !config
|| !context
) {
541 if ( !kextd
->_initializing
) {
542 CFStringRef primaryKey
;
546 primaryKey
= CFDictionaryGetValue(config
, CFSTR("ParentKey"));
551 if ( !KEXTManagerGetBundle(manager
, primaryKey
) ) {
556 array
= CFArrayCreate(kCFAllocatorDefault
, vals
, 1, &kCFTypeArrayCallBacks
);
558 KEXTManagerLoadPersonalities(manager
, array
);
564 static void _KEXTDConfigWasRemoved(KEXTManagerRef manager
, KEXTConfigRef config
, void * context
)
568 if ( !manager
|| !config
|| !context
) {
574 if ( !kextd
->_initializing
) {
575 KEXTManagerUnloadPersonality(manager
, config
);
579 static void ArrayUnloadPersonality(const void * val
, void * context
)
581 KEXTManagerRef manager
;
582 KEXTPersonalityRef person
;
585 person
= (KEXTPersonalityRef
)val
;
587 KEXTManagerUnloadPersonality(manager
, person
);
590 // This is called when a bundle has been removed from the filesystem.
591 static Boolean
_KEXTDWillRemoveBundleCB(KEXTManagerRef manager
, KEXTBundleRef bundle
, void * context
)
593 KEXTD
* k
= (KEXTD
*)context
;
599 count
= CFArrayGetCount(k
->_helpers
);
600 for ( i
= 0; i
< count
; i
++ ) {
601 KEXTDHelper
* helper
;
603 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
607 if ( helper
->cbs
.BundleRemove
) {
608 ret
= helper
->cbs
.BundleRemove(bundle
, helper
->context
);
615 CFArrayRef personalities
;
620 // XXX -- svail: might want to unload bundle personalities
621 // from IOCatalogue and maybe unload the modules if possible.
622 // If a module is present with active personalities, don't remove
623 // bundle from database.
624 personalities
= KEXTManagerCopyPersonalitiesForBundle(manager
, bundle
);
625 if ( personalities
) {
626 range
= CFRangeMake(0, CFArrayGetCount(personalities
));
627 CFArrayApplyFunction(personalities
, range
, ArrayUnloadPersonality
, manager
);
628 CFRelease(personalities
);
631 configs
= KEXTManagerCopyConfigsForBundle(manager
, bundle
);
633 range
= CFRangeMake(0, CFArrayGetCount(configs
));
634 CFArrayApplyFunction(configs
, range
, ArrayUnloadPersonality
, manager
);
638 url
= KEXTBundleCopyURL(bundle
);
640 if ( k
->_beVerbose
&& ret
) {
644 cfstr
= CFURLGetString(url
);
645 if ( CFStringGetCString(cfstr
, str
, 256, kCFStringEncodingNonLossyASCII
) ) {
646 syslog(LOG_INFO
, "%s removed.", str
);
650 // Remove any unloaded personalities from the unloaded
651 // list if they are associated with the bundle.
653 _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef
)k
, KEXTBundleGetPrimaryKey(bundle
));
661 // This is called before KEXT loads a KMOD.
662 static Boolean
_KEXTDModuleWillLoadCB(KEXTManagerRef manager
, KEXTModuleRef
module, void * context
)
669 k
= (KEXTD
*)context
;
672 count
= CFArrayGetCount(k
->_helpers
);
673 for ( i
= 0; i
< count
; i
++ ) {
674 KEXTDHelper
* helper
;
676 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
680 if ( helper
->cbs
.ModuleWillLoad
) {
681 if ( !helper
->cbs
.ModuleWillLoad(module, helper
->context
) ) {
689 CFStringRef moduleName
;
692 moduleName
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
696 if ( !CFStringGetCString(moduleName
, name
, 256, kCFStringEncodingNonLossyASCII
) )
699 syslog(LOG_INFO
, "loading module: %s.\n", name
);
705 // This is called when a module has been successfully loaded.
706 static void _KEXTDModuleWasLoadedCB(KEXTManagerRef manager
, KEXTModuleRef
module, void * context
)
710 CFMutableArrayRef send
;
714 k
= (KEXTD
*)context
;
716 count
= CFArrayGetCount(k
->_helpers
);
717 for ( i
= 0; i
< count
; i
++ ) {
718 KEXTDHelper
* helper
;
720 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
724 if ( helper
->cbs
.ModuleWasLoaded
) {
725 helper
->cbs
.ModuleWasLoaded(module, helper
->context
);
729 // Remove personalities from unloaded list if they
730 // are associated with the module and pass them to the
731 // kernel just in case they aren't there yet.
733 array
= CFArrayCreateCopy(kCFAllocatorDefault
, k
->_unloaded
);
734 send
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
735 count
= CFArrayGetCount(array
);
737 CFArrayRemoveAllValues(k
->_unloaded
);
739 for ( i
= 0; i
< count
; i
++ ) {
740 KEXTPersonalityRef person
;
741 CFStringRef moduleID
;
742 CFStringRef personalityBundleID
;
744 person
= (KEXTPersonalityRef
)CFArrayGetValueAtIndex(array
, i
);
749 moduleID
= KEXTPersonalityGetProperty(person
, CFSTR("CFBundleIdentifier"));
754 personalityBundleID
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
755 if ( !personalityBundleID
) {
759 if ( !CFEqual(moduleID
, personalityBundleID
) ) {
760 CFArrayAppendValue(k
->_unloaded
, person
);
763 CFArrayAppendValue(send
, person
);
767 if ( CFArrayGetCount(send
) > 0 ) {
768 KEXTManagerLoadPersonalities(k
->_manager
, send
);
774 if ( k
->_beVerbose
) {
775 CFStringRef moduleName
;
778 moduleName
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
782 if ( !CFStringGetCString(moduleName
, name
, 256, kCFStringEncodingNonLossyASCII
) )
785 syslog(LOG_INFO
, "loaded module: %s\n", name
);
789 static KEXTReturn
_KEXTDModuleErrorCB(KEXTManagerRef manager
, KEXTModuleRef
module, KEXTReturn error
, void * context
)
796 CFStringRef moduleName
;
798 k
= (KEXTD
*)context
;
800 moduleName
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
802 return kKEXTReturnPropertyNotFound
;
804 if ( !CFStringGetCString(moduleName
, name
, 256, kCFStringEncodingNonLossyASCII
) )
805 return kKEXTReturnNoMemory
;
807 if ( error
== kKEXTReturnModuleAlreadyLoaded
) {
809 syslog(LOG_INFO
, "module already loaded: %s.\n", name
);
815 count
= CFArrayGetCount(k
->_helpers
);
816 for ( i
= 0; i
< count
; i
++ ) {
817 KEXTDHelper
* helper
;
819 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
823 if ( helper
->cbs
.ModuleLoadError
) {
824 ret
= helper
->cbs
.ModuleLoadError(module, error
, helper
->context
);
825 if ( ret
== kKEXTReturnSuccess
) {
830 if ( ret
== kKEXTReturnSuccess
)
831 return kKEXTReturnSuccess
;
833 syslog(LOG_ERR
, "error (%d) loading module: %s.\n", ret
, name
);
839 static void _KEXTDTimerCallout(CFRunLoopTimerRef timer
, void * info
)
841 KEXTDScanPaths((KEXTDRef
)info
);
845 static void _KEXTDSIGHUPCallout(void * info
)
850 if ( k
->_beVerbose
) {
851 syslog(LOG_INFO
, "user requests directory re-scan.");
854 // Check for new or removed bundles and do the appropriate
856 KEXTDScanPaths((KEXTDRef
)info
);
858 // Make sure we try to load the unloaded personalities
859 // It's probably overkill to do this here.
860 if ( CFArrayGetCount(k
->_unloaded
) > 0 ) {
861 KEXTManagerLoadPersonalities(k
->_manager
, k
->_unloaded
);
865 // This function is called when IOCatalogue requests a driver module.
866 static void _KEXTDPerform(void * info
)
873 // KEXTDScanPaths((KEXTDRef)k);
875 PTLockTakeLock(k
->_queue_lock
);
876 while ( !queue_empty(&k
->_requestQ
) ) {
877 request_t
* reqstruct
;
880 // Dequeue the kernel request structure.
881 reqstruct
= (request_t
*)queue_first(&k
->_requestQ
);
882 queue_remove(&k
->_requestQ
, reqstruct
, request_t
*, link
);
883 PTLockUnlock(k
->_queue_lock
);
885 type
= reqstruct
->type
;
886 name
= reqstruct
->kmodname
;
889 if( type
== kIOCatalogMatchIdle
) {
891 mach_timespec_t timeout
= { 10, 0 };
892 IOKitWaitQuiet( k
->_catPort
, &timeout
);
897 if ( k
->_beVerbose
) {
900 if ( CFStringGetCString(name
, modname
, 256, kCFStringEncodingNonLossyASCII
) ) {
901 syslog(LOG_INFO
, "kernel requests module: %s", modname
);
905 KEXTDKernelRequest((KEXTDRef
)k
, name
);
909 PTLockTakeLock(k
->_queue_lock
);
911 PTLockUnlock(k
->_queue_lock
);
914 KEXTDRef
KEXTDCreate(CFArrayRef scanPaths
, KEXTReturn
* error
)
918 kextd
= (KEXTD
*)malloc(sizeof(KEXTD
));
920 *error
= kKEXTReturnNoMemory
;
923 memset(kextd
, 0, sizeof(KEXTD
));
925 kextd
->_queue_lock
= PTLockCreate();
926 kextd
->_runloop_lock
= PTLockCreate();
928 kextd
->_helpers
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
929 kextd
->_unloaded
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
930 kextd
->_scanPaths
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
931 if ( !kextd
->_scanPaths
|| !kextd
->_unloaded
|| !kextd
->_helpers
) {
932 *error
= kKEXTReturnNoMemory
;
933 KEXTDFree((KEXTDRef
)kextd
);
937 kextd
->_initializing
= true;
938 kextd
->_beVerbose
= false;
940 kextd
->_pollFileSystem
= false;
941 kextd
->_pollingPeriod
= TIMER_PERIOD_S
;
944 queue_init(&kextd
->_requestQ
);
951 count
= CFArrayGetCount(scanPaths
);
952 for ( i
= 0; i
< count
; i
++ ) {
953 url
= (CFURLRef
)CFArrayGetValueAtIndex(scanPaths
, i
);
954 KEXTDAddScanPath((KEXTDRef
)kextd
, url
);
958 return (KEXTDRef
)kextd
;
961 static void _KEXTDFlushHelpers(KEXTDRef kextd
)
968 count
= CFArrayGetCount(k
->_helpers
);
969 for ( i
= 0; i
< count
; i
++ ) {
970 KEXTDHelper
* helper
;
972 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
976 if ( helper
->cbs
.DaemonWillTerminate
)
977 helper
->cbs
.DaemonWillTerminate(helper
->context
);
978 if ( helper
->cbs
.HelperFinalize
)
979 helper
->cbs
.HelperFinalize(helper
->context
);
985 void KEXTDFree(KEXTDRef kextd
)
991 syslog(LOG_DEBUG
, "terminating.");
994 _KEXTDFlushHelpers(kextd
);
995 CFRelease(k
->_helpers
);
997 if ( k
->_kernelsource
)
998 CFRelease(k
->_kernelsource
);
999 if ( k
->_signalsource
)
1000 CFRelease(k
->_signalsource
);
1002 CFRelease(k
->_runloop
);
1003 if ( k
->_scanPaths
)
1004 CFRelease(k
->_scanPaths
);
1006 KEXTManagerRelease(k
->_manager
);
1007 if ( k
->_queue_lock
)
1008 PTLockFree(k
->_queue_lock
);
1009 if ( k
->_runloop_lock
)
1010 PTLockFree(k
->_runloop_lock
);
1017 void KEXTDReset(KEXTDRef kextd
)
1023 syslog(LOG_DEBUG
, "resetting.");
1026 count
= CFArrayGetCount(k
->_helpers
);
1027 for ( i
= 0; i
< count
; i
++ ) {
1028 KEXTDHelper
* helper
;
1030 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
1034 if ( helper
->cbs
.EventOccurred
)
1035 helper
->cbs
.EventOccurred(kKEXTEventReset
, NULL
, helper
->context
);
1039 KEXTManagerReset(k
->_manager
);
1041 KEXTDScanPaths(kextd
);
1044 static KEXTReturn
_KEXTDSendDataToCatalog(KEXTDRef kextd
, int flag
, CFTypeRef obj
)
1054 error
= kKEXTReturnSuccess
;
1056 data
= IOCFSerialize(obj
, 0);
1058 return kKEXTReturnSerializationError
;
1061 len
= CFDataGetLength(data
);
1062 ptr
= (void *)CFDataGetBytePtr(data
);
1063 error
= KERN2KEXTReturn(IOCatalogueSendData(k
->_catPort
, flag
, ptr
, len
));
1069 static KEXTReturn
_KEXTDSendPersonalities(KEXTDRef kextd
, KEXTBootlevel bootlevel
)
1074 CFMutableArrayRef configs
;
1075 CFMutableArrayRef toload
;
1079 error
= kKEXTReturnSuccess
;
1081 toload
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1083 return kKEXTReturnNoMemory
;
1087 bundles
= KEXTManagerCopyAllBundles(((KEXTD
*)kextd
)->_manager
);
1089 configs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1093 return kKEXTReturnNoMemory
;
1096 context
[0] = ((KEXTD
*)kextd
)->_manager
;
1097 context
[1] = configs
;
1099 range
= CFRangeMake(0, CFArrayGetCount(bundles
));
1100 CFArrayApplyFunction(bundles
, range
, (CFArrayApplierFunction
)ConfigsForBundles
, context
);
1104 // Filter out any inappropriate personalities given the bootlevel of the
1105 // system. Store these personalities in the _unloaded list, they will be
1106 // loaded when a SIGHUP is sent to the daemon.
1107 context
[0] = ((KEXTD
*)kextd
)->_unloaded
;
1108 context
[1] = toload
;
1109 context
[2] = &bootlevel
;
1111 persons
= KEXTManagerCopyAllPersonalities(((KEXTD
*)kextd
)->_manager
);
1113 range
= CFRangeMake(0, CFArrayGetCount(persons
));
1114 CFArrayApplyFunction(persons
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context
);
1119 range
= CFRangeMake(0, CFArrayGetCount(configs
));
1120 CFArrayApplyFunction(configs
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context
);
1124 if ( CFArrayGetCount(toload
) > 0 ) {
1125 error
= KEXTManagerLoadPersonalities(((KEXTD
*)kextd
)->_manager
, toload
);
1136 static inline Boolean
_KEXTPersonalityNeedsModule(KEXTPersonalityRef person
, CFStringRef modName
)
1140 name
= KEXTPersonalityGetProperty(person
, CFSTR("CFBundleIdentifier"));
1145 return CFEqual(name
, modName
);
1148 // If a module fails to load for some reason, then put the
1149 // personalities associated with this module in a look-aside
1150 // buffer, we'll try loading them later, maybe when a broken
1151 // dependency is fixed.
1152 static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd
, CFStringRef modName
)
1164 array
= KEXTManagerCopyAllEntities(k
->_manager
);
1168 // Find personalities which depend on this module.
1169 count
= CFArrayGetCount(array
);
1170 for ( i
= 0; i
< count
; i
++ ) {
1174 KEXTEntityRef entity
;
1176 entity
= (KEXTEntityRef
)CFArrayGetValueAtIndex(array
, i
);
1180 type
= KEXTManagerGetEntityType(entity
);
1181 if ( !type
|| !CFEqual(type
, KEXTPersonalityGetEntityType()) ) {
1185 name
= KEXTPersonalityGetProperty(entity
, CFSTR("CFBundleIdentifier"));
1186 if ( !name
|| !CFEqual(modName
, name
) ) {
1190 range
= CFRangeMake(0, CFArrayGetCount(k
->_unloaded
));
1192 if ( CFArrayContainsValue(k
->_unloaded
, range
, entity
) ) {
1196 CFArrayAppendValue(k
->_unloaded
, entity
);
1198 if ( !k
->_initializing
) {
1199 KEXTManagerUnloadPersonality(k
->_manager
, entity
);
1206 static void RemovePersonsWithParentFromUnloadedList(void * val
, void * context
[])
1208 KEXTPersonalityRef person
;
1209 CFMutableArrayRef unloaded
;
1210 CFStringRef parentKey
;
1213 if ( !val
|| !context
) {
1218 unloaded
= context
[0];
1219 parentKey
= context
[1];
1221 key
= CFDictionaryGetValue(person
, CFSTR("ParentKey"));
1222 if ( !parentKey
|| !key
|| CFEqual(parentKey
, key
) ) {
1226 CFArrayAppendValue(unloaded
, person
);
1229 // Remove personalities from the unloaded list if their
1230 // associated bundle is removed.
1231 static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd
, CFStringRef parentKey
)
1233 CFMutableArrayRef unloaded
;
1238 unloaded
= ((KEXTD
*)kextd
)->_unloaded
;
1240 array
= CFArrayCreateCopy(kCFAllocatorDefault
, unloaded
);
1241 CFArrayRemoveAllValues(unloaded
);
1243 context
[0] = unloaded
;
1244 context
[1] = (void *)parentKey
;
1246 range
= CFRangeMake(0, CFArrayGetCount(array
));
1247 CFArrayApplyFunction(
1250 (CFArrayApplierFunction
)RemovePersonsWithParentFromUnloadedList
,
1256 static KEXTReturn
_KEXTDProcessLoadCommand(KEXTDRef kextd
, CFStringRef name
)
1263 if ( !CFStringGetCString(name
, cname
, 256, kCFStringEncodingNonLossyASCII
) ) {
1264 error
= kKEXTReturnNoMemory
;
1268 error
= KEXTDLoadModule(kextd
, name
);
1269 if ( error
!= kKEXTReturnSuccess
&&
1270 error
!= kKEXTReturnModuleAlreadyLoaded
) {
1271 CFDictionaryRef matchingDict
;
1272 const void * keys
[1];
1273 const void * vals
[1];
1276 keys
[0] = CFSTR("CFBundleIdentifier");
1280 error
= kKEXTReturnPropertyNotFound
;
1284 matchingDict
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, vals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1285 if ( !matchingDict
) {
1286 error
= kKEXTReturnNoMemory
;
1290 error
= _KEXTDSendDataToCatalog(kextd
, kIOCatalogRemoveDrivers
, matchingDict
);
1291 CFRelease(matchingDict
);
1292 if ( error
!= kKEXTReturnSuccess
) {
1293 syslog(LOG_DEBUG
, "error ( %d) removing drivers.", error
);
1298 // Place personalities which failed to load this module onto
1299 // a look-aside queue. We'll try to load the module later
1300 // when a broken dependency is fixed.
1301 _KEXTDAddPersonalitiesWithModuleToUnloadedList(kextd
, name
);
1305 error
= KERN2KEXTReturn(IOCatalogueModuleLoaded(k
->_catPort
, cname
));
1306 if ( error
!= kKEXTReturnSuccess
) {
1307 syslog(LOG_DEBUG
, "error (%d) signalling IOCatalogue.", error
);
1314 void KEXTDHangup(KEXTDRef kextd
)
1319 if ( k
->_signalsource
) {
1320 PTLockTakeLock(k
->_runloop_lock
);
1321 CFRunLoopSourceSignal(k
->_signalsource
);
1322 CFRunLoopWakeUp(k
->_runloop
);
1323 PTLockUnlock(k
->_runloop_lock
);
1327 KEXTReturn
KEXTDKernelRequest(KEXTDRef kextd
, CFStringRef name
)
1333 ret
= kKEXTReturnBadArgument
;
1339 event
= kKEXTEventModuleRequest
;
1342 context
[1] = &event
;
1343 context
[2] = (void *)name
;
1345 range
= CFRangeMake(0, CFArrayGetCount(k
->_helpers
));
1346 CFArrayApplyFunction(k
->_helpers
, range
, (CFArrayApplierFunction
)CallHelperEvent
, context
);
1347 ret
= _KEXTDProcessLoadCommand((KEXTDRef
)k
, name
);
1353 // The kernel blocks the thread which entered this
1354 // function until the kernel requests a driver to load.
1355 static void * _KEXTDKmodWait(void * info
)
1357 mach_port_t kmodPort
;
1361 request_t
* reqstruct
;
1366 return (void *)kKEXTReturnBadArgument
;
1368 kmodPort
= mach_host_self(); /* must be privileged to work */
1370 kextd
= (KEXTD
*)info
;
1371 if ( !kextd
->_kernelsource
)
1372 return (void *)kKEXTReturnBadArgument
;
1376 kmod_load_extension_cmd_t
* cmd
;
1377 mach_msg_type_number_t dataCount
;
1382 error
= kKEXTReturnSuccess
;
1384 // Wait for kernel to unblock the thread.
1385 kr
= kmod_control(kmodPort
, 0, KMOD_CNTL_GET_CMD
, &data
, &dataCount
);
1386 if ( kr
!= KERN_SUCCESS
) {
1387 syslog(LOG_ERR
, "error (%d): kmod_control.\n", kr
);
1391 cmd
= (kmod_load_extension_cmd_t
*)data
;
1397 case kIOCatalogMatchIdle
:
1400 case KMOD_LOAD_EXTENSION_PACKET
: {
1402 str
= CFStringCreateWithCString(NULL
, cmd
->name
, kCFStringEncodingNonLossyASCII
);
1408 error
= kKEXTReturnError
;
1412 if( error
== kKEXTReturnSuccess
) {
1414 reqstruct
= (request_t
*)malloc(sizeof(request_t
));
1416 memset(reqstruct
, 0, sizeof(request_t
));
1417 reqstruct
->type
= cmd
->type
;
1418 reqstruct
->kmodname
= str
;
1419 // queue up a reqest.
1420 PTLockTakeLock(kextd
->_queue_lock
);
1421 queue_enter(&kextd
->_requestQ
, reqstruct
, request_t
*, link
);
1422 PTLockUnlock(kextd
->_queue_lock
);
1424 // wake up the runloop.
1425 PTLockTakeLock(kextd
->_runloop_lock
);
1426 CFRunLoopSourceSignal(kextd
->_kernelsource
);
1427 CFRunLoopWakeUp(kextd
->_runloop
);
1428 PTLockUnlock(kextd
->_runloop_lock
);
1432 // Deallocate kernel allocated memory.
1433 vm_deallocate(mach_task_self(), (vm_address_t
)data
, dataCount
);
1434 if ( kr
!= KERN_SUCCESS
) {
1435 syslog(LOG_DEBUG
, "vm_deallocate failed. aborting.\n");
1440 return (void *)kKEXTReturnSuccess
;
1448 #include <mach/semaphore.h>
1449 #include <mach/sync_policy.h>
1450 #include <mach/bootstrap.h> /* bootstrap_ports */
1451 #undef _bootstrap_user_ /* XXX FIXME */
1452 #include <servers/bootstrap.h> /* bootstrap_look_up */
1453 #include <servers/bootstrap_defs.h>
1456 KEXTdaemonSignal(void)
1459 mach_port_t bs_port
;
1461 static boolean_t signalled
= false;
1467 printf("kextd: idle\n");
1471 kr
= task_get_bootstrap_port(mach_task_self(), &bs_port
);
1472 if( kr
!= KERN_SUCCESS
)
1473 syslog(LOG_ERR
, "task_get_bootstrap_port (%lx)\n", kr
);
1474 kr
= bootstrap_look_up(bs_port
, "kextdsignal", &sema
);
1475 if( kr
!= BOOTSTRAP_SUCCESS
)
1476 syslog(LOG_ERR
, "bootstrap_look_up(%lx)\n", kr
);
1477 kr
= semaphore_signal_all( sema
);
1478 if( kr
!= KERN_SUCCESS
)
1479 syslog(LOG_ERR
, "semaphore_signal_all(%lx)\n", kr
);
1483 static semaphore_t gDaemonSema
;
1486 KEXTdaemonWait(void)
1489 mach_timespec_t waitTime
= { 40, 0 };
1491 kr
= semaphore_timedwait( gDaemonSema
, waitTime
);
1492 if( kr
!= KERN_SUCCESS
)
1493 syslog(LOG_ERR
, "semaphore_timedwait(%lx)\n", kr
);
1497 KEXTdaemon(nochdir
, noclose
)
1498 int nochdir
, noclose
;
1501 mach_port_t bs_port
;
1504 kr
= semaphore_create( mach_task_self(), &gDaemonSema
, SYNC_POLICY_FIFO
, 0);
1505 if( kr
!= KERN_SUCCESS
)
1506 syslog(LOG_ERR
, "semaphore_create(%lx)\n", kr
);
1507 kr
= task_get_bootstrap_port(mach_task_self(), &bs_port
);
1508 if( kr
!= KERN_SUCCESS
)
1509 syslog(LOG_ERR
, "task_get_bootstrap_port(%lx)\n", kr
);
1510 kr
= bootstrap_register(bs_port
, "kextdsignal", gDaemonSema
);
1511 if( kr
!= BOOTSTRAP_SUCCESS
)
1512 syslog(LOG_ERR
, "bootstrap_look_up(%lx)\n", kr
);
1519 * Under some circumstances a CFRunLoop could have been established
1520 * in the parent process. Since the mach ports associated with the
1521 * run loop are not passed to the child process we need to start
1522 * with a clean slate.
1524 _CFRunLoopSetCurrent(NULL
);
1538 if (!noclose
&& (fd
= open(_PATH_DEVNULL
, O_RDWR
, 0)) != -1) {
1539 (void)dup2(fd
, STDIN_FILENO
);
1540 (void)dup2(fd
, STDOUT_FILENO
);
1541 (void)dup2(fd
, STDERR_FILENO
);
1550 KEXTReturn
KEXTDStartMain(KEXTDRef kextd
, Boolean beVerbose
, Boolean safeBoot
, Boolean debug
, Boolean poll
, CFIndex period
, KEXTBootlevel bootlevel
)
1552 KEXTReturn
KEXTDStartMain(KEXTDRef kextd
, Boolean beVerbose
, Boolean safeBoot
, Boolean debug
, KEXTBootlevel bootlevel
)
1555 pthread_attr_t kmod_thread_attr
;
1556 pthread_t kmod_thread
;
1561 CFRunLoopSourceContext sourceContext
;
1562 KEXTManagerBundleLoadingCallbacks bcb
= {
1564 _KEXTDAuthenticateBundleCB
,
1565 _KEXTDWillAddBundleCB
,
1566 _KEXTDWasAddedBundleCB
,
1568 _KEXTDWillRemoveBundleCB
,
1571 KEXTManagerModuleLoadingCallbacks modcbs
= {
1573 _KEXTDModuleWillLoadCB
,
1574 _KEXTDModuleWasLoadedCB
,
1575 _KEXTDModuleErrorCB
,
1579 KEXTManagerConfigsCallbacks cfgcbs
= {
1582 _KEXTDConfigWasAdded
,
1584 _KEXTDConfigWasRemoved
,
1592 syslog(LOG_ERR
, "failed to daemonize process. Aborting!\n");
1593 return kKEXTReturnError
;
1598 k
->_manager
= KEXTManagerCreate(&bcb
, &modcbs
, NULL
, &cfgcbs
, kextd
,
1599 &logErrorFunction
, &logMessageFunction
, safeBoot
, &error
);
1603 k
->_initializing
= true;
1604 k
->_catPort
= _KEXTManagerGetMachPort(k
->_manager
);
1605 k
->_beVerbose
= beVerbose
;
1607 k
->_pollFileSystem
= poll
;
1608 k
->_pollingPeriod
= period
;
1610 memset(&sourceContext
, NULL
, sizeof(CFRunLoopSourceContext
));
1612 error
= _KEXTDInitSyslog(k
);
1613 if ( error
!= kKEXTReturnSuccess
) {
1619 // FIXME: Need a way to make this synchronous!
1620 error
= KERN2KEXTReturn(IOCatalogueSendData(k
->_catPort
, kIOCatalogRemoveKernelLinker
, 0, 0));
1621 if (error
!= kKEXTReturnSuccess
) {
1622 syslog(LOG_ERR
, "couldn't remove linker from kernel (may have been removed already).",
1624 // this is only serious the first time kextd launches....
1625 // FIXME: how exactly should we handle this? Create a separate program
1626 // to trigger KLD unload?
1629 signal(SIGHUP
, signalhandler
);
1631 k
->_runloop
= CFRunLoopGetCurrent();
1632 if ( !k
->_runloop
) {
1633 syslog(LOG_ERR
, "error allocating runloop.\n");
1637 sourceContext
.version
= 0;
1638 sourceContext
.info
= k
;
1639 sourceContext
.perform
= _KEXTDSIGHUPCallout
;
1640 k
->_signalsource
= CFRunLoopSourceCreate(kCFAllocatorDefault
, 1, &sourceContext
);
1641 if ( !k
->_signalsource
) {
1642 syslog(LOG_ERR
, "error allocating signal runloop source.\n");
1645 CFRunLoopAddSource(k
->_runloop
, k
->_signalsource
, kCFRunLoopDefaultMode
);
1647 sourceContext
.perform
= _KEXTDPerform
;
1648 k
->_kernelsource
= CFRunLoopSourceCreate(kCFAllocatorDefault
, 2, &sourceContext
);
1649 if ( !k
->_kernelsource
) {
1650 syslog(LOG_ERR
, "error allocating kernel runloop source.\n");
1653 CFRunLoopAddSource(k
->_runloop
, k
->_kernelsource
, kCFRunLoopDefaultMode
);
1655 count
= CFArrayGetCount(k
->_helpers
);
1656 for ( i
= 0; i
< count
; i
++ ) {
1657 KEXTDHelper
* helper
;
1659 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
1663 if ( helper
->cbs
.DaemonDidFinishLaunching
)
1664 helper
->cbs
.DaemonDidFinishLaunching(helper
->context
);
1667 // Fork off the kmod_control message thread.
1668 pthread_attr_init(&kmod_thread_attr
);
1669 pthread_create(&kmod_thread
, &kmod_thread_attr
, _KEXTDKmodWait
, kextd
);
1670 pthread_detach(kmod_thread
);
1672 syslog(LOG_INFO
, "started.");
1674 IOCatalogueReset(k
->_catPort
, kIOCatalogResetDefault
);
1675 KEXTDScanPaths(kextd
);
1679 CFRunLoopTimerRef timer
;
1680 CFRunLoopTimerContext timerContext
= {
1681 0, kextd
, NULL
, NULL
, NULL
,
1684 timer
= CFRunLoopTimerCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent(), period
, 0, 10, _KEXTDTimerCallout
, &timerContext
);
1686 syslog(LOG_ERR
, "error allocating kmod runloop timer.\n");
1687 return kKEXTReturnError
;
1690 CFRunLoopAddTimer(k
->_runloop
, timer
, kCFRunLoopDefaultMode
);
1695 if ( (error
= _KEXTDSendPersonalities(kextd
, bootlevel
)) != kKEXTReturnSuccess
) {
1696 // KEXTError(error, CFSTR("Error sending personalities to IOCatalogue"));
1697 syslog(LOG_ERR
, "error (%d) sending personalities to IOCatalogue.", error
);
1701 k
->_initializing
= false;
1705 return kKEXTReturnSuccess
;
1708 void KEXTDScanPaths(KEXTDRef kextd
)
1719 count
= CFArrayGetCount(k
->_scanPaths
);
1720 for ( i
= 0; i
< count
; i
++ ) {
1723 url
= (CFURLRef
)CFArrayGetValueAtIndex(k
->_scanPaths
, i
);
1726 if ( k
->_beVerbose
) {
1730 cfstr
= CFURLGetString(url
);
1731 if ( CFStringGetCString(cfstr
, str
, 256, kCFStringEncodingNonLossyASCII
) ) {
1732 syslog(LOG_INFO
, "scanning: %s.", str
);
1735 error
= KEXTManagerScanPath(k
->_manager
, url
);
1736 if ( error
!= kKEXTReturnSuccess
) {
1737 syslog(LOG_ERR
, "error (%d) scanning path.\n", error
);
1743 CFIndex count
, index
;
1746 path
= CFURLCreateCopyAppendingPathComponent(
1747 kCFAllocatorDefault
,
1753 array
= (CFArrayRef
)IOURLCreatePropertyFromResource(
1754 kCFAllocatorDefault
, path
,
1755 kIOURLFileDirectoryContents
,
1761 count
= CFArrayGetCount(array
);
1762 for ( index
= 0; index
< count
; index
++ ) {
1764 file
= (CFURLRef
) CFArrayGetValueAtIndex(array
, index
);
1767 PEFExamineFile( k
->_catPort
, file
);
1772 #endif /* LOOKAPPLENDRV */
1777 void KEXTDAddScanPath(KEXTDRef kextd
, CFURLRef path
)
1779 if ( !kextd
|| !path
)
1782 if ( CFURLGetTypeID() != CFGetTypeID(path
) )
1785 CFArrayAppendValue(((KEXTD
*)kextd
)->_scanPaths
, path
);
1788 void KEXTDRegisterHelperCallbacks(KEXTDRef kextd
, KEXTDHelperCallbacks
* callbacks
)
1791 KEXTDHelper
* helper
;
1793 if ( !kextd
|| !callbacks
)
1797 helper
= (KEXTDHelper
*)malloc(sizeof(KEXTDHelper
));
1801 helper
->cbs
.HelperInitialize
= callbacks
->HelperInitialize
;
1802 helper
->cbs
.HelperFinalize
= callbacks
->HelperFinalize
;
1803 helper
->cbs
.DaemonDidFinishLaunching
= callbacks
->DaemonDidFinishLaunching
;
1804 helper
->cbs
.DaemonWillTerminate
= callbacks
->DaemonWillTerminate
;
1805 helper
->cbs
.BundleAdd
= callbacks
->BundleAdd
;
1806 helper
->cbs
.BundleRemove
= callbacks
->BundleRemove
;
1807 helper
->cbs
.EventOccurred
= callbacks
->EventOccurred
;
1808 helper
->cbs
.ModuleWillLoad
= callbacks
->ModuleWillLoad
;
1809 helper
->cbs
.ModuleWasLoaded
= callbacks
->ModuleWasLoaded
;
1810 helper
->cbs
.ModuleLoadError
= callbacks
->ModuleLoadError
;
1812 helper
->context
= helper
->cbs
.HelperInitialize(kextd
);
1814 CFArrayAppendValue(k
->_helpers
, helper
);
1817 KEXTReturn
KEXTDLoadModule(KEXTDRef kextd
, CFStringRef moduleName
)
1819 KEXTD
* k
= (KEXTD
*)kextd
;
1820 KEXTModuleRef
module;
1822 if ( !kextd
|| !moduleName
)
1823 return kKEXTReturnBadArgument
;
1825 module = KEXTManagerGetModule(k
->_manager
, moduleName
);
1827 return kKEXTReturnModuleNotFound
;
1829 return KEXTManagerLoadModule(k
->_manager
, module);