]> git.saurik.com Git - apple/system_cmds.git/blame_incremental - kextd.tproj/KEXTD.c
system_cmds-175.tar.gz
[apple/system_cmds.git] / kextd.tproj / KEXTD.c
... / ...
CommitLineData
1#define CFRUNLOOP_NEW_API 1
2
3#include "KEXTD.h"
4#include "PTLock.h"
5#include <IOKit/IOKitLib.h>
6#include <IOKit/IOKitServer.h>
7#include <IOKit/IOCFSerialize.h>
8#include <IOKit/IOCFURLAccess.h>
9#include <pthread.h>
10#include <stdlib.h>
11#include <errno.h>
12#include <unistd.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>
18#include <syslog.h>
19
20
21#define TIMER_PERIOD_S 10
22#define LOOKAPPLENDRV 1
23
24static Boolean gDebug;
25static void KEXTdaemonSignal(void);
26
27// from kernserv/queue.h now kern/queue.h
28
29/*
30 * A generic doubly-linked list (queue).
31 */
32
33struct queue_entry {
34 struct queue_entry *next; /* next element */
35 struct queue_entry *prev; /* previous element */
36};
37
38typedef struct queue_entry *queue_t;
39typedef struct queue_entry queue_head_t;
40typedef struct queue_entry queue_chain_t;
41typedef struct queue_entry *queue_entry_t;
42
43/*
44 * Macro: queue_init
45 * Function:
46 * Initialize the given queue.
47 * Header:
48 * void queue_init(q)
49 * queue_t q; \* MODIFIED *\
50 */
51#define queue_init(q) ((q)->next = (q)->prev = q)
52
53/*
54 * Macro: queue_first
55 * Function:
56 * Returns the first entry in the queue,
57 * Header:
58 * queue_entry_t queue_first(q)
59 * queue_t q; \* IN *\
60 */
61#define queue_first(q) ((q)->next)
62
63/*
64 * Macro: queue_next
65 * Header:
66 * queue_entry_t queue_next(qc)
67 * queue_t qc;
68 */
69#define queue_next(qc) ((qc)->next)
70
71/*
72 * Macro: queue_end
73 * Header:
74 * boolean_t queue_end(q, qe)
75 * queue_t q;
76 * queue_entry_t qe;
77 */
78#define queue_end(q, qe) ((q) == (qe))
79
80#define queue_empty(q) queue_end((q), queue_first(q))
81
82/*
83 * Macro: queue_enter
84 * Header:
85 * void queue_enter(q, elt, type, field)
86 * queue_t q;
87 * <type> elt;
88 * <type> is what's in our queue
89 * <field> is the chain field in (*<type>)
90 */
91#define queue_enter(head, elt, type, field) \
92do { \
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; \
98 } \
99 else { \
100 register queue_entry_t prev; \
101 \
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);\
107 } \
108} while(0)
109
110/*
111 * Macro: queue_field [internal use only]
112 * Function:
113 * Find the queue_chain_t (or queue_t) for the
114 * given element (thing) in the given queue (head)
115 */
116#define queue_field(head, thing, type, field) \
117 (((head) == (thing)) ? (head) : &((type)(thing))->field)
118
119/*
120 * Macro: queue_remove
121 * Header:
122 * void queue_remove(q, qe, type, field)
123 * arguments as in queue_enter
124 */
125#define queue_remove(head, elt, type, field) \
126do { \
127 register queue_entry_t next, prev; \
128 \
129 next = (elt)->field.next; \
130 prev = (elt)->field.prev; \
131 \
132 queue_field((head), next, type, field)->prev = prev; \
133 queue_field((head), prev, type, field)->next = next; \
134} while(0)
135
136
137typedef struct _KEXTD {
138 CFIndex _refcount;
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;
151 Boolean _beVerbose;
152#if TIMERSOURCE
153 Boolean _pollFileSystem;
154 CFIndex _pollingPeriod;
155#endif
156} KEXTD;
157
158typedef struct _request {
159 unsigned int type;
160 CFStringRef kmodname;
161 CFStringRef kmodvers;
162 queue_chain_t link;
163} request_t;
164
165typedef struct _KEXTDHelper {
166 void * context;
167 KEXTDHelperCallbacks cbs;
168} KEXTDHelper;
169
170CFDictionaryRef _KEXTPersonalityGetProperties(KEXTPersonalityRef personality);
171static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd, CFStringRef parentKey);
172static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd, CFStringRef modName);
173const void * _KEXTPersonalityRetainCB(CFAllocatorRef allocator, const void *ptr);
174void _KEXTPersonalityReleaseCB(CFAllocatorRef allocator, const void *ptr);
175Boolean _KEXTPersonalityEqualCB(const void *ptr1, const void *ptr2);
176mach_port_t _KEXTManagerGetMachPort(KEXTManagerRef manager);
177
178extern kern_return_t
179kmod_control(host_t host,
180 kmod_t id,
181 kmod_control_flavor_t flavor,
182 kmod_args_t *data,
183 mach_msg_type_number_t *dataCount);
184
185extern KEXTReturn KERN2KEXTReturn(kern_return_t kr);
186
187static KEXTDRef _kextd = NULL;
188
189static void logErrorFunction(const char * string)
190{
191 syslog(LOG_ERR, string);
192 return;
193}
194
195static void logMessageFunction(const char * string)
196{
197 syslog(LOG_INFO, string);
198 return;
199}
200
201
202static void ArrayMergeFunc(const void * val, void * context)
203{
204 CFMutableArrayRef array;
205
206 array = context;
207
208 CFArrayAppendValue(array, val);
209}
210
211static void CFArrayMergeArray(CFMutableArrayRef array1, CFArrayRef array2)
212{
213 CFRange range;
214
215 if ( !array1 || !array2 ) {
216 return;
217 }
218
219 range = CFRangeMake(0, CFArrayGetCount(array2));
220 CFArrayApplyFunction(array2, range, ArrayMergeFunc, array1);
221}
222
223static void CallHelperEvent(void * val, void * context[])
224{
225 KEXTDRef kextd;
226 KEXTEvent event;
227 KEXTDHelper * helper;
228 CFTypeRef item;
229
230 helper = val;
231 kextd = context[0];
232 event = *(KEXTEvent *)context[1];
233 item = context[2];
234
235 if ( helper && context && helper->cbs.EventOccurred ) {
236 helper->cbs.EventOccurred(event, item, kextd);
237 }
238}
239
240static void ConfigsForBundles(const void * var, void * context[])
241{
242 KEXTManagerRef manager;
243 KEXTBundleRef bundle;
244 CFMutableArrayRef array;
245 CFArrayRef configs;
246
247 bundle = (KEXTBundleRef)var;
248
249 manager = context[0];
250 array = context[1];
251
252 configs = KEXTManagerCopyConfigsForBundle(manager, bundle);
253 if ( configs ) {
254 CFArrayMergeArray(array, configs);
255 CFRelease(configs);
256 }
257}
258
259
260static inline KEXTBootlevel _KEXTDGetBootlevel(KEXTPersonalityRef personality)
261{
262 KEXTBootlevel bootlevel;
263 CFStringRef priority;
264 CFStringRef category;
265
266 bootlevel = kKEXTBootlevelExempt;
267 priority = KEXTPersonalityGetProperty(personality, CFSTR("BootPriority"));
268 if ( !priority ) {
269 category = KEXTPersonalityGetProperty(personality, CFSTR("DeviceCategory"));
270 if ( !category ) {
271 return kKEXTBootlevelExempt;
272 }
273
274 if ( CFEqual(category, CFSTR("System Controller")) ) {
275 bootlevel = kKEXTBootlevelRequired;
276 }
277 else if ( CFEqual(category, CFSTR("Bus Controller")) ) {
278 bootlevel = kKEXTBootlevelFlexible;
279 }
280 else if ( CFEqual(category, CFSTR("Keyboard")) ) {
281 bootlevel = kKEXTBootlevelSingleUser;
282 }
283 else if ( CFEqual(category, CFSTR("Input Device")) ) {
284 bootlevel = kKEXTBootlevelExempt;
285 }
286 else if ( CFEqual(category, CFSTR("Pointing Device")) ) {
287 bootlevel = kKEXTBootlevelExempt;
288 }
289 else if ( CFEqual(category, CFSTR("Mouse")) ) {
290 bootlevel = kKEXTBootlevelRecovery;
291 }
292 else if ( CFEqual(category, CFSTR("Graphics Controller")) ) {
293 bootlevel = kKEXTBootlevelRecovery;
294 }
295 else if ( CFEqual(category, CFSTR("Graphics Accelerator")) ) {
296 bootlevel = kKEXTBootlevelExempt;
297 }
298 else if ( CFEqual(category, CFSTR("Video Device")) ) {
299 bootlevel = kKEXTBootlevelExempt;
300 }
301 else if ( CFEqual(category, CFSTR("Disk Controller")) ) {
302 bootlevel = kKEXTBootlevelFlexible;
303 }
304 else if ( CFEqual(category, CFSTR("Disk Media")) ) {
305 bootlevel = kKEXTBootlevelFlexible;
306 }
307 else if ( CFEqual(category, CFSTR("Audio Controller")) ) {
308 bootlevel = kKEXTBootlevelExempt;
309 }
310 else if ( CFEqual(category, CFSTR("Sound Device")) ) {
311 bootlevel = kKEXTBootlevelExempt;
312 }
313 else if ( CFEqual(category, CFSTR("Network Controller")) ) {
314 bootlevel = kKEXTBootlevelFlexible;
315 }
316
317 return bootlevel;
318 }
319
320 if ( CFEqual(priority, CFSTR("Exempt")) ) {
321 bootlevel = kKEXTBootlevelExempt;
322 }
323 else if ( CFEqual(priority, CFSTR("Recovery")) ) {
324 bootlevel = kKEXTBootlevelRecovery;
325 }
326 else if ( CFEqual(priority, CFSTR("Special")) ) {
327 bootlevel = kKEXTBootlevelSingleUser;
328 }
329 else if ( CFEqual(priority, CFSTR("Flexible")) ) {
330 bootlevel = kKEXTBootlevelFlexible;
331 }
332 else if ( CFEqual(priority, CFSTR("Required")) ) {
333 bootlevel = kKEXTBootlevelRequired;
334 }
335
336 return bootlevel;
337}
338
339static void ArrayAddToLoadList(void * val, void * context[])
340{
341 KEXTPersonalityRef person;
342 KEXTBootlevel bootlevel;
343 CFMutableArrayRef unloaded;
344 CFMutableArrayRef loadlist;
345 CFRange range;
346 Boolean doAdd;
347
348 if ( !val || !context ) {
349 return;
350 }
351
352 doAdd = true;
353 person = val;
354 unloaded = context[0];
355 loadlist = context[1];
356 bootlevel = *(KEXTBootlevel *)context[2];
357
358 if ( bootlevel != kKEXTBootlevelNormal ) {
359 doAdd = _KEXTDGetBootlevel(person) & bootlevel;
360 }
361
362 if ( doAdd ) {
363 range = CFRangeMake(0, CFArrayGetCount(loadlist));
364 if ( !CFArrayContainsValue(loadlist, range, person) ) {
365 CFArrayAppendValue(loadlist, person);
366 }
367 }
368 else {
369 range = CFRangeMake(0, CFArrayGetCount(unloaded));
370 if ( !CFArrayContainsValue(unloaded, range, person) ) {
371 CFArrayAppendValue(unloaded, person);
372 }
373 CFArrayAppendValue(unloaded, person);
374 }
375}
376
377static void signalhandler(int signal)
378{
379 if ( _kextd && (signal == SIGHUP) ) {
380 KEXTDHangup(_kextd);
381 }
382}
383
384static KEXTReturn _KEXTDInitSyslog(KEXTD * k)
385{
386 openlog("kextd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
387
388 return kKEXTReturnSuccess;
389}
390
391// This is called when authenticating a new bundle.
392static KEXTReturn _KEXTDAuthenticateBundleCB(CFURLRef url, void * context)
393{
394 Boolean ret;
395
396 ret = KEXTManagerAuthenticateURL(url);
397 if ( !ret ) {
398 KEXTD * k = (KEXTD *)context;
399 KEXTEvent event;
400 CFStringRef urlString;
401 CFRange range;
402 char name[256];
403 void * context2[3];
404
405 urlString = CFURLGetString(url);
406 if ( CFStringGetCString(urlString, name, 256, kCFStringEncodingNonLossyASCII) )
407 syslog(LOG_ERR, "%s failed authentication.", name);
408
409 event = kKEXTEventBundleAuthenticationFailed;
410 context2[0] = k;
411 context2[1] = &event;
412 context2[2] = (void *)url;
413
414 range = CFRangeMake(0, CFArrayGetCount(k->_helpers));
415 CFArrayApplyFunction(k->_helpers, range, (CFArrayApplierFunction)CallHelperEvent, context2);
416 }
417
418 return ret;
419}
420
421// This is called when a new bundle has been found.
422static Boolean _KEXTDWillAddBundleCB(KEXTManagerRef manager, KEXTBundleRef bundle, void * context)
423{
424 KEXTD * k = (KEXTD *)context;
425 CFURLRef url;
426 CFIndex count;
427 CFIndex i;
428 Boolean ret;
429
430 ret = true;
431 count = CFArrayGetCount(k->_helpers);
432 for ( i = 0; i < count; i++ ) {
433 KEXTDHelper * helper;
434
435 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
436 if ( !helper )
437 continue;
438
439 if ( helper->cbs.BundleAdd ) {
440 ret = helper->cbs.BundleAdd(bundle, helper->context);
441 if ( !ret )
442 break;
443 }
444 }
445
446 url = KEXTBundleCopyURL(bundle);
447 if ( url ) {
448 if ( k->_beVerbose && ret ) {
449 CFStringRef cfstr;
450 char str[256];
451
452 cfstr = CFURLGetString(url);
453 if ( CFStringGetCString(cfstr, str, 256, kCFStringEncodingNonLossyASCII) ) {
454 syslog(LOG_INFO, "%s added.", str);
455 }
456 }
457
458 // Remove any unloaded personalities from look-aside queue
459 // which are in this bundle.
460 _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef)k, KEXTBundleGetPrimaryKey(bundle));
461 CFRelease(url);
462 }
463
464 return ret;
465}
466
467// This is called after a bundle has been added to the KEXTManager database.
468static void _KEXTDWasAddedBundleCB(KEXTManagerRef manager, KEXTBundleRef bundle, void * context)
469{
470 KEXTD * k;
471 KEXTBootlevel bootlevel;
472 CFMutableArrayRef toload;
473 CFArrayRef persons;
474 CFArrayRef configs;
475 CFArrayRef unloaded;
476 CFRange range;
477 void * context2[3];
478
479 k = (KEXTD *)context;
480 if ( k->_initializing ) {
481 return;
482 }
483
484 bootlevel = kKEXTBootlevelNormal;
485
486 toload = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
487 if ( !toload ) {
488 return;
489 }
490
491 context2[0] = k->_unloaded;
492 context2[1] = toload;
493 context2[2] = &bootlevel;
494
495
496 // Create a list of all personalities and configurations
497 // and send it to the catalogue. First, get the unloaded
498 // personalities.
499 unloaded = CFArrayCreateCopy(kCFAllocatorDefault, k->_unloaded);
500 CFArrayRemoveAllValues(k->_unloaded);
501 if ( unloaded ) {
502 range = CFRangeMake(0, CFArrayGetCount(unloaded));
503 CFArrayApplyFunction(unloaded, range, (CFArrayApplierFunction)ArrayAddToLoadList, context2);
504 CFRelease(unloaded);
505 }
506
507 persons = KEXTManagerCopyPersonalitiesForBundle(manager, bundle);
508 if ( persons ) {
509 range = CFRangeMake(0, CFArrayGetCount(persons));
510 CFArrayApplyFunction(persons, range, (CFArrayApplierFunction)ArrayAddToLoadList, context2);
511 CFRelease(persons);
512 }
513
514 configs = KEXTManagerCopyConfigsForBundle(manager, bundle);
515 if ( configs ) {
516 range = CFRangeMake(0, CFArrayGetCount(configs));
517 CFArrayApplyFunction(configs, range, (CFArrayApplierFunction)ArrayAddToLoadList, context2);
518 CFRelease(configs);
519
520 }
521
522 // Send the list to IOCatalogue.
523 if ( CFArrayGetCount(toload) > 0 ) {
524 KEXTManagerLoadPersonalities(k->_manager, toload);
525 }
526
527 CFRelease(toload);
528}
529
530static void _KEXTDConfigWasAdded(KEXTManagerRef manager, KEXTConfigRef config, void * context)
531{
532 KEXTD * kextd;
533
534 if ( !manager || !config || !context ) {
535 return;
536 }
537
538 kextd = context;
539
540 if ( !kextd->_initializing ) {
541 CFStringRef primaryKey;
542 CFArrayRef array;
543 void * vals[1];
544
545 primaryKey = CFDictionaryGetValue(config, CFSTR("ParentKey"));
546 if ( !primaryKey ) {
547 return;
548 }
549
550 if ( !KEXTManagerGetBundle(manager, primaryKey) ) {
551 return;
552 }
553
554 vals[0] = config;
555 array = CFArrayCreate(kCFAllocatorDefault, vals, 1, &kCFTypeArrayCallBacks);
556 if ( array ) {
557 KEXTManagerLoadPersonalities(manager, array);
558 CFRelease(array);
559 }
560 }
561}
562
563static void _KEXTDConfigWasRemoved(KEXTManagerRef manager, KEXTConfigRef config, void * context)
564{
565 KEXTD * kextd;
566
567 if ( !manager || !config || !context ) {
568 return;
569 }
570
571 kextd = context;
572
573 if ( !kextd->_initializing ) {
574 KEXTManagerUnloadPersonality(manager, config);
575 }
576}
577
578static void ArrayUnloadPersonality(const void * val, void * context)
579{
580 KEXTManagerRef manager;
581 KEXTPersonalityRef person;
582
583 manager = context;
584 person = (KEXTPersonalityRef)val;
585
586 KEXTManagerUnloadPersonality(manager, person);
587}
588
589// This is called when a bundle has been removed from the filesystem.
590static Boolean _KEXTDWillRemoveBundleCB(KEXTManagerRef manager, KEXTBundleRef bundle, void * context)
591{
592 KEXTD * k = (KEXTD *)context;
593 CFIndex count;
594 CFIndex i;
595 Boolean ret;
596
597 ret = true;
598 count = CFArrayGetCount(k->_helpers);
599 for ( i = 0; i < count; i++ ) {
600 KEXTDHelper * helper;
601
602 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
603 if ( !helper )
604 continue;
605
606 if ( helper->cbs.BundleRemove ) {
607 ret = helper->cbs.BundleRemove(bundle, helper->context);
608 if ( !ret )
609 break;
610 }
611 }
612
613 if ( ret ) {
614 CFArrayRef personalities;
615 CFArrayRef configs;
616 CFURLRef url;
617 CFRange range;
618
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);
628 }
629
630 configs = KEXTManagerCopyConfigsForBundle(manager, bundle);
631 if ( configs ) {
632 range = CFRangeMake(0, CFArrayGetCount(configs));
633 CFArrayApplyFunction(configs, range, ArrayUnloadPersonality, manager);
634 CFRelease(configs);
635 }
636
637 url = KEXTBundleCopyURL(bundle);
638 if ( url ) {
639 if ( k->_beVerbose && ret ) {
640 CFStringRef cfstr;
641 char str[256];
642
643 cfstr = CFURLGetString(url);
644 if ( CFStringGetCString(cfstr, str, 256, kCFStringEncodingNonLossyASCII) ) {
645 syslog(LOG_INFO, "%s removed.", str);
646 }
647 }
648
649 // Remove any unloaded personalities from the unloaded
650 // list if they are associated with the bundle.
651
652 _KEXTDRemovePersonalitiesFromUnloadedList((KEXTDRef)k, KEXTBundleGetPrimaryKey(bundle));
653 CFRelease(url);
654 }
655 }
656
657 return ret;
658}
659
660// This is called before KEXT loads a KMOD.
661static Boolean _KEXTDModuleWillLoadCB(KEXTManagerRef manager, KEXTModuleRef module, void * context)
662{
663 KEXTD * k;
664 CFIndex count;
665 CFIndex i;
666 Boolean ret;
667
668 k = (KEXTD *)context;
669
670 ret = true;
671 count = CFArrayGetCount(k->_helpers);
672 for ( i = 0; i < count; i++ ) {
673 KEXTDHelper * helper;
674
675 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
676 if ( !helper )
677 continue;
678
679 if ( helper->cbs.ModuleWillLoad ) {
680 if ( !helper->cbs.ModuleWillLoad(module, helper->context) ) {
681 ret = false;
682 break;
683 }
684 }
685 }
686
687 if ( ret ) {
688 CFStringRef moduleName;
689 char name[256];
690
691 moduleName = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
692 if ( !moduleName )
693 return false;
694
695 if ( !CFStringGetCString(moduleName, name, 256, kCFStringEncodingNonLossyASCII) )
696 return false;
697
698 syslog(LOG_INFO, "loading module: %s.\n", name);
699 }
700
701 return ret;
702}
703
704// This is called when a module has been successfully loaded.
705static void _KEXTDModuleWasLoadedCB(KEXTManagerRef manager, KEXTModuleRef module, void * context)
706{
707 KEXTD * k;
708 CFArrayRef array;
709 CFMutableArrayRef send;
710 CFIndex count;
711 CFIndex i;
712
713 k = (KEXTD *)context;
714
715 count = CFArrayGetCount(k->_helpers);
716 for ( i = 0; i < count; i++ ) {
717 KEXTDHelper * helper;
718
719 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
720 if ( !helper )
721 continue;
722
723 if ( helper->cbs.ModuleWasLoaded ) {
724 helper->cbs.ModuleWasLoaded(module, helper->context);
725 }
726 }
727
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.
731
732 array = CFArrayCreateCopy(kCFAllocatorDefault, k->_unloaded);
733 send = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
734 count = CFArrayGetCount(array);
735
736 CFArrayRemoveAllValues(k->_unloaded);
737
738 for ( i = 0; i < count; i++ ) {
739 KEXTPersonalityRef person;
740 CFStringRef moduleID;
741 CFStringRef personalityBundleID;
742
743 person = (KEXTPersonalityRef)CFArrayGetValueAtIndex(array, i);
744 if ( !person ) {
745 continue;
746 }
747
748 moduleID = KEXTPersonalityGetProperty(person, CFSTR("CFBundleIdentifier"));
749 if ( !moduleID ) {
750 continue;
751 }
752
753 personalityBundleID = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
754 if ( !personalityBundleID ) {
755 continue;
756 }
757
758 if ( !CFEqual(moduleID, personalityBundleID) ) {
759 CFArrayAppendValue(k->_unloaded, person);
760 }
761 else {
762 CFArrayAppendValue(send, person);
763 }
764 }
765
766 if ( CFArrayGetCount(send) > 0 ) {
767 KEXTManagerLoadPersonalities(k->_manager, send);
768 }
769
770 CFRelease(send);
771 CFRelease(array);
772
773 if ( k->_beVerbose ) {
774 CFStringRef moduleName;
775 char name[256];
776
777 moduleName = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
778 if ( !moduleName )
779 return;
780
781 if ( !CFStringGetCString(moduleName, name, 256, kCFStringEncodingNonLossyASCII) )
782 return;
783
784 syslog(LOG_INFO, "loaded module: %s\n", name);
785 }
786}
787
788static KEXTReturn _KEXTDModuleErrorCB(KEXTManagerRef manager, KEXTModuleRef module, KEXTReturn error, void * context)
789{
790 char name[256];
791 KEXTD * k;
792 KEXTReturn ret;
793 CFIndex i;
794 CFIndex count;
795 CFStringRef moduleName;
796
797 k = (KEXTD *)context;
798
799 moduleName = KEXTModuleGetProperty(module, CFSTR("CFBundleIdentifier"));
800 if ( !moduleName )
801 return kKEXTReturnPropertyNotFound;
802
803 if ( !CFStringGetCString(moduleName, name, 256, kCFStringEncodingNonLossyASCII) )
804 return kKEXTReturnNoMemory;
805
806 if ( error == kKEXTReturnModuleAlreadyLoaded ) {
807 if ( k->_beVerbose )
808 syslog(LOG_INFO, "module already loaded: %s.\n", name);
809
810 return error;
811 }
812
813 ret = error;
814 count = CFArrayGetCount(k->_helpers);
815 for ( i = 0; i < count; i++ ) {
816 KEXTDHelper * helper;
817
818 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
819 if ( !helper )
820 continue;
821
822 if ( helper->cbs.ModuleLoadError ) {
823 ret = helper->cbs.ModuleLoadError(module, error, helper->context);
824 if ( ret == kKEXTReturnSuccess ) {
825 break;
826 }
827 }
828 }
829 if ( ret == kKEXTReturnSuccess )
830 return kKEXTReturnSuccess;
831
832 syslog(LOG_ERR, "error (%d) loading module: %s.\n", ret, name);
833
834 return ret;
835}
836
837#if TIMERSOURCE
838static void _KEXTDTimerCallout(CFRunLoopTimerRef timer, void * info)
839{
840 KEXTDScanPaths((KEXTDRef)info);
841}
842#endif
843
844static void _KEXTDSIGHUPCallout(void * info)
845{
846 KEXTD * k;
847
848 k = (KEXTD *)info;
849 if ( k->_beVerbose ) {
850 syslog(LOG_INFO, "user requests directory re-scan.");
851 }
852
853 // Check for new or removed bundles and do the appropriate
854 // things.
855 KEXTDScanPaths((KEXTDRef)info);
856
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);
861 }
862}
863
864// This function is called when IOCatalogue requests a driver module.
865static void _KEXTDPerform(void * info)
866{
867 KEXTD * k;
868 unsigned int type;
869
870 k = (KEXTD *)info;
871
872// KEXTDScanPaths((KEXTDRef)k);
873
874 PTLockTakeLock(k->_queue_lock);
875 while ( !queue_empty(&k->_requestQ) ) {
876 request_t * reqstruct;
877 CFStringRef name;
878
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);
883
884 type = reqstruct->type;
885 name = reqstruct->kmodname;
886 free(reqstruct);
887
888 if( type == kIOCatalogMatchIdle) {
889
890 mach_timespec_t timeout = { 10, 0 };
891 IOKitWaitQuiet( k->_catPort, &timeout );
892 KEXTdaemonSignal();
893
894 } else if ( name ) {
895
896 if ( k->_beVerbose ) {
897 char modname[256];
898
899 if ( CFStringGetCString(name, modname, 256, kCFStringEncodingNonLossyASCII) ) {
900 syslog(LOG_INFO, "kernel requests module: %s", modname);
901 }
902 }
903
904 KEXTDKernelRequest((KEXTDRef)k, name);
905 CFRelease(name);
906 }
907
908 PTLockTakeLock(k->_queue_lock);
909 }
910 PTLockUnlock(k->_queue_lock);
911}
912
913KEXTDRef KEXTDCreate(CFArrayRef scanPaths, KEXTReturn * error)
914{
915 KEXTD * kextd;
916
917 kextd = (KEXTD *)malloc(sizeof(KEXTD));
918 if ( !kextd ) {
919 *error = kKEXTReturnNoMemory;
920 return NULL;
921 }
922 memset(kextd, 0, sizeof(KEXTD));
923
924 kextd->_queue_lock = PTLockCreate();
925 kextd->_runloop_lock = PTLockCreate();
926
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);
933 return NULL;
934 }
935
936 kextd->_initializing = true;
937 kextd->_beVerbose = false;
938#if TIMERSOURCE
939 kextd->_pollFileSystem = false;
940 kextd->_pollingPeriod = TIMER_PERIOD_S;
941#endif
942
943 queue_init(&kextd->_requestQ);
944
945 if ( scanPaths ) {
946 CFURLRef url;
947 CFIndex count;
948 CFIndex i;
949
950 count = CFArrayGetCount(scanPaths);
951 for ( i = 0; i < count; i++ ) {
952 url = (CFURLRef)CFArrayGetValueAtIndex(scanPaths, i);
953 KEXTDAddScanPath((KEXTDRef)kextd, url);
954 }
955 }
956
957 return (KEXTDRef)kextd;
958}
959
960static void _KEXTDFlushHelpers(KEXTDRef kextd)
961{
962 KEXTD * k;
963 CFIndex count;
964 CFIndex i;
965
966 k = (KEXTD *)kextd;
967 count = CFArrayGetCount(k->_helpers);
968 for ( i = 0; i < count; i++ ) {
969 KEXTDHelper * helper;
970
971 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
972 if ( !helper )
973 continue;
974
975 if ( helper->cbs.DaemonWillTerminate )
976 helper->cbs.DaemonWillTerminate(helper->context);
977 if ( helper->cbs.HelperFinalize )
978 helper->cbs.HelperFinalize(helper->context);
979
980 free(helper);
981 }
982}
983
984void KEXTDFree(KEXTDRef kextd)
985{
986 KEXTD * k;
987
988 k = (KEXTD *)kextd;
989
990 syslog(LOG_DEBUG, "terminating.");
991
992 if ( k->_helpers ) {
993 _KEXTDFlushHelpers(kextd);
994 CFRelease(k->_helpers);
995 }
996 if ( k->_kernelsource )
997 CFRelease(k->_kernelsource);
998 if ( k->_signalsource )
999 CFRelease(k->_signalsource);
1000 if ( k->_runloop )
1001 CFRelease(k->_runloop);
1002 if ( k->_scanPaths )
1003 CFRelease(k->_scanPaths);
1004 if ( k->_manager )
1005 KEXTManagerRelease(k->_manager);
1006 if ( k->_queue_lock )
1007 PTLockFree(k->_queue_lock);
1008 if ( k->_runloop_lock )
1009 PTLockFree(k->_runloop_lock);
1010
1011 closelog();
1012
1013 free(kextd);
1014}
1015
1016void KEXTDReset(KEXTDRef kextd)
1017{
1018 KEXTD * k;
1019 CFIndex count;
1020 CFIndex i;
1021
1022 syslog(LOG_DEBUG, "resetting.");
1023
1024 k = (KEXTD *)kextd;
1025 count = CFArrayGetCount(k->_helpers);
1026 for ( i = 0; i < count; i++ ) {
1027 KEXTDHelper * helper;
1028
1029 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
1030 if ( !helper )
1031 continue;
1032
1033 if ( helper->cbs.EventOccurred )
1034 helper->cbs.EventOccurred(kKEXTEventReset, NULL, helper->context);
1035 }
1036
1037 if ( k->_manager )
1038 KEXTManagerReset(k->_manager);
1039
1040 KEXTDScanPaths(kextd);
1041}
1042
1043static KEXTReturn _KEXTDSendDataToCatalog(KEXTDRef kextd, int flag, CFTypeRef obj)
1044{
1045 KEXTD * k;
1046 KEXTReturn error;
1047 CFDataRef data;
1048 CFIndex len;
1049 void * ptr;
1050
1051 k = (KEXTD *)kextd;
1052 data = NULL;
1053 error = kKEXTReturnSuccess;
1054
1055 data = IOCFSerialize(obj, 0);
1056 if ( !data ) {
1057 return kKEXTReturnSerializationError;
1058 }
1059
1060 len = CFDataGetLength(data);
1061 ptr = (void *)CFDataGetBytePtr(data);
1062 error = KERN2KEXTReturn(IOCatalogueSendData(k->_catPort, flag, ptr, len));
1063 CFRelease(data);
1064
1065 return error;
1066}
1067
1068static KEXTReturn _KEXTDSendPersonalities(KEXTDRef kextd, KEXTBootlevel bootlevel)
1069{
1070 KEXTReturn error;
1071 CFArrayRef persons;
1072 CFArrayRef bundles;
1073 CFMutableArrayRef configs;
1074 CFMutableArrayRef toload;
1075 CFRange range;
1076 void * context[3];
1077
1078 error = kKEXTReturnSuccess;
1079
1080 toload = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1081 if ( !toload ) {
1082 return kKEXTReturnNoMemory;
1083 }
1084
1085 configs = NULL;
1086 bundles = KEXTManagerCopyAllBundles(((KEXTD*)kextd)->_manager);
1087 if ( bundles ) {
1088 configs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1089 if ( !configs ) {
1090 CFRelease(bundles);
1091 CFRelease(toload);
1092 return kKEXTReturnNoMemory;
1093 }
1094
1095 context[0] = ((KEXTD*)kextd)->_manager;
1096 context[1] = configs;
1097
1098 range = CFRangeMake(0, CFArrayGetCount(bundles));
1099 CFArrayApplyFunction(bundles, range, (CFArrayApplierFunction)ConfigsForBundles, context);
1100 CFRelease(bundles);
1101 }
1102
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;
1109
1110 persons = KEXTManagerCopyAllPersonalities(((KEXTD*)kextd)->_manager);
1111 if ( persons ) {
1112 range = CFRangeMake(0, CFArrayGetCount(persons));
1113 CFArrayApplyFunction(persons, range, (CFArrayApplierFunction)ArrayAddToLoadList, context);
1114 CFRelease(persons);
1115 }
1116
1117 if ( configs ) {
1118 range = CFRangeMake(0, CFArrayGetCount(configs));
1119 CFArrayApplyFunction(configs, range, (CFArrayApplierFunction)ArrayAddToLoadList, context);
1120 CFRelease(configs);
1121 }
1122
1123 if ( CFArrayGetCount(toload) > 0 ) {
1124 error = KEXTManagerLoadPersonalities(((KEXTD *)kextd)->_manager, toload);
1125 } else {
1126 KEXTdaemonSignal();
1127 }
1128
1129 CFRelease(toload);
1130
1131 return error;
1132
1133}
1134
1135static inline Boolean _KEXTPersonalityNeedsModule(KEXTPersonalityRef person, CFStringRef modName)
1136{
1137 CFStringRef name;
1138
1139 name = KEXTPersonalityGetProperty(person, CFSTR("CFBundleIdentifier"));
1140 if ( !name ) {
1141 return false;
1142 }
1143
1144 return CFEqual(name, modName);
1145}
1146
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.
1151static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd, CFStringRef modName)
1152{
1153 CFArrayRef array;
1154 CFIndex i;
1155 CFIndex count;
1156 KEXTD * k;
1157
1158 if ( !modName )
1159 return;
1160
1161 k = (KEXTD *)kextd;
1162
1163 array = KEXTManagerCopyAllEntities(k->_manager);
1164 if ( !array )
1165 return;
1166
1167 // Find personalities which depend on this module.
1168 count = CFArrayGetCount(array);
1169 for ( i = 0; i < count; i++ ) {
1170 CFStringRef type;
1171 CFStringRef name;
1172 CFRange range;
1173 KEXTEntityRef entity;
1174
1175 entity = (KEXTEntityRef)CFArrayGetValueAtIndex(array, i);
1176 if ( !entity )
1177 continue;
1178
1179 type = KEXTManagerGetEntityType(entity);
1180 if ( !type || !CFEqual(type, KEXTPersonalityGetEntityType()) ) {
1181 continue;
1182 }
1183
1184 name = KEXTPersonalityGetProperty(entity, CFSTR("CFBundleIdentifier"));
1185 if ( !name || !CFEqual(modName, name) ) {
1186 continue;
1187 }
1188
1189 range = CFRangeMake(0, CFArrayGetCount(k->_unloaded));
1190
1191 if ( CFArrayContainsValue(k->_unloaded, range, entity) ) {
1192 continue;
1193 }
1194
1195 CFArrayAppendValue(k->_unloaded, entity);
1196
1197 if ( !k->_initializing ) {
1198 KEXTManagerUnloadPersonality(k->_manager, entity);
1199 }
1200
1201 }
1202 CFRelease(array);
1203}
1204
1205static void RemovePersonsWithParentFromUnloadedList(void * val, void * context[])
1206{
1207 KEXTPersonalityRef person;
1208 CFMutableArrayRef unloaded;
1209 CFStringRef parentKey;
1210 CFStringRef key;
1211
1212 if ( !val || !context ) {
1213 return;
1214 }
1215
1216 person = val;
1217 unloaded = context[0];
1218 parentKey = context[1];
1219
1220 key = CFDictionaryGetValue(person, CFSTR("ParentKey"));
1221 if ( !parentKey || !key || CFEqual(parentKey, key) ) {
1222 return;
1223 }
1224
1225 CFArrayAppendValue(unloaded, person);
1226}
1227
1228// Remove personalities from the unloaded list if their
1229// associated bundle is removed.
1230static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd, CFStringRef parentKey)
1231{
1232 CFMutableArrayRef unloaded;
1233 CFArrayRef array;
1234 CFRange range;
1235 void * context[2];
1236
1237 unloaded = ((KEXTD *)kextd)->_unloaded;
1238
1239 array = CFArrayCreateCopy(kCFAllocatorDefault, unloaded);
1240 CFArrayRemoveAllValues(unloaded);
1241
1242 context[0] = unloaded;
1243 context[1] = (void *)parentKey;
1244
1245 range = CFRangeMake(0, CFArrayGetCount(array));
1246 CFArrayApplyFunction(
1247 array,
1248 range,
1249 (CFArrayApplierFunction)RemovePersonsWithParentFromUnloadedList,
1250 context);
1251
1252 CFRelease(array);
1253}
1254
1255static KEXTReturn _KEXTDProcessLoadCommand(KEXTDRef kextd, CFStringRef name)
1256{
1257 char cname[256];
1258 KEXTReturn error;
1259 KEXTD * k;
1260
1261 k = (KEXTD *)kextd;
1262 if ( !CFStringGetCString(name, cname, 256, kCFStringEncodingNonLossyASCII) ) {
1263 error = kKEXTReturnNoMemory;
1264 return error;
1265 }
1266
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];
1273
1274 do {
1275 keys[0] = CFSTR("CFBundleIdentifier");
1276 vals[0] = name;
1277
1278 if ( !vals[0] ) {
1279 error = kKEXTReturnPropertyNotFound;
1280 break;
1281 }
1282
1283 matchingDict = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1284 if ( !matchingDict ) {
1285 error = kKEXTReturnNoMemory;
1286 break;
1287 }
1288
1289 error = _KEXTDSendDataToCatalog(kextd, kIOCatalogRemoveDrivers, matchingDict);
1290 CFRelease(matchingDict);
1291 if ( error != kKEXTReturnSuccess ) {
1292 syslog(LOG_DEBUG, "error ( %d) removing drivers.", error);
1293 break;
1294 }
1295 } while ( false );
1296
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);
1301 }
1302 else {
1303
1304 error = KERN2KEXTReturn(IOCatalogueModuleLoaded(k->_catPort, cname));
1305 if ( error != kKEXTReturnSuccess ) {
1306 syslog(LOG_DEBUG, "error (%d) signalling IOCatalogue.", error);
1307 }
1308 }
1309
1310 return error;
1311}
1312
1313void KEXTDHangup(KEXTDRef kextd)
1314{
1315 KEXTD * k;
1316
1317 k = (KEXTD *)kextd;
1318 if ( k->_signalsource ) {
1319 PTLockTakeLock(k->_runloop_lock);
1320 CFRunLoopSourceSignal(k->_signalsource);
1321 CFRunLoopWakeUp(k->_runloop);
1322 PTLockUnlock(k->_runloop_lock);
1323 }
1324}
1325
1326KEXTReturn KEXTDKernelRequest(KEXTDRef kextd, CFStringRef name)
1327{
1328 KEXTD * k;
1329 KEXTReturn ret;
1330
1331 k = (KEXTD *)kextd;
1332 ret = kKEXTReturnBadArgument;
1333 if ( name ) {
1334 KEXTEvent event;
1335 CFRange range;
1336 void * context[3];
1337
1338 event = kKEXTEventModuleRequest;
1339
1340 context[0] = kextd;
1341 context[1] = &event;
1342 context[2] = (void *)name;
1343
1344 range = CFRangeMake(0, CFArrayGetCount(k->_helpers));
1345 CFArrayApplyFunction(k->_helpers, range, (CFArrayApplierFunction)CallHelperEvent, context);
1346 ret = _KEXTDProcessLoadCommand((KEXTDRef)k, name);
1347 }
1348
1349 return ret;
1350}
1351
1352// The kernel blocks the thread which entered this
1353// function until the kernel requests a driver to load.
1354static void * _KEXTDKmodWait(void * info)
1355{
1356 mach_port_t kmodPort;
1357 kern_return_t kr;
1358 KEXTD * kextd;
1359 KEXTReturn error;
1360 request_t * reqstruct;
1361 CFStringRef str;
1362 unsigned int type;
1363
1364 if ( !info )
1365 return (void *)kKEXTReturnBadArgument;
1366
1367 kmodPort = mach_host_self(); /* must be privileged to work */
1368
1369 kextd = (KEXTD *)info;
1370 if ( !kextd->_kernelsource )
1371 return (void *)kKEXTReturnBadArgument;
1372
1373 while ( 1 ) {
1374 kmod_args_t data;
1375 kmod_load_extension_cmd_t * cmd;
1376 mach_msg_type_number_t dataCount;
1377 kern_return_t kr;
1378
1379 data = 0;
1380 dataCount = 0;
1381 error = kKEXTReturnSuccess;
1382
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);
1387 continue;
1388 }
1389
1390 cmd = (kmod_load_extension_cmd_t *)data;
1391 type = cmd->type;
1392 str = 0;
1393
1394 switch ( type ) {
1395
1396 case kIOCatalogMatchIdle:
1397 break;
1398
1399 case KMOD_LOAD_EXTENSION_PACKET: {
1400
1401 str = CFStringCreateWithCString(NULL, cmd->name, kCFStringEncodingNonLossyASCII);
1402 if( str)
1403 break;
1404 // else fall thru
1405 }
1406 default:
1407 error = kKEXTReturnError;
1408 break;
1409 }
1410
1411 if( error == kKEXTReturnSuccess) {
1412
1413 reqstruct = (request_t *)malloc(sizeof(request_t));
1414 if( reqstruct) {
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);
1422
1423 // wake up the runloop.
1424 PTLockTakeLock(kextd->_runloop_lock);
1425 CFRunLoopSourceSignal(kextd->_kernelsource);
1426 CFRunLoopWakeUp(kextd->_runloop);
1427 PTLockUnlock(kextd->_runloop_lock);
1428 }
1429 }
1430
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");
1435 exit(1);
1436 }
1437 }
1438
1439 return (void *)kKEXTReturnSuccess;
1440}
1441
1442
1443#include <fcntl.h>
1444#include <paths.h>
1445#include <unistd.h>
1446#include <assert.h>
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>
1453
1454static void
1455KEXTdaemonSignal(void)
1456{
1457 kern_return_t kr;
1458 mach_port_t bs_port;
1459 semaphore_t sema;
1460 static boolean_t signalled = false;
1461
1462 if (signalled)
1463 return;
1464 signalled = TRUE;
1465 if (gDebug) {
1466 printf("kextd: idle\n");
1467 return;
1468 }
1469
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);
1479
1480}
1481
1482static semaphore_t gDaemonSema;
1483
1484static void
1485KEXTdaemonWait(void)
1486{
1487 kern_return_t kr;
1488 mach_timespec_t waitTime = { 40, 0 };
1489
1490 kr = semaphore_timedwait( gDaemonSema, waitTime );
1491 if( kr != KERN_SUCCESS )
1492 syslog(LOG_ERR, "semaphore_timedwait(%lx)\n", kr);
1493}
1494
1495static int
1496KEXTdaemon(nochdir, noclose)
1497 int nochdir, noclose;
1498{
1499 kern_return_t kr;
1500 mach_port_t bs_port;
1501 int fd;
1502
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);
1512
1513 switch (fork()) {
1514 case -1:
1515 return (-1);
1516 case 0:
1517 break;
1518 default:
1519 KEXTdaemonWait();
1520 _exit(0);
1521 }
1522
1523 if (setsid() == -1)
1524 return (-1);
1525
1526 if (!nochdir)
1527 (void)chdir("/");
1528
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);
1533 if (fd > 2)
1534 (void)close (fd);
1535 }
1536 return (0);
1537}
1538
1539
1540#if TIMERSOURCE
1541KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel)
1542#else
1543KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, KEXTBootlevel bootlevel)
1544#endif
1545{
1546 pthread_attr_t kmod_thread_attr;
1547 pthread_t kmod_thread;
1548 KEXTReturn error;
1549 KEXTD * k;
1550 CFIndex count;
1551 CFIndex i;
1552 CFRunLoopSourceContext sourceContext;
1553 KEXTManagerBundleLoadingCallbacks bcb = {
1554 0,
1555 _KEXTDAuthenticateBundleCB,
1556 _KEXTDWillAddBundleCB,
1557 _KEXTDWasAddedBundleCB,
1558 NULL,
1559 _KEXTDWillRemoveBundleCB,
1560 NULL,
1561 };
1562 KEXTManagerModuleLoadingCallbacks modcbs = {
1563 0,
1564 _KEXTDModuleWillLoadCB,
1565 _KEXTDModuleWasLoadedCB,
1566 _KEXTDModuleErrorCB,
1567 NULL,
1568 NULL,
1569 };
1570 KEXTManagerConfigsCallbacks cfgcbs = {
1571 0,
1572 NULL,
1573 _KEXTDConfigWasAdded,
1574 NULL,
1575 _KEXTDConfigWasRemoved,
1576 };
1577
1578 gDebug = debug;
1579 if (!debug) {
1580 errno = 0;
1581 KEXTdaemon(0, 0);
1582 if ( errno ) {
1583 syslog(LOG_ERR, "failed to daemonize process. Aborting!\n");
1584 return kKEXTReturnError;
1585 }
1586 }
1587
1588 k = (KEXTD *)kextd;
1589 k->_manager = KEXTManagerCreate(&bcb, &modcbs, NULL, &cfgcbs, kextd,
1590 &logErrorFunction, &logMessageFunction, safeBoot, &error);
1591 if ( !k->_manager )
1592 return error;
1593
1594 k->_initializing = true;
1595 k->_catPort = _KEXTManagerGetMachPort(k->_manager);
1596 k->_beVerbose = beVerbose;
1597#if TIMERSOURCE
1598 k->_pollFileSystem = poll;
1599 k->_pollingPeriod = period;
1600#endif
1601 memset(&sourceContext, NULL, sizeof(CFRunLoopSourceContext));
1602
1603 error = _KEXTDInitSyslog(k);
1604 if ( error != kKEXTReturnSuccess ) {
1605 return error;
1606 }
1607
1608 _kextd = kextd;
1609
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).",
1614 error);
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?
1618 }
1619
1620 signal(SIGHUP, signalhandler);
1621
1622 k->_runloop = CFRunLoopGetCurrent();
1623 if ( !k->_runloop ) {
1624 syslog(LOG_ERR, "error allocating runloop.\n");
1625 return NULL;
1626 }
1627
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");
1634 return NULL;
1635 }
1636 CFRunLoopAddSource(k->_runloop, k->_signalsource, kCFRunLoopDefaultMode);
1637
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");
1642 return NULL;
1643 }
1644 CFRunLoopAddSource(k->_runloop, k->_kernelsource, kCFRunLoopDefaultMode);
1645
1646 count = CFArrayGetCount(k->_helpers);
1647 for ( i = 0; i < count; i++ ) {
1648 KEXTDHelper * helper;
1649
1650 helper = (KEXTDHelper *)CFArrayGetValueAtIndex(k->_helpers, i);
1651 if ( !helper )
1652 continue;
1653
1654 if ( helper->cbs.DaemonDidFinishLaunching )
1655 helper->cbs.DaemonDidFinishLaunching(helper->context);
1656 }
1657
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);
1662
1663 syslog(LOG_INFO, "started.");
1664
1665 IOCatalogueReset(k->_catPort, kIOCatalogResetDefault);
1666 KEXTDScanPaths(kextd);
1667
1668#if TIMERSOURCE
1669 if ( poll ) {
1670 CFRunLoopTimerRef timer;
1671 CFRunLoopTimerContext timerContext = {
1672 0, kextd, NULL, NULL, NULL,
1673 };
1674
1675 timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), period, 0, 10, _KEXTDTimerCallout, &timerContext);
1676 if ( !timer ) {
1677 syslog(LOG_ERR, "error allocating kmod runloop timer.\n");
1678 return kKEXTReturnError;
1679 }
1680
1681 CFRunLoopAddTimer(k->_runloop, timer, kCFRunLoopDefaultMode);
1682 CFRelease(timer);
1683 }
1684#endif
1685
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);
1689 return error;
1690 }
1691
1692 k->_initializing = false;
1693
1694 CFRunLoopRun();
1695
1696 return kKEXTReturnSuccess;
1697}
1698
1699void KEXTDScanPaths(KEXTDRef kextd)
1700{
1701 KEXTReturn error;
1702 KEXTD * k;
1703 CFIndex count;
1704 CFIndex i;
1705
1706 k = (KEXTD *)kextd;
1707 if ( !k->_manager )
1708 return;
1709
1710 count = CFArrayGetCount(k->_scanPaths);
1711 for ( i = 0; i < count; i++ ) {
1712 CFURLRef url;
1713
1714 url = (CFURLRef)CFArrayGetValueAtIndex(k->_scanPaths, i);
1715
1716 if ( url ) {
1717 if ( k->_beVerbose ) {
1718 CFStringRef cfstr;
1719 char str[256];
1720
1721 cfstr = CFURLGetString(url);
1722 if ( CFStringGetCString(cfstr, str, 256, kCFStringEncodingNonLossyASCII) ) {
1723 syslog(LOG_INFO, "scanning: %s.", str);
1724 }
1725 }
1726 error = KEXTManagerScanPath(k->_manager, url);
1727 if ( error != kKEXTReturnSuccess ) {
1728 syslog(LOG_ERR, "error (%d) scanning path.\n", error);
1729 }
1730#if LOOKAPPLENDRV
1731 do {
1732 CFURLRef path;
1733 CFArrayRef array;
1734 CFIndex count, index;
1735 SInt32 err;
1736
1737 path = CFURLCreateCopyAppendingPathComponent(
1738 kCFAllocatorDefault,
1739 url,
1740 CFSTR("AppleNDRV"),
1741 TRUE);
1742 if ( !path )
1743 continue;
1744 array = (CFArrayRef)IOURLCreatePropertyFromResource(
1745 kCFAllocatorDefault, path,
1746 kIOURLFileDirectoryContents,
1747 &err);
1748 CFRelease( path );
1749 if ( !array )
1750 continue;
1751
1752 count = CFArrayGetCount(array);
1753 for ( index = 0; index < count; index++ ) {
1754 CFURLRef file;
1755 file = (CFURLRef) CFArrayGetValueAtIndex(array, index);
1756 if ( !file )
1757 continue;
1758 PEFExamineFile( k->_catPort, file );
1759 }
1760 CFRelease(array);
1761
1762 } while( false );
1763#endif /* LOOKAPPLENDRV */
1764 }
1765 }
1766}
1767
1768void KEXTDAddScanPath(KEXTDRef kextd, CFURLRef path)
1769{
1770 if ( !kextd || !path )
1771 return;
1772
1773 if ( CFURLGetTypeID() != CFGetTypeID(path) )
1774 return;
1775
1776 CFArrayAppendValue(((KEXTD *)kextd)->_scanPaths, path);
1777}
1778
1779void KEXTDRegisterHelperCallbacks(KEXTDRef kextd, KEXTDHelperCallbacks * callbacks)
1780{
1781 KEXTD * k;
1782 KEXTDHelper * helper;
1783
1784 if ( !kextd || !callbacks )
1785 return;
1786
1787 k = (KEXTD *)kextd;
1788 helper = (KEXTDHelper *)malloc(sizeof(KEXTDHelper));
1789 if ( !helper )
1790 return;
1791
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;
1802
1803 helper->context = helper->cbs.HelperInitialize(kextd);
1804
1805 CFArrayAppendValue(k->_helpers, helper);
1806}
1807
1808KEXTReturn KEXTDLoadModule(KEXTDRef kextd, CFStringRef moduleName)
1809{
1810 KEXTD * k = (KEXTD *)kextd;
1811 KEXTModuleRef module;
1812
1813 if ( !kextd || !moduleName )
1814 return kKEXTReturnBadArgument;
1815
1816 module = KEXTManagerGetModule(k->_manager, moduleName);
1817 if ( !module )
1818 return kKEXTReturnModuleNotFound;
1819
1820 return KEXTManagerLoadModule(k->_manager, module);
1821}
1822
1823