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