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>
21 #define TIMER_PERIOD_S 10
22 #define LOOKAPPLENDRV 1
24 static Boolean gDebug
;
25 static void KEXTdaemonSignal(void);
27 // from kernserv/queue.h now kern/queue.h
30 * A generic doubly-linked list (queue).
34 struct queue_entry
*next
; /* next element */
35 struct queue_entry
*prev
; /* previous element */
38 typedef struct queue_entry
*queue_t
;
39 typedef struct queue_entry queue_head_t
;
40 typedef struct queue_entry queue_chain_t
;
41 typedef struct queue_entry
*queue_entry_t
;
46 * Initialize the given queue.
49 * queue_t q; \* MODIFIED *\
51 #define queue_init(q) ((q)->next = (q)->prev = q)
56 * Returns the first entry in the queue,
58 * queue_entry_t queue_first(q)
61 #define queue_first(q) ((q)->next)
66 * queue_entry_t queue_next(qc)
69 #define queue_next(qc) ((qc)->next)
74 * boolean_t queue_end(q, qe)
78 #define queue_end(q, qe) ((q) == (qe))
80 #define queue_empty(q) queue_end((q), queue_first(q))
85 * void queue_enter(q, elt, type, field)
88 * <type> is what's in our queue
89 * <field> is the chain field in (*<type>)
91 #define queue_enter(head, elt, type, field) \
93 if (queue_empty((head))) { \
94 (head)->next = (queue_entry_t) elt; \
95 (head)->prev = (queue_entry_t) elt; \
96 (elt)->field.next = head; \
97 (elt)->field.prev = head; \
100 register queue_entry_t prev; \
102 prev = (head)->prev; \
103 (elt)->field.prev = prev; \
104 (elt)->field.next = head; \
105 (head)->prev = (queue_entry_t)(elt); \
106 ((type)prev)->field.next = (queue_entry_t)(elt);\
111 * Macro: queue_field [internal use only]
113 * Find the queue_chain_t (or queue_t) for the
114 * given element (thing) in the given queue (head)
116 #define queue_field(head, thing, type, field) \
117 (((head) == (thing)) ? (head) : &((type)(thing))->field)
120 * Macro: queue_remove
122 * void queue_remove(q, qe, type, field)
123 * arguments as in queue_enter
125 #define queue_remove(head, elt, type, field) \
127 register queue_entry_t next, prev; \
129 next = (elt)->field.next; \
130 prev = (elt)->field.prev; \
132 queue_field((head), next, type, field)->prev = prev; \
133 queue_field((head), prev, type, field)->next = next; \
137 typedef struct _KEXTD
{
139 CFRunLoopRef _runloop
;
140 CFRunLoopSourceRef _signalsource
;
141 CFRunLoopSourceRef _kernelsource
;
142 CFMutableArrayRef _scanPaths
;
143 CFMutableArrayRef _unloaded
;
144 CFMutableArrayRef _helpers
;
145 queue_head_t _requestQ
;
146 PTLockRef _runloop_lock
;
147 PTLockRef _queue_lock
;
148 KEXTManagerRef _manager
;
149 mach_port_t _catPort
;
150 Boolean _initializing
;
153 Boolean _pollFileSystem
;
154 CFIndex _pollingPeriod
;
158 typedef struct _request
{
160 CFStringRef kmodname
;
161 CFStringRef kmodvers
;
165 typedef struct _KEXTDHelper
{
167 KEXTDHelperCallbacks cbs
;
170 CFDictionaryRef
_KEXTPersonalityGetProperties(KEXTPersonalityRef personality
);
171 static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd
, CFStringRef parentKey
);
172 static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd
, CFStringRef modName
);
173 const void * _KEXTPersonalityRetainCB(CFAllocatorRef allocator
, const void *ptr
);
174 void _KEXTPersonalityReleaseCB(CFAllocatorRef allocator
, const void *ptr
);
175 Boolean
_KEXTPersonalityEqualCB(const void *ptr1
, const void *ptr2
);
176 mach_port_t
_KEXTManagerGetMachPort(KEXTManagerRef manager
);
179 kmod_control(host_t host
,
181 kmod_control_flavor_t flavor
,
183 mach_msg_type_number_t
*dataCount
);
185 extern KEXTReturn
KERN2KEXTReturn(kern_return_t kr
);
187 static KEXTDRef _kextd
= NULL
;
189 static void logErrorFunction(const char * string
)
191 syslog(LOG_ERR
, string
);
195 static void logMessageFunction(const char * string
)
197 syslog(LOG_INFO
, string
);
202 static void ArrayMergeFunc(const void * val
, void * context
)
204 CFMutableArrayRef array
;
208 CFArrayAppendValue(array
, val
);
211 static void CFArrayMergeArray(CFMutableArrayRef array1
, CFArrayRef array2
)
215 if ( !array1
|| !array2
) {
219 range
= CFRangeMake(0, CFArrayGetCount(array2
));
220 CFArrayApplyFunction(array2
, range
, ArrayMergeFunc
, array1
);
223 static void CallHelperEvent(void * val
, void * context
[])
227 KEXTDHelper
* helper
;
232 event
= *(KEXTEvent
*)context
[1];
235 if ( helper
&& context
&& helper
->cbs
.EventOccurred
) {
236 helper
->cbs
.EventOccurred(event
, item
, kextd
);
240 static void ConfigsForBundles(const void * var
, void * context
[])
242 KEXTManagerRef manager
;
243 KEXTBundleRef bundle
;
244 CFMutableArrayRef array
;
247 bundle
= (KEXTBundleRef
)var
;
249 manager
= context
[0];
252 configs
= KEXTManagerCopyConfigsForBundle(manager
, bundle
);
254 CFArrayMergeArray(array
, configs
);
260 static inline KEXTBootlevel
_KEXTDGetBootlevel(KEXTPersonalityRef personality
)
262 KEXTBootlevel bootlevel
;
263 CFStringRef priority
;
264 CFStringRef category
;
266 bootlevel
= kKEXTBootlevelExempt
;
267 priority
= KEXTPersonalityGetProperty(personality
, CFSTR("BootPriority"));
269 category
= KEXTPersonalityGetProperty(personality
, CFSTR("DeviceCategory"));
271 return kKEXTBootlevelExempt
;
274 if ( CFEqual(category
, CFSTR("System Controller")) ) {
275 bootlevel
= kKEXTBootlevelRequired
;
277 else if ( CFEqual(category
, CFSTR("Bus Controller")) ) {
278 bootlevel
= kKEXTBootlevelFlexible
;
280 else if ( CFEqual(category
, CFSTR("Keyboard")) ) {
281 bootlevel
= kKEXTBootlevelSingleUser
;
283 else if ( CFEqual(category
, CFSTR("Input Device")) ) {
284 bootlevel
= kKEXTBootlevelExempt
;
286 else if ( CFEqual(category
, CFSTR("Pointing Device")) ) {
287 bootlevel
= kKEXTBootlevelExempt
;
289 else if ( CFEqual(category
, CFSTR("Mouse")) ) {
290 bootlevel
= kKEXTBootlevelRecovery
;
292 else if ( CFEqual(category
, CFSTR("Graphics Controller")) ) {
293 bootlevel
= kKEXTBootlevelRecovery
;
295 else if ( CFEqual(category
, CFSTR("Graphics Accelerator")) ) {
296 bootlevel
= kKEXTBootlevelExempt
;
298 else if ( CFEqual(category
, CFSTR("Video Device")) ) {
299 bootlevel
= kKEXTBootlevelExempt
;
301 else if ( CFEqual(category
, CFSTR("Disk Controller")) ) {
302 bootlevel
= kKEXTBootlevelFlexible
;
304 else if ( CFEqual(category
, CFSTR("Disk Media")) ) {
305 bootlevel
= kKEXTBootlevelFlexible
;
307 else if ( CFEqual(category
, CFSTR("Audio Controller")) ) {
308 bootlevel
= kKEXTBootlevelExempt
;
310 else if ( CFEqual(category
, CFSTR("Sound Device")) ) {
311 bootlevel
= kKEXTBootlevelExempt
;
313 else if ( CFEqual(category
, CFSTR("Network Controller")) ) {
314 bootlevel
= kKEXTBootlevelFlexible
;
320 if ( CFEqual(priority
, CFSTR("Exempt")) ) {
321 bootlevel
= kKEXTBootlevelExempt
;
323 else if ( CFEqual(priority
, CFSTR("Recovery")) ) {
324 bootlevel
= kKEXTBootlevelRecovery
;
326 else if ( CFEqual(priority
, CFSTR("Special")) ) {
327 bootlevel
= kKEXTBootlevelSingleUser
;
329 else if ( CFEqual(priority
, CFSTR("Flexible")) ) {
330 bootlevel
= kKEXTBootlevelFlexible
;
332 else if ( CFEqual(priority
, CFSTR("Required")) ) {
333 bootlevel
= kKEXTBootlevelRequired
;
339 static void ArrayAddToLoadList(void * val
, void * context
[])
341 KEXTPersonalityRef person
;
342 KEXTBootlevel bootlevel
;
343 CFMutableArrayRef unloaded
;
344 CFMutableArrayRef loadlist
;
348 if ( !val
|| !context
) {
354 unloaded
= context
[0];
355 loadlist
= context
[1];
356 bootlevel
= *(KEXTBootlevel
*)context
[2];
358 if ( bootlevel
!= kKEXTBootlevelNormal
) {
359 doAdd
= _KEXTDGetBootlevel(person
) & bootlevel
;
363 range
= CFRangeMake(0, CFArrayGetCount(loadlist
));
364 if ( !CFArrayContainsValue(loadlist
, range
, person
) ) {
365 CFArrayAppendValue(loadlist
, person
);
369 range
= CFRangeMake(0, CFArrayGetCount(unloaded
));
370 if ( !CFArrayContainsValue(unloaded
, range
, person
) ) {
371 CFArrayAppendValue(unloaded
, person
);
373 CFArrayAppendValue(unloaded
, person
);
377 static void signalhandler(int signal
)
379 if ( _kextd
&& (signal
== SIGHUP
) ) {
384 static KEXTReturn
_KEXTDInitSyslog(KEXTD
* k
)
386 openlog("kextd", LOG_PID
| LOG_NDELAY
, LOG_DAEMON
);
388 return kKEXTReturnSuccess
;
391 // This is called when authenticating a new bundle.
392 static KEXTReturn
_KEXTDAuthenticateBundleCB(CFURLRef url
, void * context
)
396 ret
= KEXTManagerAuthenticateURL(url
);
398 KEXTD
* k
= (KEXTD
*)context
;
400 CFStringRef urlString
;
405 urlString
= CFURLGetString(url
);
406 if ( CFStringGetCString(urlString
, name
, 256, kCFStringEncodingNonLossyASCII
) )
407 syslog(LOG_ERR
, "%s failed authentication.", name
);
409 event
= kKEXTEventBundleAuthenticationFailed
;
411 context2
[1] = &event
;
412 context2
[2] = (void *)url
;
414 range
= CFRangeMake(0, CFArrayGetCount(k
->_helpers
));
415 CFArrayApplyFunction(k
->_helpers
, range
, (CFArrayApplierFunction
)CallHelperEvent
, context2
);
421 // This is called when a new bundle has been found.
422 static Boolean
_KEXTDWillAddBundleCB(KEXTManagerRef manager
, KEXTBundleRef bundle
, void * context
)
424 KEXTD
* k
= (KEXTD
*)context
;
431 count
= CFArrayGetCount(k
->_helpers
);
432 for ( i
= 0; i
< count
; i
++ ) {
433 KEXTDHelper
* helper
;
435 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
439 if ( helper
->cbs
.BundleAdd
) {
440 ret
= helper
->cbs
.BundleAdd(bundle
, helper
->context
);
446 url
= KEXTBundleCopyURL(bundle
);
448 if ( k
->_beVerbose
&& ret
) {
452 cfstr
= CFURLGetString(url
);
453 if ( CFStringGetCString(cfstr
, str
, 256, kCFStringEncodingNonLossyASCII
) ) {
454 syslog(LOG_INFO
, "%s added.", str
);
458 // Remove any unloaded personalities from look-aside queue
459 // which are in this bundle.
460 _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef
)k
, KEXTBundleGetPrimaryKey(bundle
));
467 // This is called after a bundle has been added to the KEXTManager database.
468 static void _KEXTDWasAddedBundleCB(KEXTManagerRef manager
, KEXTBundleRef bundle
, void * context
)
471 KEXTBootlevel bootlevel
;
472 CFMutableArrayRef toload
;
479 k
= (KEXTD
*)context
;
480 if ( k
->_initializing
) {
484 bootlevel
= kKEXTBootlevelNormal
;
486 toload
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
491 context2
[0] = k
->_unloaded
;
492 context2
[1] = toload
;
493 context2
[2] = &bootlevel
;
496 // Create a list of all personalities and configurations
497 // and send it to the catalogue. First, get the unloaded
499 unloaded
= CFArrayCreateCopy(kCFAllocatorDefault
, k
->_unloaded
);
500 CFArrayRemoveAllValues(k
->_unloaded
);
502 range
= CFRangeMake(0, CFArrayGetCount(unloaded
));
503 CFArrayApplyFunction(unloaded
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context2
);
507 persons
= KEXTManagerCopyPersonalitiesForBundle(manager
, bundle
);
509 range
= CFRangeMake(0, CFArrayGetCount(persons
));
510 CFArrayApplyFunction(persons
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context2
);
514 configs
= KEXTManagerCopyConfigsForBundle(manager
, bundle
);
516 range
= CFRangeMake(0, CFArrayGetCount(configs
));
517 CFArrayApplyFunction(configs
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context2
);
522 // Send the list to IOCatalogue.
523 if ( CFArrayGetCount(toload
) > 0 ) {
524 KEXTManagerLoadPersonalities(k
->_manager
, toload
);
530 static void _KEXTDConfigWasAdded(KEXTManagerRef manager
, KEXTConfigRef config
, void * context
)
534 if ( !manager
|| !config
|| !context
) {
540 if ( !kextd
->_initializing
) {
541 CFStringRef primaryKey
;
545 primaryKey
= CFDictionaryGetValue(config
, CFSTR("ParentKey"));
550 if ( !KEXTManagerGetBundle(manager
, primaryKey
) ) {
555 array
= CFArrayCreate(kCFAllocatorDefault
, vals
, 1, &kCFTypeArrayCallBacks
);
557 KEXTManagerLoadPersonalities(manager
, array
);
563 static void _KEXTDConfigWasRemoved(KEXTManagerRef manager
, KEXTConfigRef config
, void * context
)
567 if ( !manager
|| !config
|| !context
) {
573 if ( !kextd
->_initializing
) {
574 KEXTManagerUnloadPersonality(manager
, config
);
578 static void ArrayUnloadPersonality(const void * val
, void * context
)
580 KEXTManagerRef manager
;
581 KEXTPersonalityRef person
;
584 person
= (KEXTPersonalityRef
)val
;
586 KEXTManagerUnloadPersonality(manager
, person
);
589 // This is called when a bundle has been removed from the filesystem.
590 static Boolean
_KEXTDWillRemoveBundleCB(KEXTManagerRef manager
, KEXTBundleRef bundle
, void * context
)
592 KEXTD
* k
= (KEXTD
*)context
;
598 count
= CFArrayGetCount(k
->_helpers
);
599 for ( i
= 0; i
< count
; i
++ ) {
600 KEXTDHelper
* helper
;
602 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
606 if ( helper
->cbs
.BundleRemove
) {
607 ret
= helper
->cbs
.BundleRemove(bundle
, helper
->context
);
614 CFArrayRef personalities
;
619 // XXX -- svail: might want to unload bundle personalities
620 // from IOCatalogue and maybe unload the modules if possible.
621 // If a module is present with active personalities, don't remove
622 // bundle from database.
623 personalities
= KEXTManagerCopyPersonalitiesForBundle(manager
, bundle
);
624 if ( personalities
) {
625 range
= CFRangeMake(0, CFArrayGetCount(personalities
));
626 CFArrayApplyFunction(personalities
, range
, ArrayUnloadPersonality
, manager
);
627 CFRelease(personalities
);
630 configs
= KEXTManagerCopyConfigsForBundle(manager
, bundle
);
632 range
= CFRangeMake(0, CFArrayGetCount(configs
));
633 CFArrayApplyFunction(configs
, range
, ArrayUnloadPersonality
, manager
);
637 url
= KEXTBundleCopyURL(bundle
);
639 if ( k
->_beVerbose
&& ret
) {
643 cfstr
= CFURLGetString(url
);
644 if ( CFStringGetCString(cfstr
, str
, 256, kCFStringEncodingNonLossyASCII
) ) {
645 syslog(LOG_INFO
, "%s removed.", str
);
649 // Remove any unloaded personalities from the unloaded
650 // list if they are associated with the bundle.
652 _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef
)k
, KEXTBundleGetPrimaryKey(bundle
));
660 // This is called before KEXT loads a KMOD.
661 static Boolean
_KEXTDModuleWillLoadCB(KEXTManagerRef manager
, KEXTModuleRef
module, void * context
)
668 k
= (KEXTD
*)context
;
671 count
= CFArrayGetCount(k
->_helpers
);
672 for ( i
= 0; i
< count
; i
++ ) {
673 KEXTDHelper
* helper
;
675 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
679 if ( helper
->cbs
.ModuleWillLoad
) {
680 if ( !helper
->cbs
.ModuleWillLoad(module, helper
->context
) ) {
688 CFStringRef moduleName
;
691 moduleName
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
695 if ( !CFStringGetCString(moduleName
, name
, 256, kCFStringEncodingNonLossyASCII
) )
698 syslog(LOG_INFO
, "loading module: %s.\n", name
);
704 // This is called when a module has been successfully loaded.
705 static void _KEXTDModuleWasLoadedCB(KEXTManagerRef manager
, KEXTModuleRef
module, void * context
)
709 CFMutableArrayRef send
;
713 k
= (KEXTD
*)context
;
715 count
= CFArrayGetCount(k
->_helpers
);
716 for ( i
= 0; i
< count
; i
++ ) {
717 KEXTDHelper
* helper
;
719 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
723 if ( helper
->cbs
.ModuleWasLoaded
) {
724 helper
->cbs
.ModuleWasLoaded(module, helper
->context
);
728 // Remove personalities from unloaded list if they
729 // are associated with the module and pass them to the
730 // kernel just in case they aren't there yet.
732 array
= CFArrayCreateCopy(kCFAllocatorDefault
, k
->_unloaded
);
733 send
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
734 count
= CFArrayGetCount(array
);
736 CFArrayRemoveAllValues(k
->_unloaded
);
738 for ( i
= 0; i
< count
; i
++ ) {
739 KEXTPersonalityRef person
;
740 CFStringRef moduleID
;
741 CFStringRef personalityBundleID
;
743 person
= (KEXTPersonalityRef
)CFArrayGetValueAtIndex(array
, i
);
748 moduleID
= KEXTPersonalityGetProperty(person
, CFSTR("CFBundleIdentifier"));
753 personalityBundleID
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
754 if ( !personalityBundleID
) {
758 if ( !CFEqual(moduleID
, personalityBundleID
) ) {
759 CFArrayAppendValue(k
->_unloaded
, person
);
762 CFArrayAppendValue(send
, person
);
766 if ( CFArrayGetCount(send
) > 0 ) {
767 KEXTManagerLoadPersonalities(k
->_manager
, send
);
773 if ( k
->_beVerbose
) {
774 CFStringRef moduleName
;
777 moduleName
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
781 if ( !CFStringGetCString(moduleName
, name
, 256, kCFStringEncodingNonLossyASCII
) )
784 syslog(LOG_INFO
, "loaded module: %s\n", name
);
788 static KEXTReturn
_KEXTDModuleErrorCB(KEXTManagerRef manager
, KEXTModuleRef
module, KEXTReturn error
, void * context
)
795 CFStringRef moduleName
;
797 k
= (KEXTD
*)context
;
799 moduleName
= KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
801 return kKEXTReturnPropertyNotFound
;
803 if ( !CFStringGetCString(moduleName
, name
, 256, kCFStringEncodingNonLossyASCII
) )
804 return kKEXTReturnNoMemory
;
806 if ( error
== kKEXTReturnModuleAlreadyLoaded
) {
808 syslog(LOG_INFO
, "module already loaded: %s.\n", name
);
814 count
= CFArrayGetCount(k
->_helpers
);
815 for ( i
= 0; i
< count
; i
++ ) {
816 KEXTDHelper
* helper
;
818 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
822 if ( helper
->cbs
.ModuleLoadError
) {
823 ret
= helper
->cbs
.ModuleLoadError(module, error
, helper
->context
);
824 if ( ret
== kKEXTReturnSuccess
) {
829 if ( ret
== kKEXTReturnSuccess
)
830 return kKEXTReturnSuccess
;
832 syslog(LOG_ERR
, "error (%d) loading module: %s.\n", ret
, name
);
838 static void _KEXTDTimerCallout(CFRunLoopTimerRef timer
, void * info
)
840 KEXTDScanPaths((KEXTDRef
)info
);
844 static void _KEXTDSIGHUPCallout(void * info
)
849 if ( k
->_beVerbose
) {
850 syslog(LOG_INFO
, "user requests directory re-scan.");
853 // Check for new or removed bundles and do the appropriate
855 KEXTDScanPaths((KEXTDRef
)info
);
857 // Make sure we try to load the unloaded personalities
858 // It's probably overkill to do this here.
859 if ( CFArrayGetCount(k
->_unloaded
) > 0 ) {
860 KEXTManagerLoadPersonalities(k
->_manager
, k
->_unloaded
);
864 // This function is called when IOCatalogue requests a driver module.
865 static void _KEXTDPerform(void * info
)
872 // KEXTDScanPaths((KEXTDRef)k);
874 PTLockTakeLock(k
->_queue_lock
);
875 while ( !queue_empty(&k
->_requestQ
) ) {
876 request_t
* reqstruct
;
879 // Dequeue the kernel request structure.
880 reqstruct
= (request_t
*)queue_first(&k
->_requestQ
);
881 queue_remove(&k
->_requestQ
, reqstruct
, request_t
*, link
);
882 PTLockUnlock(k
->_queue_lock
);
884 type
= reqstruct
->type
;
885 name
= reqstruct
->kmodname
;
888 if( type
== kIOCatalogMatchIdle
) {
890 mach_timespec_t timeout
= { 10, 0 };
891 IOKitWaitQuiet( k
->_catPort
, &timeout
);
896 if ( k
->_beVerbose
) {
899 if ( CFStringGetCString(name
, modname
, 256, kCFStringEncodingNonLossyASCII
) ) {
900 syslog(LOG_INFO
, "kernel requests module: %s", modname
);
904 KEXTDKernelRequest((KEXTDRef
)k
, name
);
908 PTLockTakeLock(k
->_queue_lock
);
910 PTLockUnlock(k
->_queue_lock
);
913 KEXTDRef
KEXTDCreate(CFArrayRef scanPaths
, KEXTReturn
* error
)
917 kextd
= (KEXTD
*)malloc(sizeof(KEXTD
));
919 *error
= kKEXTReturnNoMemory
;
922 memset(kextd
, 0, sizeof(KEXTD
));
924 kextd
->_queue_lock
= PTLockCreate();
925 kextd
->_runloop_lock
= PTLockCreate();
927 kextd
->_helpers
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
928 kextd
->_unloaded
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
929 kextd
->_scanPaths
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
930 if ( !kextd
->_scanPaths
|| !kextd
->_unloaded
|| !kextd
->_helpers
) {
931 *error
= kKEXTReturnNoMemory
;
932 KEXTDFree((KEXTDRef
)kextd
);
936 kextd
->_initializing
= true;
937 kextd
->_beVerbose
= false;
939 kextd
->_pollFileSystem
= false;
940 kextd
->_pollingPeriod
= TIMER_PERIOD_S
;
943 queue_init(&kextd
->_requestQ
);
950 count
= CFArrayGetCount(scanPaths
);
951 for ( i
= 0; i
< count
; i
++ ) {
952 url
= (CFURLRef
)CFArrayGetValueAtIndex(scanPaths
, i
);
953 KEXTDAddScanPath((KEXTDRef
)kextd
, url
);
957 return (KEXTDRef
)kextd
;
960 static void _KEXTDFlushHelpers(KEXTDRef kextd
)
967 count
= CFArrayGetCount(k
->_helpers
);
968 for ( i
= 0; i
< count
; i
++ ) {
969 KEXTDHelper
* helper
;
971 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
975 if ( helper
->cbs
.DaemonWillTerminate
)
976 helper
->cbs
.DaemonWillTerminate(helper
->context
);
977 if ( helper
->cbs
.HelperFinalize
)
978 helper
->cbs
.HelperFinalize(helper
->context
);
984 void KEXTDFree(KEXTDRef kextd
)
990 syslog(LOG_DEBUG
, "terminating.");
993 _KEXTDFlushHelpers(kextd
);
994 CFRelease(k
->_helpers
);
996 if ( k
->_kernelsource
)
997 CFRelease(k
->_kernelsource
);
998 if ( k
->_signalsource
)
999 CFRelease(k
->_signalsource
);
1001 CFRelease(k
->_runloop
);
1002 if ( k
->_scanPaths
)
1003 CFRelease(k
->_scanPaths
);
1005 KEXTManagerRelease(k
->_manager
);
1006 if ( k
->_queue_lock
)
1007 PTLockFree(k
->_queue_lock
);
1008 if ( k
->_runloop_lock
)
1009 PTLockFree(k
->_runloop_lock
);
1016 void KEXTDReset(KEXTDRef kextd
)
1022 syslog(LOG_DEBUG
, "resetting.");
1025 count
= CFArrayGetCount(k
->_helpers
);
1026 for ( i
= 0; i
< count
; i
++ ) {
1027 KEXTDHelper
* helper
;
1029 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
1033 if ( helper
->cbs
.EventOccurred
)
1034 helper
->cbs
.EventOccurred(kKEXTEventReset
, NULL
, helper
->context
);
1038 KEXTManagerReset(k
->_manager
);
1040 KEXTDScanPaths(kextd
);
1043 static KEXTReturn
_KEXTDSendDataToCatalog(KEXTDRef kextd
, int flag
, CFTypeRef obj
)
1053 error
= kKEXTReturnSuccess
;
1055 data
= IOCFSerialize(obj
, 0);
1057 return kKEXTReturnSerializationError
;
1060 len
= CFDataGetLength(data
);
1061 ptr
= (void *)CFDataGetBytePtr(data
);
1062 error
= KERN2KEXTReturn(IOCatalogueSendData(k
->_catPort
, flag
, ptr
, len
));
1068 static KEXTReturn
_KEXTDSendPersonalities(KEXTDRef kextd
, KEXTBootlevel bootlevel
)
1073 CFMutableArrayRef configs
;
1074 CFMutableArrayRef toload
;
1078 error
= kKEXTReturnSuccess
;
1080 toload
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1082 return kKEXTReturnNoMemory
;
1086 bundles
= KEXTManagerCopyAllBundles(((KEXTD
*)kextd
)->_manager
);
1088 configs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1092 return kKEXTReturnNoMemory
;
1095 context
[0] = ((KEXTD
*)kextd
)->_manager
;
1096 context
[1] = configs
;
1098 range
= CFRangeMake(0, CFArrayGetCount(bundles
));
1099 CFArrayApplyFunction(bundles
, range
, (CFArrayApplierFunction
)ConfigsForBundles
, context
);
1103 // Filter out any inappropriate personalities given the bootlevel of the
1104 // system. Store these personalities in the _unloaded list, they will be
1105 // loaded when a SIGHUP is sent to the daemon.
1106 context
[0] = ((KEXTD
*)kextd
)->_unloaded
;
1107 context
[1] = toload
;
1108 context
[2] = &bootlevel
;
1110 persons
= KEXTManagerCopyAllPersonalities(((KEXTD
*)kextd
)->_manager
);
1112 range
= CFRangeMake(0, CFArrayGetCount(persons
));
1113 CFArrayApplyFunction(persons
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context
);
1118 range
= CFRangeMake(0, CFArrayGetCount(configs
));
1119 CFArrayApplyFunction(configs
, range
, (CFArrayApplierFunction
)ArrayAddToLoadList
, context
);
1123 if ( CFArrayGetCount(toload
) > 0 ) {
1124 error
= KEXTManagerLoadPersonalities(((KEXTD
*)kextd
)->_manager
, toload
);
1135 static inline Boolean
_KEXTPersonalityNeedsModule(KEXTPersonalityRef person
, CFStringRef modName
)
1139 name
= KEXTPersonalityGetProperty(person
, CFSTR("CFBundleIdentifier"));
1144 return CFEqual(name
, modName
);
1147 // If a module fails to load for some reason, then put the
1148 // personalities associated with this module in a look-aside
1149 // buffer, we'll try loading them later, maybe when a broken
1150 // dependency is fixed.
1151 static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd
, CFStringRef modName
)
1163 array
= KEXTManagerCopyAllEntities(k
->_manager
);
1167 // Find personalities which depend on this module.
1168 count
= CFArrayGetCount(array
);
1169 for ( i
= 0; i
< count
; i
++ ) {
1173 KEXTEntityRef entity
;
1175 entity
= (KEXTEntityRef
)CFArrayGetValueAtIndex(array
, i
);
1179 type
= KEXTManagerGetEntityType(entity
);
1180 if ( !type
|| !CFEqual(type
, KEXTPersonalityGetEntityType()) ) {
1184 name
= KEXTPersonalityGetProperty(entity
, CFSTR("CFBundleIdentifier"));
1185 if ( !name
|| !CFEqual(modName
, name
) ) {
1189 range
= CFRangeMake(0, CFArrayGetCount(k
->_unloaded
));
1191 if ( CFArrayContainsValue(k
->_unloaded
, range
, entity
) ) {
1195 CFArrayAppendValue(k
->_unloaded
, entity
);
1197 if ( !k
->_initializing
) {
1198 KEXTManagerUnloadPersonality(k
->_manager
, entity
);
1205 static void RemovePersonsWithParentFromUnloadedList(void * val
, void * context
[])
1207 KEXTPersonalityRef person
;
1208 CFMutableArrayRef unloaded
;
1209 CFStringRef parentKey
;
1212 if ( !val
|| !context
) {
1217 unloaded
= context
[0];
1218 parentKey
= context
[1];
1220 key
= CFDictionaryGetValue(person
, CFSTR("ParentKey"));
1221 if ( !parentKey
|| !key
|| CFEqual(parentKey
, key
) ) {
1225 CFArrayAppendValue(unloaded
, person
);
1228 // Remove personalities from the unloaded list if their
1229 // associated bundle is removed.
1230 static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd
, CFStringRef parentKey
)
1232 CFMutableArrayRef unloaded
;
1237 unloaded
= ((KEXTD
*)kextd
)->_unloaded
;
1239 array
= CFArrayCreateCopy(kCFAllocatorDefault
, unloaded
);
1240 CFArrayRemoveAllValues(unloaded
);
1242 context
[0] = unloaded
;
1243 context
[1] = (void *)parentKey
;
1245 range
= CFRangeMake(0, CFArrayGetCount(array
));
1246 CFArrayApplyFunction(
1249 (CFArrayApplierFunction
)RemovePersonsWithParentFromUnloadedList
,
1255 static KEXTReturn
_KEXTDProcessLoadCommand(KEXTDRef kextd
, CFStringRef name
)
1262 if ( !CFStringGetCString(name
, cname
, 256, kCFStringEncodingNonLossyASCII
) ) {
1263 error
= kKEXTReturnNoMemory
;
1267 error
= KEXTDLoadModule(kextd
, name
);
1268 if ( error
!= kKEXTReturnSuccess
&&
1269 error
!= kKEXTReturnModuleAlreadyLoaded
) {
1270 CFDictionaryRef matchingDict
;
1271 const void * keys
[1];
1272 const void * vals
[1];
1275 keys
[0] = CFSTR("CFBundleIdentifier");
1279 error
= kKEXTReturnPropertyNotFound
;
1283 matchingDict
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, vals
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1284 if ( !matchingDict
) {
1285 error
= kKEXTReturnNoMemory
;
1289 error
= _KEXTDSendDataToCatalog(kextd
, kIOCatalogRemoveDrivers
, matchingDict
);
1290 CFRelease(matchingDict
);
1291 if ( error
!= kKEXTReturnSuccess
) {
1292 syslog(LOG_DEBUG
, "error ( %d) removing drivers.", error
);
1297 // Place personalities which failed to load this module onto
1298 // a look-aside queue. We'll try to load the module later
1299 // when a broken dependency is fixed.
1300 _KEXTDAddPersonalitiesWithModuleToUnloadedList(kextd
, name
);
1304 error
= KERN2KEXTReturn(IOCatalogueModuleLoaded(k
->_catPort
, cname
));
1305 if ( error
!= kKEXTReturnSuccess
) {
1306 syslog(LOG_DEBUG
, "error (%d) signalling IOCatalogue.", error
);
1313 void KEXTDHangup(KEXTDRef kextd
)
1318 if ( k
->_signalsource
) {
1319 PTLockTakeLock(k
->_runloop_lock
);
1320 CFRunLoopSourceSignal(k
->_signalsource
);
1321 CFRunLoopWakeUp(k
->_runloop
);
1322 PTLockUnlock(k
->_runloop_lock
);
1326 KEXTReturn
KEXTDKernelRequest(KEXTDRef kextd
, CFStringRef name
)
1332 ret
= kKEXTReturnBadArgument
;
1338 event
= kKEXTEventModuleRequest
;
1341 context
[1] = &event
;
1342 context
[2] = (void *)name
;
1344 range
= CFRangeMake(0, CFArrayGetCount(k
->_helpers
));
1345 CFArrayApplyFunction(k
->_helpers
, range
, (CFArrayApplierFunction
)CallHelperEvent
, context
);
1346 ret
= _KEXTDProcessLoadCommand((KEXTDRef
)k
, name
);
1352 // The kernel blocks the thread which entered this
1353 // function until the kernel requests a driver to load.
1354 static void * _KEXTDKmodWait(void * info
)
1356 mach_port_t kmodPort
;
1360 request_t
* reqstruct
;
1365 return (void *)kKEXTReturnBadArgument
;
1367 kmodPort
= mach_host_self(); /* must be privileged to work */
1369 kextd
= (KEXTD
*)info
;
1370 if ( !kextd
->_kernelsource
)
1371 return (void *)kKEXTReturnBadArgument
;
1375 kmod_load_extension_cmd_t
* cmd
;
1376 mach_msg_type_number_t dataCount
;
1381 error
= kKEXTReturnSuccess
;
1383 // Wait for kernel to unblock the thread.
1384 kr
= kmod_control(kmodPort
, 0, KMOD_CNTL_GET_CMD
, &data
, &dataCount
);
1385 if ( kr
!= KERN_SUCCESS
) {
1386 syslog(LOG_ERR
, "error (%d): kmod_control.\n", kr
);
1390 cmd
= (kmod_load_extension_cmd_t
*)data
;
1396 case kIOCatalogMatchIdle
:
1399 case KMOD_LOAD_EXTENSION_PACKET
: {
1401 str
= CFStringCreateWithCString(NULL
, cmd
->name
, kCFStringEncodingNonLossyASCII
);
1407 error
= kKEXTReturnError
;
1411 if( error
== kKEXTReturnSuccess
) {
1413 reqstruct
= (request_t
*)malloc(sizeof(request_t
));
1415 memset(reqstruct
, 0, sizeof(request_t
));
1416 reqstruct
->type
= cmd
->type
;
1417 reqstruct
->kmodname
= str
;
1418 // queue up a reqest.
1419 PTLockTakeLock(kextd
->_queue_lock
);
1420 queue_enter(&kextd
->_requestQ
, reqstruct
, request_t
*, link
);
1421 PTLockUnlock(kextd
->_queue_lock
);
1423 // wake up the runloop.
1424 PTLockTakeLock(kextd
->_runloop_lock
);
1425 CFRunLoopSourceSignal(kextd
->_kernelsource
);
1426 CFRunLoopWakeUp(kextd
->_runloop
);
1427 PTLockUnlock(kextd
->_runloop_lock
);
1431 // Deallocate kernel allocated memory.
1432 vm_deallocate(mach_task_self(), (vm_address_t
)data
, dataCount
);
1433 if ( kr
!= KERN_SUCCESS
) {
1434 syslog(LOG_DEBUG
, "vm_deallocate failed. aborting.\n");
1439 return (void *)kKEXTReturnSuccess
;
1447 #include <mach/semaphore.h>
1448 #include <mach/sync_policy.h>
1449 #include <mach/bootstrap.h> /* bootstrap_ports */
1450 #undef _bootstrap_user_ /* XXX FIXME */
1451 #include <servers/bootstrap.h> /* bootstrap_look_up */
1452 #include <servers/bootstrap_defs.h>
1455 KEXTdaemonSignal(void)
1458 mach_port_t bs_port
;
1460 static boolean_t signalled
= false;
1466 printf("kextd: idle\n");
1470 kr
= task_get_bootstrap_port(mach_task_self(), &bs_port
);
1471 if( kr
!= KERN_SUCCESS
)
1472 syslog(LOG_ERR
, "task_get_bootstrap_port (%lx)\n", kr
);
1473 kr
= bootstrap_look_up(bs_port
, "kextdsignal", &sema
);
1474 if( kr
!= BOOTSTRAP_SUCCESS
)
1475 syslog(LOG_ERR
, "bootstrap_look_up(%lx)\n", kr
);
1476 kr
= semaphore_signal_all( sema
);
1477 if( kr
!= KERN_SUCCESS
)
1478 syslog(LOG_ERR
, "semaphore_signal_all(%lx)\n", kr
);
1482 static semaphore_t gDaemonSema
;
1485 KEXTdaemonWait(void)
1488 mach_timespec_t waitTime
= { 40, 0 };
1490 kr
= semaphore_timedwait( gDaemonSema
, waitTime
);
1491 if( kr
!= KERN_SUCCESS
)
1492 syslog(LOG_ERR
, "semaphore_timedwait(%lx)\n", kr
);
1496 KEXTdaemon(nochdir
, noclose
)
1497 int nochdir
, noclose
;
1500 mach_port_t bs_port
;
1503 kr
= semaphore_create( mach_task_self(), &gDaemonSema
, SYNC_POLICY_FIFO
, 0);
1504 if( kr
!= KERN_SUCCESS
)
1505 syslog(LOG_ERR
, "semaphore_create(%lx)\n", kr
);
1506 kr
= task_get_bootstrap_port(mach_task_self(), &bs_port
);
1507 if( kr
!= KERN_SUCCESS
)
1508 syslog(LOG_ERR
, "task_get_bootstrap_port(%lx)\n", kr
);
1509 kr
= bootstrap_register(bs_port
, "kextdsignal", gDaemonSema
);
1510 if( kr
!= BOOTSTRAP_SUCCESS
)
1511 syslog(LOG_ERR
, "bootstrap_look_up(%lx)\n", kr
);
1529 if (!noclose
&& (fd
= open(_PATH_DEVNULL
, O_RDWR
, 0)) != -1) {
1530 (void)dup2(fd
, STDIN_FILENO
);
1531 (void)dup2(fd
, STDOUT_FILENO
);
1532 (void)dup2(fd
, STDERR_FILENO
);
1541 KEXTReturn
KEXTDStartMain(KEXTDRef kextd
, Boolean beVerbose
, Boolean safeBoot
, Boolean debug
, Boolean poll
, CFIndex period
, KEXTBootlevel bootlevel
)
1543 KEXTReturn
KEXTDStartMain(KEXTDRef kextd
, Boolean beVerbose
, Boolean safeBoot
, Boolean debug
, KEXTBootlevel bootlevel
)
1546 pthread_attr_t kmod_thread_attr
;
1547 pthread_t kmod_thread
;
1552 CFRunLoopSourceContext sourceContext
;
1553 KEXTManagerBundleLoadingCallbacks bcb
= {
1555 _KEXTDAuthenticateBundleCB
,
1556 _KEXTDWillAddBundleCB
,
1557 _KEXTDWasAddedBundleCB
,
1559 _KEXTDWillRemoveBundleCB
,
1562 KEXTManagerModuleLoadingCallbacks modcbs
= {
1564 _KEXTDModuleWillLoadCB
,
1565 _KEXTDModuleWasLoadedCB
,
1566 _KEXTDModuleErrorCB
,
1570 KEXTManagerConfigsCallbacks cfgcbs
= {
1573 _KEXTDConfigWasAdded
,
1575 _KEXTDConfigWasRemoved
,
1583 syslog(LOG_ERR
, "failed to daemonize process. Aborting!\n");
1584 return kKEXTReturnError
;
1589 k
->_manager
= KEXTManagerCreate(&bcb
, &modcbs
, NULL
, &cfgcbs
, kextd
,
1590 &logErrorFunction
, &logMessageFunction
, safeBoot
, &error
);
1594 k
->_initializing
= true;
1595 k
->_catPort
= _KEXTManagerGetMachPort(k
->_manager
);
1596 k
->_beVerbose
= beVerbose
;
1598 k
->_pollFileSystem
= poll
;
1599 k
->_pollingPeriod
= period
;
1601 memset(&sourceContext
, NULL
, sizeof(CFRunLoopSourceContext
));
1603 error
= _KEXTDInitSyslog(k
);
1604 if ( error
!= kKEXTReturnSuccess
) {
1610 // FIXME: Need a way to make this synchronous!
1611 error
= KERN2KEXTReturn(IOCatalogueSendData(k
->_catPort
, kIOCatalogRemoveKernelLinker
, 0, 0));
1612 if (error
!= kKEXTReturnSuccess
) {
1613 syslog(LOG_ERR
, "couldn't remove linker from kernel (may have been removed already).",
1615 // this is only serious the first time kextd launches....
1616 // FIXME: how exactly should we handle this? Create a separate program
1617 // to trigger KLD unload?
1620 signal(SIGHUP
, signalhandler
);
1622 k
->_runloop
= CFRunLoopGetCurrent();
1623 if ( !k
->_runloop
) {
1624 syslog(LOG_ERR
, "error allocating runloop.\n");
1628 sourceContext
.version
= 0;
1629 sourceContext
.info
= k
;
1630 sourceContext
.perform
= _KEXTDSIGHUPCallout
;
1631 k
->_signalsource
= CFRunLoopSourceCreate(kCFAllocatorDefault
, 1, &sourceContext
);
1632 if ( !k
->_signalsource
) {
1633 syslog(LOG_ERR
, "error allocating signal runloop source.\n");
1636 CFRunLoopAddSource(k
->_runloop
, k
->_signalsource
, kCFRunLoopDefaultMode
);
1638 sourceContext
.perform
= _KEXTDPerform
;
1639 k
->_kernelsource
= CFRunLoopSourceCreate(kCFAllocatorDefault
, 2, &sourceContext
);
1640 if ( !k
->_kernelsource
) {
1641 syslog(LOG_ERR
, "error allocating kernel runloop source.\n");
1644 CFRunLoopAddSource(k
->_runloop
, k
->_kernelsource
, kCFRunLoopDefaultMode
);
1646 count
= CFArrayGetCount(k
->_helpers
);
1647 for ( i
= 0; i
< count
; i
++ ) {
1648 KEXTDHelper
* helper
;
1650 helper
= (KEXTDHelper
*)CFArrayGetValueAtIndex(k
->_helpers
, i
);
1654 if ( helper
->cbs
.DaemonDidFinishLaunching
)
1655 helper
->cbs
.DaemonDidFinishLaunching(helper
->context
);
1658 // Fork off the kmod_control message thread.
1659 pthread_attr_init(&kmod_thread_attr
);
1660 pthread_create(&kmod_thread
, &kmod_thread_attr
, _KEXTDKmodWait
, kextd
);
1661 pthread_detach(kmod_thread
);
1663 syslog(LOG_INFO
, "started.");
1665 IOCatalogueReset(k
->_catPort
, kIOCatalogResetDefault
);
1666 KEXTDScanPaths(kextd
);
1670 CFRunLoopTimerRef timer
;
1671 CFRunLoopTimerContext timerContext
= {
1672 0, kextd
, NULL
, NULL
, NULL
,
1675 timer
= CFRunLoopTimerCreate(kCFAllocatorDefault
, CFAbsoluteTimeGetCurrent(), period
, 0, 10, _KEXTDTimerCallout
, &timerContext
);
1677 syslog(LOG_ERR
, "error allocating kmod runloop timer.\n");
1678 return kKEXTReturnError
;
1681 CFRunLoopAddTimer(k
->_runloop
, timer
, kCFRunLoopDefaultMode
);
1686 if ( (error
= _KEXTDSendPersonalities(kextd
, bootlevel
)) != kKEXTReturnSuccess
) {
1687 // KEXTError(error, CFSTR("Error sending personalities to IOCatalogue"));
1688 syslog(LOG_ERR
, "error (%d) sending personalities to IOCatalogue.", error
);
1692 k
->_initializing
= false;
1696 return kKEXTReturnSuccess
;
1699 void KEXTDScanPaths(KEXTDRef kextd
)
1710 count
= CFArrayGetCount(k
->_scanPaths
);
1711 for ( i
= 0; i
< count
; i
++ ) {
1714 url
= (CFURLRef
)CFArrayGetValueAtIndex(k
->_scanPaths
, i
);
1717 if ( k
->_beVerbose
) {
1721 cfstr
= CFURLGetString(url
);
1722 if ( CFStringGetCString(cfstr
, str
, 256, kCFStringEncodingNonLossyASCII
) ) {
1723 syslog(LOG_INFO
, "scanning: %s.", str
);
1726 error
= KEXTManagerScanPath(k
->_manager
, url
);
1727 if ( error
!= kKEXTReturnSuccess
) {
1728 syslog(LOG_ERR
, "error (%d) scanning path.\n", error
);
1734 CFIndex count
, index
;
1737 path
= CFURLCreateCopyAppendingPathComponent(
1738 kCFAllocatorDefault
,
1744 array
= (CFArrayRef
)IOURLCreatePropertyFromResource(
1745 kCFAllocatorDefault
, path
,
1746 kIOURLFileDirectoryContents
,
1752 count
= CFArrayGetCount(array
);
1753 for ( index
= 0; index
< count
; index
++ ) {
1755 file
= (CFURLRef
) CFArrayGetValueAtIndex(array
, index
);
1758 PEFExamineFile( k
->_catPort
, file
);
1763 #endif /* LOOKAPPLENDRV */
1768 void KEXTDAddScanPath(KEXTDRef kextd
, CFURLRef path
)
1770 if ( !kextd
|| !path
)
1773 if ( CFURLGetTypeID() != CFGetTypeID(path
) )
1776 CFArrayAppendValue(((KEXTD
*)kextd
)->_scanPaths
, path
);
1779 void KEXTDRegisterHelperCallbacks(KEXTDRef kextd
, KEXTDHelperCallbacks
* callbacks
)
1782 KEXTDHelper
* helper
;
1784 if ( !kextd
|| !callbacks
)
1788 helper
= (KEXTDHelper
*)malloc(sizeof(KEXTDHelper
));
1792 helper
->cbs
.HelperInitialize
= callbacks
->HelperInitialize
;
1793 helper
->cbs
.HelperFinalize
= callbacks
->HelperFinalize
;
1794 helper
->cbs
.DaemonDidFinishLaunching
= callbacks
->DaemonDidFinishLaunching
;
1795 helper
->cbs
.DaemonWillTerminate
= callbacks
->DaemonWillTerminate
;
1796 helper
->cbs
.BundleAdd
= callbacks
->BundleAdd
;
1797 helper
->cbs
.BundleRemove
= callbacks
->BundleRemove
;
1798 helper
->cbs
.EventOccurred
= callbacks
->EventOccurred
;
1799 helper
->cbs
.ModuleWillLoad
= callbacks
->ModuleWillLoad
;
1800 helper
->cbs
.ModuleWasLoaded
= callbacks
->ModuleWasLoaded
;
1801 helper
->cbs
.ModuleLoadError
= callbacks
->ModuleLoadError
;
1803 helper
->context
= helper
->cbs
.HelperInitialize(kextd
);
1805 CFArrayAppendValue(k
->_helpers
, helper
);
1808 KEXTReturn
KEXTDLoadModule(KEXTDRef kextd
, CFStringRef moduleName
)
1810 KEXTD
* k
= (KEXTD
*)kextd
;
1811 KEXTModuleRef
module;
1813 if ( !kextd
|| !moduleName
)
1814 return kKEXTReturnBadArgument
;
1816 module = KEXTManagerGetModule(k
->_manager
, moduleName
);
1818 return kKEXTReturnModuleNotFound
;
1820 return KEXTManagerLoadModule(k
->_manager
, module);