]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/plugin_support.c
configd-130.tar.gz
[apple/configd.git] / configd.tproj / plugin_support.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * October 30, 2003 Allan Nathanson <ajn@apple.com>
28 * - add plugin "stop()" function support
29 *
30 * June 11, 2001 Allan Nathanson <ajn@apple.com>
31 * - start using CFBundle code
32 *
33 * June 1, 2001 Allan Nathanson <ajn@apple.com>
34 * - public API conversion
35 *
36 * May 26, 2000 Allan Nathanson <ajn@apple.com>
37 * - initial revision
38 */
39
40 #include <mach-o/dyld.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/param.h>
44 #include <dirent.h>
45 #include <sysexits.h>
46 #include <unistd.h>
47 #include <NSSystemDirectories.h>
48
49 #include "configd.h"
50 #include "configd_server.h"
51 #include <SystemConfiguration/SCDPlugin.h>
52 void _SCDPluginExecInit();
53
54
55 /*
56 * path components, extensions, entry points, ...
57 */
58 #define BUNDLE_DIRECTORY "/SystemConfiguration" /* [/System/Library]/... */
59 #define BUNDLE_DIR_EXTENSION ".bundle"
60
61
62 typedef struct {
63 CFBundleRef bundle;
64 Boolean loaded;
65 Boolean builtin;
66 Boolean verbose;
67 SCDynamicStoreBundleLoadFunction load;
68 SCDynamicStoreBundleStartFunction start;
69 SCDynamicStoreBundlePrimeFunction prime;
70 SCDynamicStoreBundleStopFunction stop;
71 } *bundleInfoRef;
72
73
74 // all loaded bundles
75 static CFMutableArrayRef allBundles = NULL;
76
77 // exiting bundles
78 static CFMutableDictionaryRef exiting = NULL;
79
80 // plugin CFRunLoopRef
81 static CFRunLoopRef plugin_runLoop = NULL;
82
83
84 #ifdef ppc
85 //extern SCDynamicStoreBundleLoadFunction load_ATconfig;
86 //extern SCDynamicStoreBundleStopFunction stop_ATconfig;
87 #endif /* ppc */
88 extern SCDynamicStoreBundleLoadFunction load_IPMonitor;
89 extern SCDynamicStoreBundlePrimeFunction prime_IPMonitor;
90 extern SCDynamicStoreBundleLoadFunction load_InterfaceNamer;
91 extern SCDynamicStoreBundleLoadFunction load_KernelEventMonitor;
92 extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor;
93 extern SCDynamicStoreBundleLoadFunction load_Kicker;
94 extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration;
95 extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor;
96 extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor;
97 extern SCDynamicStoreBundleStopFunction stop_PreferencesMonitor;
98
99
100 typedef struct {
101 const CFStringRef bundleID;
102 const void *load; // SCDynamicStoreBundleLoadFunction
103 const void *start; // SCDynamicStoreBundleStartFunction
104 const void *prime; // SCDynamicStoreBundlePrimeFunction
105 const void *stop; // SCDynamicStoreBundleStopFunction
106 } builtin, *builtinRef;
107
108
109 static const builtin builtin_plugins[] = {
110 #ifdef ppc
111 // {
112 // CFSTR("com.apple.SystemConfiguration.ATconfig"),
113 // &load_ATconfig,
114 // NULL,
115 // NULL,
116 // &stop_ATconfig
117 // },
118 #endif /* ppc */
119 {
120 CFSTR("com.apple.SystemConfiguration.IPMonitor"),
121 &load_IPMonitor,
122 NULL,
123 &prime_IPMonitor,
124 NULL
125 },
126 {
127 CFSTR("com.apple.SystemConfiguration.InterfaceNamer"),
128 &load_InterfaceNamer,
129 NULL,
130 NULL,
131 NULL
132 },
133 {
134 CFSTR("com.apple.SystemConfiguration.KernelEventMonitor"),
135 &load_KernelEventMonitor,
136 NULL,
137 &prime_KernelEventMonitor,
138 NULL
139 },
140 {
141 CFSTR("com.apple.SystemConfiguration.Kicker"),
142 &load_Kicker,
143 NULL,
144 NULL,
145 NULL
146 },
147 {
148 CFSTR("com.apple.SystemConfiguration.LinkConfiguration"),
149 &load_LinkConfiguration,
150 NULL,
151 NULL,
152 NULL
153 },
154 {
155 CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
156 &load_PreferencesMonitor,
157 NULL,
158 &prime_PreferencesMonitor,
159 &stop_PreferencesMonitor
160 }
161 };
162
163
164 static void
165 addBundle(CFBundleRef bundle)
166 {
167 CFDictionaryRef bundleDict;
168 bundleInfoRef bundleInfo;
169
170 bundleInfo = CFAllocatorAllocate(NULL, sizeof(*bundleInfo), 0);
171 bundleInfo->bundle = (CFBundleRef)CFRetain(bundle);
172 bundleInfo->loaded = FALSE;
173 bundleInfo->builtin = FALSE;
174 bundleInfo->verbose = FALSE;
175 bundleInfo->load = NULL;
176 bundleInfo->start = NULL;
177 bundleInfo->prime = NULL;
178 bundleInfo->stop = NULL;
179
180 bundleDict = CFBundleGetInfoDictionary(bundle);
181 if (isA_CFDictionary(bundleDict)) {
182 CFBooleanRef bVal;
183
184 bVal = CFDictionaryGetValue(bundleDict, kSCBundleIsBuiltinKey);
185 if (isA_CFBoolean(bVal) && CFBooleanGetValue(bVal)) {
186 bundleInfo->builtin = TRUE;
187 }
188
189 bVal = CFDictionaryGetValue(bundleDict, kSCBundleVerboseKey);
190 if (isA_CFBoolean(bVal) && CFBooleanGetValue(bVal)) {
191 bundleInfo->verbose = TRUE;
192 }
193 }
194
195 CFArrayAppendValue(allBundles, bundleInfo);
196 return;
197 }
198
199
200 static CFStringRef
201 shortBundleIdentifier(CFStringRef bundleID)
202 {
203 CFIndex len = CFStringGetLength(bundleID);
204 CFRange range;
205 CFStringRef shortID = NULL;
206
207 if (CFStringFindWithOptions(bundleID,
208 CFSTR("."),
209 CFRangeMake(0, len),
210 kCFCompareBackwards,
211 &range)) {
212 range.location = range.location + range.length;
213 range.length = len - range.location;
214 shortID = CFStringCreateWithSubstring(NULL, bundleID, range);
215 }
216
217 return shortID;
218 }
219
220
221 static void *
222 getBundleSymbol(CFBundleRef bundle, CFStringRef functionName, CFStringRef shortID)
223 {
224 void *func;
225
226 // search for load(), start(), prime(), stop(), ...
227 func = CFBundleGetFunctionPointerForName(bundle, functionName);
228 if (func != NULL) {
229 return func;
230 }
231
232 if (shortID != NULL) {
233 CFStringRef altFunctionName;
234
235 // search for load_XXX(), ...
236 altFunctionName = CFStringCreateWithFormat(NULL,
237 NULL,
238 CFSTR("%@_%@"),
239 functionName,
240 shortID);
241 func = CFBundleGetFunctionPointerForName(bundle, altFunctionName);
242 CFRelease(altFunctionName);
243 }
244
245 return func;
246 }
247
248
249 static void
250 loadBundle(const void *value, void *context) {
251 CFStringRef bundleID;
252 bundleInfoRef bundleInfo = (bundleInfoRef)value;
253 Boolean bundleExclude;
254 CFIndex *nLoaded = (CFIndex *)context;
255 CFStringRef shortID;
256
257 bundleID = CFBundleGetIdentifier(bundleInfo->bundle);
258 if (bundleID == NULL) {
259 // sorry, no bundles without a bundle identifier
260 SCLog(TRUE, LOG_DEBUG, CFSTR("skipped %@"), bundleInfo->bundle);
261 return;
262 }
263
264 shortID = shortBundleIdentifier(bundleID);
265
266 bundleExclude = CFSetContainsValue(_plugins_exclude, bundleID);
267 if (bundleExclude) {
268 if (shortID != NULL) {
269 bundleExclude = CFSetContainsValue(_plugins_exclude, shortID);
270 }
271 }
272
273 if (bundleExclude) {
274 // sorry, this bundle has been excluded
275 SCLog(TRUE, LOG_DEBUG, CFSTR("excluded %@"), bundleID);
276 goto done;
277 }
278
279 if (!bundleInfo->verbose) {
280 bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, bundleID);
281 if (!bundleInfo->verbose) {
282 if (shortID != NULL) {
283 bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, shortID);
284 }
285 }
286 }
287
288 if (bundleInfo->builtin) {
289 int i;
290
291 SCLog(TRUE, LOG_DEBUG, CFSTR("adding %@"), bundleID);
292
293 for (i = 0; i < sizeof(builtin_plugins)/sizeof(builtin_plugins[0]); i++) {
294 if (CFEqual(bundleID, builtin_plugins[i].bundleID)) {
295 bundleInfo->load = builtin_plugins[i].load;
296 bundleInfo->start = builtin_plugins[i].start;
297 bundleInfo->prime = builtin_plugins[i].prime;
298 bundleInfo->stop = builtin_plugins[i].stop;
299 break;
300 }
301 }
302 } else {
303 SCLog(TRUE, LOG_DEBUG, CFSTR("loading %@"), bundleID);
304
305 if (!CFBundleLoadExecutable(bundleInfo->bundle)) {
306 SCLog(TRUE, LOG_NOTICE, CFSTR("%@ load failed"), bundleID);
307 goto done;
308 }
309
310 // get bundle entry points
311 bundleInfo->load = getBundleSymbol(bundleInfo->bundle, CFSTR("load" ), shortID);
312 bundleInfo->start = getBundleSymbol(bundleInfo->bundle, CFSTR("start"), shortID);
313 bundleInfo->prime = getBundleSymbol(bundleInfo->bundle, CFSTR("prime"), shortID);
314 bundleInfo->stop = getBundleSymbol(bundleInfo->bundle, CFSTR("stop" ), shortID);
315 }
316
317 /* mark this bundle as having been loaded */
318 bundleInfo->loaded = TRUE;
319
320 /* bump the count of loaded bundles */
321 *nLoaded = *nLoaded + 1;
322
323 done :
324
325 if (shortID != NULL) CFRelease(shortID);
326 return;
327 }
328
329
330 void
331 callLoadFunction(const void *value, void *context) {
332 bundleInfoRef bundleInfo = (bundleInfoRef)value;
333
334 if (!bundleInfo->loaded) {
335 return;
336 }
337
338 if (bundleInfo->load == NULL) {
339 // if no load() function
340 return;
341 }
342
343 (*bundleInfo->load)(bundleInfo->bundle, bundleInfo->verbose);
344 return;
345 }
346
347
348 void
349 callStartFunction(const void *value, void *context) {
350 bundleInfoRef bundleInfo = (bundleInfoRef)value;
351 CFURLRef bundleURL;
352 char bundleName[MAXNAMLEN + 1];
353 char bundlePath[MAXPATHLEN];
354 char *cp;
355 int len;
356 Boolean ok;
357
358 if (!bundleInfo->loaded) {
359 return;
360 }
361
362 if (bundleInfo->start == NULL) {
363 // if no start() function
364 return;
365 }
366
367 bundleURL = CFBundleCopyBundleURL(bundleInfo->bundle);
368 if (bundleURL == NULL) {
369 return;
370 }
371
372 ok = CFURLGetFileSystemRepresentation(bundleURL,
373 TRUE,
374 (UInt8 *)&bundlePath,
375 sizeof(bundlePath));
376 CFRelease(bundleURL);
377 if (!ok) {
378 return;
379 }
380
381 cp = strrchr(bundlePath, '/');
382 if (cp) {
383 cp++;
384 } else {
385 cp = bundlePath;
386 }
387
388 /* check if this directory entry is a valid bundle name */
389 len = strlen(cp);
390 if (len <= (int)sizeof(BUNDLE_DIR_EXTENSION)) {
391 /* if entry name isn't long enough */
392 return;
393 }
394
395 len -= sizeof(BUNDLE_DIR_EXTENSION) - 1;
396 if (strcmp(&cp[len], BUNDLE_DIR_EXTENSION) != 0) {
397 /* if entry name doesn end with ".bundle" */
398 return;
399 }
400
401 /* get (just) the bundle's name */
402 bundleName[0] = '\0';
403 (void) strncat(bundleName, cp, len);
404
405 (*bundleInfo->start)(bundleName, bundlePath);
406 return;
407 }
408
409
410 void
411 callPrimeFunction(const void *value, void *context) {
412 bundleInfoRef bundleInfo = (bundleInfoRef)value;
413
414 if (!bundleInfo->loaded) {
415 return;
416 }
417
418 if (bundleInfo->prime == NULL) {
419 // if no prime() function
420 return;
421 }
422
423 (*bundleInfo->prime)();
424 return;
425 }
426
427
428 static void
429 stopComplete(void *info)
430 {
431 CFBundleRef bundle = (CFBundleRef)info;
432 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
433 CFRunLoopSourceRef stopRls;
434
435 SCLog(TRUE, LOG_DEBUG, CFSTR("** %@ complete (%f)"), bundleID, CFAbsoluteTimeGetCurrent());
436
437 stopRls = (CFRunLoopSourceRef)CFDictionaryGetValue(exiting, bundle);
438 CFRunLoopSourceInvalidate(stopRls);
439
440 CFDictionaryRemoveValue(exiting, bundle);
441
442 if (CFDictionaryGetCount(exiting) == 0) {
443 int status;
444
445 // if all of the plugins are happy
446 status = server_shutdown();
447 SCLog(TRUE, LOG_DEBUG, CFSTR("server shutdown complete (%f)"), CFAbsoluteTimeGetCurrent());
448 exit (status);
449 }
450
451 return;
452 }
453
454
455 static void
456 stopDelayed(CFRunLoopTimerRef timer, void *info)
457 {
458 const void **keys;
459 CFIndex i;
460 CFIndex n;
461 int status;
462
463 SCLog(TRUE, LOG_ERR, CFSTR("server shutdown was delayed, unresponsive plugins:"));
464
465 /*
466 * we've asked our plugins to shutdown but someone
467 * isn't listening.
468 */
469 n = CFDictionaryGetCount(exiting);
470 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
471 CFDictionaryGetKeysAndValues(exiting, keys, NULL);
472 for (i = 0; i < n; i++) {
473 CFBundleRef bundle;
474 CFStringRef bundleID;
475
476 bundle = (CFBundleRef)keys[i];
477 bundleID = CFBundleGetIdentifier(bundle);
478 SCLog(TRUE, LOG_ERR, CFSTR("** %@"), bundleID);
479 }
480 CFAllocatorDeallocate(NULL, keys);
481
482 status = server_shutdown();
483 exit (status);
484 }
485
486 static void
487 stopBundle(const void *value, void *context) {
488 bundleInfoRef bundleInfo = (bundleInfoRef)value;
489 CFRunLoopSourceRef stopRls;
490 CFRunLoopSourceContext stopContext = { 0 // version
491 , bundleInfo->bundle // info
492 , CFRetain // retain
493 , CFRelease // release
494 , CFCopyDescription // copyDescription
495 , CFEqual // equal
496 , CFHash // hash
497 , NULL // schedule
498 , NULL // cancel
499 , stopComplete // perform
500 };
501
502 if (!bundleInfo->loaded) {
503 return;
504 }
505
506 if (bundleInfo->stop == NULL) {
507 // if no stop() function
508 return;
509 }
510
511 stopRls = CFRunLoopSourceCreate(NULL, 0, &stopContext);
512 CFRunLoopAddSource(CFRunLoopGetCurrent(), stopRls, kCFRunLoopDefaultMode);
513 CFDictionaryAddValue(exiting, bundleInfo->bundle, stopRls);
514 CFRelease(stopRls);
515
516 (*bundleInfo->stop)(stopRls);
517
518 return;
519 }
520
521
522 static void
523 stopBundles()
524 {
525 /*
526 * If defined, call each bundles stop() function. This function is
527 * called when configd has been asked to shut down (via a SIGTERM). The
528 * function should signal the provided run loop source when it is "ready"
529 * for the shut down to proceeed.
530 */
531 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle stop() functions"));
532 CFArrayApplyFunction(allBundles,
533 CFRangeMake(0, CFArrayGetCount(allBundles)),
534 stopBundle,
535 NULL);
536
537 if (CFDictionaryGetCount(exiting) == 0) {
538 int status;
539
540 // if all of the plugins are happy
541 status = server_shutdown();
542 SCLog(TRUE, LOG_DEBUG, CFSTR("server shutdown complete (%f)"), CFAbsoluteTimeGetCurrent());
543 exit (status);
544 } else {
545 CFRunLoopTimerRef timer;
546
547 /* sorry, we're not going to wait longer than 20 seconds */
548 timer = CFRunLoopTimerCreate(NULL, /* allocator */
549 CFAbsoluteTimeGetCurrent() + 20.0, /* fireDate (in 20 seconds) */
550 0.0, /* interval (== one-shot) */
551 0, /* flags */
552 0, /* order */
553 stopDelayed, /* callout */
554 NULL); /* context */
555 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
556 CFRelease(timer);
557 }
558
559 return;
560 }
561
562
563 __private_extern__
564 Boolean
565 plugin_term(int *status)
566 {
567 CFRunLoopSourceRef stopRls;
568 CFRunLoopSourceContext stopContext = { 0 // version
569 , NULL // info
570 , NULL // retain
571 , NULL // release
572 , NULL // copyDescription
573 , NULL // equal
574 , NULL // hash
575 , NULL // schedule
576 , NULL // cancel
577 , stopBundles // perform
578 };
579
580 if (plugin_runLoop == NULL) {
581 // if no plugins
582 *status = EX_OK;
583 return FALSE; // don't delay shutdown
584 }
585
586 if (exiting != NULL) {
587 // if shutdown already active
588 return TRUE;
589 }
590
591 SCLog(TRUE, LOG_DEBUG, CFSTR("starting server shutdown (%f)"), CFAbsoluteTimeGetCurrent());
592
593 exiting = CFDictionaryCreateMutable(NULL,
594 0,
595 &kCFTypeDictionaryKeyCallBacks,
596 &kCFTypeDictionaryValueCallBacks);
597
598 stopRls = CFRunLoopSourceCreate(NULL, 0, &stopContext);
599 CFRunLoopAddSource(plugin_runLoop, stopRls, kCFRunLoopDefaultMode);
600 CFRunLoopSourceSignal(stopRls);
601 CFRelease(stopRls);
602 CFRunLoopWakeUp(plugin_runLoop);
603
604 return TRUE;
605 }
606
607
608 #ifdef DEBUG
609
610 static void
611 timerCallback(CFRunLoopTimerRef timer, void *info)
612 {
613 SCLog(_configd_verbose,
614 LOG_INFO,
615 CFSTR("the CFRunLoop is waiting for something to happen...."));
616 return;
617 }
618
619 #endif /* DEBUG */
620
621
622 static void
623 sortBundles(CFMutableArrayRef orig)
624 {
625 CFMutableArrayRef new;
626
627 new = CFArrayCreateMutable(NULL, 0, NULL);
628 while (CFArrayGetCount(orig) > 0) {
629 int i;
630 Boolean inserted = FALSE;
631 int nOrig = CFArrayGetCount(orig);
632
633 for (i = 0; i < nOrig; i++) {
634 bundleInfoRef bundleInfo1 = (bundleInfoRef)CFArrayGetValueAtIndex(orig, i);
635 CFStringRef bundleID1 = CFBundleGetIdentifier(bundleInfo1->bundle);
636 int count;
637 CFDictionaryRef dict;
638 int j;
639 int nRequires;
640 CFArrayRef requires = NULL;
641
642 dict = isA_CFDictionary(CFBundleGetInfoDictionary(bundleInfo1->bundle));
643 if (dict) {
644 requires = CFDictionaryGetValue(dict, kSCBundleRequiresKey);
645 requires = isA_CFArray(requires);
646 }
647 if (bundleID1 == NULL || requires == NULL) {
648 CFArrayInsertValueAtIndex(new, 0, bundleInfo1);
649 CFArrayRemoveValueAtIndex(orig, i);
650 inserted = TRUE;
651 break;
652 }
653 count = nRequires = CFArrayGetCount(requires);
654 for (j = 0; j < nRequires; j++) {
655 int k;
656 int nNew;
657 CFStringRef r = CFArrayGetValueAtIndex(requires, j);
658
659 nNew = CFArrayGetCount(new);
660 for (k = 0; k < nNew; k++) {
661 bundleInfoRef bundleInfo2 = (bundleInfoRef)CFArrayGetValueAtIndex(new, k);
662 CFStringRef bundleID2 = CFBundleGetIdentifier(bundleInfo2->bundle);
663
664 if (bundleID2 && CFEqual(bundleID2, r)) {
665 count--;
666 }
667 }
668 }
669 if (count == 0) {
670 /* all dependencies are met, append */
671 CFArrayAppendValue(new, bundleInfo1);
672 CFArrayRemoveValueAtIndex(orig, i);
673 inserted = TRUE;
674 break;
675 }
676 }
677
678 if (inserted == FALSE) {
679 SCLog(TRUE, LOG_NOTICE, CFSTR("Bundles have circular dependency!!!"));
680 break;
681 }
682 }
683 if (CFArrayGetCount(orig) > 0) {
684 /* we have a circular dependency, append remaining items on new array */
685 CFArrayAppendArray(new, orig, CFRangeMake(0, CFArrayGetCount(orig)));
686 }
687 else {
688 /* new one is a sorted version of original */
689 }
690
691 CFArrayRemoveAllValues(orig);
692 CFArrayAppendArray(orig, new, CFRangeMake(0, CFArrayGetCount(new)));
693 CFRelease(new);
694 return;
695 }
696
697
698 __private_extern__
699 void *
700 plugin_exec(void *arg)
701 {
702 CFIndex nLoaded = 0;
703
704 /* keep track of bundles */
705 allBundles = CFArrayCreateMutable(NULL, 0, NULL);
706
707 /* allow plug-ins to exec child/helper processes */
708 _SCDPluginExecInit();
709
710 if (arg == NULL) {
711 char path[MAXPATHLEN];
712 NSSearchPathEnumerationState state;
713
714 /*
715 * identify and load all bundles
716 */
717 state = NSStartSearchPathEnumeration(NSLibraryDirectory,
718 NSSystemDomainMask);
719 while ((state = NSGetNextSearchPathEnumeration(state, path))) {
720 CFArrayRef bundles;
721 CFURLRef url;
722
723 /* load any available bundle */
724 strcat(path, BUNDLE_DIRECTORY);
725 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("searching for bundles in \".\""));
726 url = CFURLCreateFromFileSystemRepresentation(NULL,
727 path,
728 strlen(path),
729 TRUE);
730 bundles = CFBundleCreateBundlesFromDirectory(NULL, url, CFSTR(".bundle"));
731 CFRelease(url);
732
733 if (bundles != NULL) {
734 CFIndex i;
735 CFIndex n;
736
737 n = CFArrayGetCount(bundles);
738 for (i = 0; i < n; i++) {
739 CFBundleRef bundle;
740
741 bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundles, i);
742 addBundle(bundle);
743 }
744 CFRelease(bundles);
745 }
746 }
747
748 sortBundles(allBundles);
749 } else {
750 CFBundleRef bundle;
751 CFURLRef url;
752
753 /*
754 * load (only) the specified bundle
755 */
756 url = CFURLCreateFromFileSystemRepresentation(NULL,
757 (char *)arg,
758 strlen((char *)arg),
759 TRUE);
760 bundle = CFBundleCreate(NULL, url);
761 if (bundle != NULL) {
762 addBundle(bundle);
763 CFRelease(bundle);
764 }
765 CFRelease(url);
766 }
767
768 /*
769 * load each bundle.
770 */
771 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("loading bundles"));
772 CFArrayApplyFunction(allBundles,
773 CFRangeMake(0, CFArrayGetCount(allBundles)),
774 loadBundle,
775 &nLoaded);
776
777 /*
778 * If defined, call each bundles load() function. This function (or
779 * the start() function) should initialize any variables, open any
780 * sessions with "configd", and register any needed notifications.
781 *
782 * Note: Establishing initial information in the store should be
783 * deferred until the prime() initialization function so that
784 * any bundles which want to receive a notification that the
785 * data has changed will have an opportunity to install a
786 * notification handler.
787 */
788 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle load() functions"));
789 CFArrayApplyFunction(allBundles,
790 CFRangeMake(0, CFArrayGetCount(allBundles)),
791 callLoadFunction,
792 NULL);
793
794 /*
795 * If defined, call each bundles start() function. This function is
796 * called after the bundle has been loaded and its load() function has
797 * been called. It should initialize any variables, open any sessions
798 * with "configd", and register any needed notifications.
799 *
800 * Note: Establishing initial information in the store should be
801 * deferred until the prime() initialization function so that
802 * any bundles which want to receive a notification that the
803 * data has changed will have an opportunity to install a
804 * notification handler.
805 */
806 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle start() functions"));
807 CFArrayApplyFunction(allBundles,
808 CFRangeMake(0, CFArrayGetCount(allBundles)),
809 callStartFunction,
810 NULL);
811
812 /*
813 * If defined, call each bundles prime() function. This function is
814 * called after the bundle has been loaded and its load() and start()
815 * functions have been called. It should initialize any configuration
816 * information and/or state in the store.
817 */
818 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle prime() functions"));
819 CFArrayApplyFunction(allBundles,
820 CFRangeMake(0, CFArrayGetCount(allBundles)),
821 callPrimeFunction,
822 NULL);
823
824 #ifdef DEBUG
825 if (arg == NULL && (nLoaded > 0)) {
826 CFRunLoopTimerRef timer;
827
828 /* allocate a periodic event (to help show we're not blocking) */
829 timer = CFRunLoopTimerCreate(NULL, /* allocator */
830 CFAbsoluteTimeGetCurrent() + 1.0, /* fireDate */
831 60.0, /* interval */
832 0, /* flags */
833 0, /* order */
834 timerCallback, /* callout */
835 NULL); /* context */
836 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
837 CFRelease(timer);
838 }
839 #endif /* DEBUG */
840
841 /*
842 * The assumption is that each loaded plugin will establish CFMachPortRef,
843 * CFSocketRef, and CFRunLoopTimerRef input sources to handle any events
844 * and register these sources with this threads run loop. If the plugin
845 * needs to wait and/or block at any time it should do so only in its a
846 * private thread.
847 */
848 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("starting plugin CFRunLoop"));
849 plugin_runLoop = CFRunLoopGetCurrent();
850 CFRunLoopRun();
851
852 SCLog(_configd_verbose, LOG_INFO, CFSTR("No more work for the \"configd\" plugins"));
853 plugin_runLoop = NULL;
854 return NULL;
855 }
856
857
858 __private_extern__
859 void
860 plugin_init()
861 {
862 pthread_attr_t tattr;
863 pthread_t tid;
864
865 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Starting thread for plug-ins..."));
866 pthread_attr_init(&tattr);
867 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
868 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
869 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
870 pthread_create(&tid, &tattr, plugin_exec, NULL);
871 pthread_attr_destroy(&tattr);
872 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" thread id=0x%08x"), tid);
873
874 return;
875 }