]>
Commit | Line | Data |
---|---|---|
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 | ||
25 | static Boolean gDebug; | |
26 | static void KEXTdaemonSignal(void); | |
27 | ||
28 | // from kernserv/queue.h now kern/queue.h | |
29 | ||
30 | /* | |
31 | * A generic doubly-linked list (queue). | |
32 | */ | |
33 | ||
34 | struct queue_entry { | |
35 | struct queue_entry *next; /* next element */ | |
36 | struct queue_entry *prev; /* previous element */ | |
37 | }; | |
38 | ||
39 | typedef struct queue_entry *queue_t; | |
40 | typedef struct queue_entry queue_head_t; | |
41 | typedef struct queue_entry queue_chain_t; | |
42 | typedef struct queue_entry *queue_entry_t; | |
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) \ | |
93 | do { \ | |
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) \ | |
127 | do { \ | |
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 | ||
138 | typedef 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 | ||
159 | typedef struct _request { | |
160 | unsigned int type; | |
161 | CFStringRef kmodname; | |
162 | CFStringRef kmodvers; | |
163 | queue_chain_t link; | |
164 | } request_t; | |
165 | ||
166 | typedef struct _KEXTDHelper { | |
167 | void * context; | |
168 | KEXTDHelperCallbacks cbs; | |
169 | } KEXTDHelper; | |
170 | ||
171 | CFDictionaryRef _KEXTPersonalityGetProperties(KEXTPersonalityRef personality); | |
172 | static void _KEXTDRemovePersonalitiesFromUnloadedList(KEXTDRef kextd, CFStringRef parentKey); | |
173 | static void _KEXTDAddPersonalitiesWithModuleToUnloadedList(KEXTDRef kextd, CFStringRef modName); | |
174 | const void * _KEXTPersonalityRetainCB(CFAllocatorRef allocator, const void *ptr); | |
175 | void _KEXTPersonalityReleaseCB(CFAllocatorRef allocator, const void *ptr); | |
176 | Boolean _KEXTPersonalityEqualCB(const void *ptr1, const void *ptr2); | |
177 | mach_port_t _KEXTManagerGetMachPort(KEXTManagerRef manager); | |
178 | ||
179 | extern kern_return_t | |
180 | kmod_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 | ||
186 | extern KEXTReturn KERN2KEXTReturn(kern_return_t kr); | |
187 | ||
188 | static KEXTDRef _kextd = NULL; | |
189 | ||
190 | static void logErrorFunction(const char * string) | |
191 | { | |
192 | syslog(LOG_ERR, string); | |
193 | return; | |
194 | } | |
195 | ||
196 | static void logMessageFunction(const char * string) | |
197 | { | |
198 | syslog(LOG_INFO, string); | |
199 | return; | |
200 | } | |
201 | ||
202 | ||
203 | static void ArrayMergeFunc(const void * val, void * context) | |
204 | { | |
205 | CFMutableArrayRef array; | |
206 | ||
207 | array = context; | |
208 | ||
209 | CFArrayAppendValue(array, val); | |
210 | } | |
211 | ||
212 | static 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 | ||
224 | static 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 | ||
241 | static 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 | ||
261 | static 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 | ||
340 | static 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 | ||
378 | static void signalhandler(int signal) | |
379 | { | |
380 | if ( _kextd && (signal == SIGHUP) ) { | |
381 | KEXTDHangup(_kextd); | |
382 | } | |
383 | } | |
384 | ||
385 | static 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. | |
393 | static 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. | |
423 | static 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. | |
469 | static 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 | ||
531 | static 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 | ||
564 | static 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 | ||
579 | static 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. | |
591 | static 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. | |
662 | static 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. | |
706 | static 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 | ||
789 | static 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 | |
839 | static void _KEXTDTimerCallout(CFRunLoopTimerRef timer, void * info) | |
840 | { | |
841 | KEXTDScanPaths((KEXTDRef)info); | |
842 | } | |
843 | #endif | |
844 | ||
845 | static 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. | |
866 | static 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 | ||
914 | KEXTDRef 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 | ||
961 | static 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 | ||
985 | void 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 | ||
1017 | void 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 | ||
1044 | static 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 | ||
1069 | static 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 | ||
1136 | static 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. | |
1152 | static 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 | ||
1206 | static 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. | |
1231 | static 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 | ||
1256 | static 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 | ||
1314 | void 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 | ||
1327 | KEXTReturn 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. | |
1355 | static 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 | ||
1455 | static void | |
1456 | KEXTdaemonSignal(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 | ||
1483 | static semaphore_t gDaemonSema; | |
1484 | ||
1485 | static void | |
1486 | KEXTdaemonWait(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 | ||
1496 | static int | |
1497 | KEXTdaemon(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 | |
1550 | KEXTReturn KEXTDStartMain(KEXTDRef kextd, Boolean beVerbose, Boolean safeBoot, Boolean debug, Boolean poll, CFIndex period, KEXTBootlevel bootlevel) | |
1551 | #else | |
1552 | KEXTReturn 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 | ||
1708 | void 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 | ||
1777 | void 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 | ||
1788 | void 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 | ||
1817 | KEXTReturn 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 |