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