2 * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * October 30, 2003 Allan Nathanson <ajn@apple.com>
28 * - add plugin "stop()" function support
30 * June 11, 2001 Allan Nathanson <ajn@apple.com>
31 * - start using CFBundle code
33 * June 1, 2001 Allan Nathanson <ajn@apple.com>
34 * - public API conversion
36 * May 26, 2000 Allan Nathanson <ajn@apple.com>
40 #include <sys/types.h>
42 #include <sys/param.h>
47 #include <NSSystemDirectories.h>
50 #include "configd_server.h"
51 #include <SystemConfiguration/SCDPlugin.h>
52 void _SCDPluginExecInit();
56 * path components, extensions, entry points, ...
58 #define BUNDLE_DIRECTORY "/SystemConfiguration" /* [/System/Library]/... */
59 #define BUNDLE_DIR_EXTENSION ".bundle"
68 SCDynamicStoreBundleLoadFunction load
;
69 SCDynamicStoreBundleStartFunction start
;
70 SCDynamicStoreBundlePrimeFunction prime
;
71 SCDynamicStoreBundleStopFunction stop
;
76 static CFMutableArrayRef allBundles
= NULL
;
79 static CFMutableDictionaryRef exiting
= NULL
;
81 // plugin CFRunLoopRef
83 CFRunLoopRef plugin_runLoop
= NULL
;
86 extern SCDynamicStoreBundleLoadFunction load_IPMonitor
;
87 extern SCDynamicStoreBundlePrimeFunction prime_IPMonitor
;
88 extern SCDynamicStoreBundleLoadFunction load_InterfaceNamer
;
89 extern SCDynamicStoreBundleLoadFunction load_KernelEventMonitor
;
90 extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor
;
91 extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration
;
92 extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor
;
93 extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor
;
94 extern SCDynamicStoreBundleLoadFunction load_NetworkIdentification
;
95 extern SCDynamicStoreBundlePrimeFunction prime_NetworkIdentification
;
99 const CFStringRef bundleID
;
100 const void *load
; // SCDynamicStoreBundleLoadFunction
101 const void *start
; // SCDynamicStoreBundleStartFunction
102 const void *prime
; // SCDynamicStoreBundlePrimeFunction
103 const void *stop
; // SCDynamicStoreBundleStopFunction
104 } builtin
, *builtinRef
;
107 static const builtin builtin_plugins
[] = {
109 CFSTR("com.apple.SystemConfiguration.IPMonitor"),
116 CFSTR("com.apple.SystemConfiguration.InterfaceNamer"),
117 &load_InterfaceNamer
,
123 CFSTR("com.apple.SystemConfiguration.KernelEventMonitor"),
124 &load_KernelEventMonitor
,
126 &prime_KernelEventMonitor
,
130 CFSTR("com.apple.SystemConfiguration.LinkConfiguration"),
131 &load_LinkConfiguration
,
137 CFSTR("com.apple.SystemConfiguration.NetworkIdentification"),
138 &load_NetworkIdentification
,
140 &prime_NetworkIdentification
,
144 CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
145 &load_PreferencesMonitor
,
147 &prime_PreferencesMonitor
,
155 traceBundle(const char *op
, CFBundleRef bundle
)
157 if (_configd_trace
!= NULL
) {
158 if (bundle
!= NULL
) {
159 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
161 SCTrace(TRUE
, _configd_trace
,
162 CFSTR("bundle : %s %@\n"),
166 SCTrace(TRUE
, _configd_trace
,
167 CFSTR("bundle : %s\n"),
178 addBundle(CFBundleRef bundle
, Boolean forceEnabled
)
180 CFDictionaryRef bundleDict
;
181 bundleInfoRef bundleInfo
;
183 bundleInfo
= CFAllocatorAllocate(NULL
, sizeof(*bundleInfo
), 0);
184 bundleInfo
->bundle
= (CFBundleRef
)CFRetain(bundle
);
185 bundleInfo
->loaded
= FALSE
;
186 bundleInfo
->builtin
= FALSE
;
187 bundleInfo
->enabled
= TRUE
;
188 bundleInfo
->verbose
= FALSE
;
189 bundleInfo
->load
= NULL
;
190 bundleInfo
->start
= NULL
;
191 bundleInfo
->prime
= NULL
;
192 bundleInfo
->stop
= NULL
;
194 bundleDict
= CFBundleGetInfoDictionary(bundle
);
195 if (isA_CFDictionary(bundleDict
)) {
198 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleIsBuiltinKey
);
199 if (isA_CFBoolean(bVal
)) {
200 bundleInfo
->builtin
= CFBooleanGetValue(bVal
);
203 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleEnabledKey
);
204 if (isA_CFBoolean(bVal
)) {
205 bundleInfo
->enabled
= CFBooleanGetValue(bVal
);
208 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleVerboseKey
);
209 if (isA_CFBoolean(bVal
)) {
210 bundleInfo
->verbose
= CFBooleanGetValue(bVal
);
215 bundleInfo
->enabled
= TRUE
;
218 CFArrayAppendValue(allBundles
, bundleInfo
);
224 shortBundleIdentifier(CFStringRef bundleID
)
226 CFIndex len
= CFStringGetLength(bundleID
);
228 CFStringRef shortID
= NULL
;
230 if (CFStringFindWithOptions(bundleID
,
235 range
.location
= range
.location
+ range
.length
;
236 range
.length
= len
- range
.location
;
237 shortID
= CFStringCreateWithSubstring(NULL
, bundleID
, range
);
245 getBundleSymbol(CFBundleRef bundle
, CFStringRef functionName
, CFStringRef shortID
)
249 // search for load(), start(), prime(), stop(), ...
250 func
= CFBundleGetFunctionPointerForName(bundle
, functionName
);
255 if (shortID
!= NULL
) {
256 CFStringRef altFunctionName
;
258 // search for load_XXX(), ...
259 altFunctionName
= CFStringCreateWithFormat(NULL
,
264 func
= CFBundleGetFunctionPointerForName(bundle
, altFunctionName
);
265 CFRelease(altFunctionName
);
273 getBundleDirNameAndPath(CFBundleRef bundle
, char *buf
, size_t buf_len
)
280 url
= CFBundleCopyBundleURL(bundle
);
285 ok
= CFURLGetFileSystemRepresentation(url
, TRUE
, (UInt8
*)buf
, buf_len
);
291 cp
= strrchr(buf
, '/');
298 /* check if this directory entry is a valid bundle name */
300 if (len
<= (int)sizeof(BUNDLE_DIR_EXTENSION
)) {
301 /* if entry name isn't long enough */
305 len
-= sizeof(BUNDLE_DIR_EXTENSION
) - 1;
306 if (strcmp(&cp
[len
], BUNDLE_DIR_EXTENSION
) != 0) {
307 /* if entry name doesn't end with ".bundle" */
320 forkBundle_setup(pid_t pid
, void *setupContext
)
324 unsetenv("__LAUNCHD_FD");
325 setenv("__FORKED_PLUGIN__", "Yes", 1);
333 forkBundle(CFBundleRef bundle
, CFStringRef bundleID
)
335 char *argv
[] = { "configd", "-d", "-t", NULL
, NULL
};
337 char path
[MAXPATHLEN
];
340 // get the bundle's path
341 name
= getBundleDirNameAndPath(bundle
, path
, sizeof(path
));
343 SCLog(TRUE
, LOG_ERR
, CFSTR("skipped %@ (could not determine path)"), bundle
);
347 // fork and exec configd opting to load only this plugin
349 pid
= _SCDPluginExecCommand2(NULL
, NULL
, 0, 0, "/usr/libexec/configd", argv
, forkBundle_setup
, NULL
);
352 CFSTR("skipped %@ (could not exec child) : %s"),
358 SCLog(TRUE
, LOG_NOTICE
, CFSTR("forked %@, pid=%d"), bundleID
, pid
);
364 loadBundle(const void *value
, void *context
) {
365 CFStringRef bundleID
;
366 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
367 Boolean bundleExclude
;
368 CFIndex
*nLoaded
= (CFIndex
*)context
;
371 bundleID
= CFBundleGetIdentifier(bundleInfo
->bundle
);
372 if (bundleID
== NULL
) {
373 // sorry, no bundles without a bundle identifier
374 SCLog(TRUE
, LOG_NOTICE
, CFSTR("skipped %@ (no bundle ID)"), bundleInfo
->bundle
);
378 shortID
= shortBundleIdentifier(bundleID
);
380 bundleExclude
= CFSetContainsValue(_plugins_exclude
, bundleID
);
381 if (!bundleExclude
) {
382 if (shortID
!= NULL
) {
383 bundleExclude
= CFSetContainsValue(_plugins_exclude
, shortID
);
388 // sorry, this bundle has been excluded
389 SCLog(TRUE
, LOG_NOTICE
, CFSTR("skipped %@ (excluded)"), bundleID
);
393 if (!bundleInfo
->enabled
) {
394 // sorry, this bundle has not been enabled
395 SCLog(TRUE
, LOG_INFO
, CFSTR("skipped %@ (disabled)"), bundleID
);
400 forkBundle(bundleInfo
->bundle
, bundleID
);
404 if (!bundleInfo
->verbose
) {
405 bundleInfo
->verbose
= CFSetContainsValue(_plugins_verbose
, bundleID
);
406 if (!bundleInfo
->verbose
) {
407 if (shortID
!= NULL
) {
408 bundleInfo
->verbose
= CFSetContainsValue(_plugins_verbose
, shortID
);
413 if (bundleInfo
->builtin
) {
416 SCLog(TRUE
, LOG_DEBUG
, CFSTR("adding %@"), bundleID
);
418 for (i
= 0; i
< sizeof(builtin_plugins
)/sizeof(builtin_plugins
[0]); i
++) {
419 if (CFEqual(bundleID
, builtin_plugins
[i
].bundleID
)) {
420 bundleInfo
->load
= builtin_plugins
[i
].load
;
421 bundleInfo
->start
= builtin_plugins
[i
].start
;
422 bundleInfo
->prime
= builtin_plugins
[i
].prime
;
423 bundleInfo
->stop
= builtin_plugins
[i
].stop
;
428 if ((bundleInfo
->load
== NULL
) &&
429 (bundleInfo
->start
== NULL
) &&
430 (bundleInfo
->prime
== NULL
) &&
431 (bundleInfo
->stop
== NULL
)) {
432 SCLog(TRUE
, LOG_NOTICE
, CFSTR("%@ add failed"), bundleID
);
436 CFErrorRef error
= NULL
;
438 SCLog(TRUE
, LOG_DEBUG
, CFSTR("loading %@"), bundleID
);
441 traceBundle("loading", bundleInfo
->bundle
);
444 if (!CFBundleLoadExecutableAndReturnError(bundleInfo
->bundle
, &error
)) {
445 CFStringRef description
;
447 description
= CFErrorCopyDescription(error
);
448 SCLog(TRUE
, LOG_NOTICE
, CFSTR("%@ load failed"), bundleID
);
449 SCLog(TRUE
, LOG_NOTICE
, CFSTR(" %@"), description
);
450 CFRelease(description
);
455 // get bundle entry points
456 bundleInfo
->load
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("load" ), shortID
);
457 bundleInfo
->start
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("start"), shortID
);
458 bundleInfo
->prime
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("prime"), shortID
);
459 bundleInfo
->stop
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("stop" ), shortID
);
462 /* mark this bundle as having been loaded */
463 bundleInfo
->loaded
= TRUE
;
465 /* bump the count of loaded bundles */
466 *nLoaded
= *nLoaded
+ 1;
470 if (shortID
!= NULL
) CFRelease(shortID
);
476 callLoadFunction(const void *value
, void *context
) {
477 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
479 if (!bundleInfo
->loaded
) {
483 if (bundleInfo
->load
== NULL
) {
484 // if no load() function
489 traceBundle("calling load() for", bundleInfo
->bundle
);
492 (*bundleInfo
->load
)(bundleInfo
->bundle
, bundleInfo
->verbose
);
503 callStartFunction(const void *value
, void *context
) {
504 const char *bundleDirName
;
505 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
506 char bundleName
[MAXNAMLEN
+ 1];
507 char bundlePath
[MAXPATHLEN
];
510 if (!bundleInfo
->loaded
) {
514 if (bundleInfo
->start
== NULL
) {
515 // if no start() function
519 /* copy the bundle's path */
520 bundleDirName
= getBundleDirNameAndPath(bundleInfo
->bundle
, bundlePath
, sizeof(bundlePath
));
521 if (bundleDirName
== NULL
) {
522 // if we have a problem with the bundle's path
526 /* copy (just) the bundle's name */
527 if (strlcpy(bundleName
, bundleDirName
, sizeof(bundleName
)) > sizeof(bundleName
)) {
528 // if we have a problem with the bundle's name
531 len
= strlen(bundleName
) - (sizeof(BUNDLE_DIR_EXTENSION
) - 1);
532 bundleName
[len
] = '\0';
535 traceBundle("calling start() for", bundleInfo
->bundle
);
538 (*bundleInfo
->start
)(bundleName
, bundlePath
);
549 callPrimeFunction(const void *value
, void *context
) {
550 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
552 if (!bundleInfo
->loaded
) {
556 if (bundleInfo
->prime
== NULL
) {
557 // if no prime() function
562 traceBundle("calling prime() for", bundleInfo
->bundle
);
565 (*bundleInfo
->prime
)();
576 stopComplete(void *info
)
578 CFBundleRef bundle
= (CFBundleRef
)info
;
579 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
580 CFRunLoopSourceRef stopRls
;
582 SCLog(TRUE
, LOG_DEBUG
, CFSTR("** %@ complete (%f)"), bundleID
, CFAbsoluteTimeGetCurrent());
584 stopRls
= (CFRunLoopSourceRef
)CFDictionaryGetValue(exiting
, bundle
);
585 if (stopRls
== NULL
) {
589 CFRunLoopSourceInvalidate(stopRls
);
591 CFDictionaryRemoveValue(exiting
, bundle
);
593 if (CFDictionaryGetCount(exiting
) == 0) {
596 // if all of the plugins are happy
597 status
= server_shutdown();
598 SCLog(TRUE
, LOG_DEBUG
, CFSTR("server shutdown complete (%f)"), CFAbsoluteTimeGetCurrent());
607 stopDelayed(CFRunLoopTimerRef timer
, void *info
)
614 SCLog(TRUE
, LOG_ERR
, CFSTR("server shutdown was delayed, unresponsive plugins:"));
617 * we've asked our plugins to shutdown but someone
620 n
= CFDictionaryGetCount(exiting
);
621 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
622 CFDictionaryGetKeysAndValues(exiting
, keys
, NULL
);
623 for (i
= 0; i
< n
; i
++) {
625 CFStringRef bundleID
;
627 bundle
= (CFBundleRef
)keys
[i
];
628 bundleID
= CFBundleGetIdentifier(bundle
);
629 SCLog(TRUE
, LOG_ERR
, CFSTR("** %@"), bundleID
);
631 CFAllocatorDeallocate(NULL
, keys
);
633 status
= server_shutdown();
638 stopRLSCopyDescription(const void *info
)
640 CFBundleRef bundle
= (CFBundleRef
)info
;
642 return CFStringCreateWithFormat(NULL
,
644 CFSTR("<stopRLS %p> {bundleID = %@}"),
646 CFBundleGetIdentifier(bundle
));
651 stopBundle(const void *value
, void *context
) {
652 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
653 CFRunLoopSourceRef stopRls
;
654 CFRunLoopSourceContext stopContext
= { 0 // version
655 , bundleInfo
->bundle
// info
657 , CFRelease
// release
658 , stopRLSCopyDescription
// copyDescription
663 , stopComplete
// perform
666 if (!bundleInfo
->loaded
) {
670 if (bundleInfo
->stop
== NULL
) {
671 // if no stop() function
675 stopRls
= CFRunLoopSourceCreate(NULL
, 0, &stopContext
);
676 CFRunLoopAddSource(CFRunLoopGetCurrent(), stopRls
, kCFRunLoopDefaultMode
);
677 CFDictionaryAddValue(exiting
, bundleInfo
->bundle
, stopRls
);
680 (*bundleInfo
->stop
)(stopRls
);
690 * If defined, call each bundles stop() function. This function is
691 * called when configd has been asked to shut down (via a SIGTERM). The
692 * function should signal the provided run loop source when it is "ready"
693 * for the shut down to proceeed.
695 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("calling bundle stop() functions"));
696 CFArrayApplyFunction(allBundles
,
697 CFRangeMake(0, CFArrayGetCount(allBundles
)),
701 if (CFDictionaryGetCount(exiting
) == 0) {
704 // if all of the plugins are happy
705 status
= server_shutdown();
706 SCLog(TRUE
, LOG_DEBUG
, CFSTR("server shutdown complete (%f)"), CFAbsoluteTimeGetCurrent());
709 CFRunLoopTimerRef timer
;
712 * launchd will only wait 20 seconds before sending us a
713 * SIGKILL and because we want to know what's stuck before
714 * that time so set our own "we're not waiting any longer"
715 * timeout for 15 seconds.
717 timer
= CFRunLoopTimerCreate(NULL
, /* allocator */
718 CFAbsoluteTimeGetCurrent() + 15.0, /* fireDate (in 15 seconds) */
719 0.0, /* interval (== one-shot) */
722 stopDelayed
, /* callout */
724 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
);
737 termRLSCopyDescription(const void *info
)
739 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SIGTERM RLS>"));
745 plugin_term(int *status
)
747 CFRunLoopSourceContext termContext
= { 0 // version
751 , termRLSCopyDescription
// copyDescription
756 , stopBundles
// perform
758 CFRunLoopSourceRef termRls
;
760 if (plugin_runLoop
== NULL
) {
763 return FALSE
; // don't delay shutdown
766 if (exiting
!= NULL
) {
767 // if shutdown already active
771 SCLog(TRUE
, LOG_DEBUG
, CFSTR("starting server shutdown (%f)"), CFAbsoluteTimeGetCurrent());
773 exiting
= CFDictionaryCreateMutable(NULL
,
775 &kCFTypeDictionaryKeyCallBacks
,
776 &kCFTypeDictionaryValueCallBacks
);
778 termRls
= CFRunLoopSourceCreate(NULL
, 0, &termContext
);
779 CFRunLoopAddSource(plugin_runLoop
, termRls
, kCFRunLoopDefaultMode
);
780 CFRunLoopSourceSignal(termRls
);
782 CFRunLoopWakeUp(plugin_runLoop
);
789 #pragma mark initialization
794 timerCallback(CFRunLoopTimerRef timer
, void *info
)
799 if ((pass
> 120) && ((pass
% 60) != 0)) {
803 traceBundle("the [plugin] CFRunLoop is waiting...", NULL
);
810 sortBundles(CFMutableArrayRef orig
)
812 CFMutableArrayRef
new;
814 new = CFArrayCreateMutable(NULL
, 0, NULL
);
815 while (CFArrayGetCount(orig
) > 0) {
817 Boolean inserted
= FALSE
;
818 int nOrig
= CFArrayGetCount(orig
);
820 for (i
= 0; i
< nOrig
; i
++) {
821 bundleInfoRef bundleInfo1
= (bundleInfoRef
)CFArrayGetValueAtIndex(orig
, i
);
822 CFStringRef bundleID1
= CFBundleGetIdentifier(bundleInfo1
->bundle
);
824 CFDictionaryRef dict
;
827 CFArrayRef
requires = NULL
;
829 dict
= isA_CFDictionary(CFBundleGetInfoDictionary(bundleInfo1
->bundle
));
831 requires = CFDictionaryGetValue(dict
, kSCBundleRequiresKey
);
832 requires = isA_CFArray(requires);
834 if (bundleID1
== NULL
|| requires == NULL
) {
835 CFArrayInsertValueAtIndex(new, 0, bundleInfo1
);
836 CFArrayRemoveValueAtIndex(orig
, i
);
840 count
= nRequires
= CFArrayGetCount(requires);
841 for (j
= 0; j
< nRequires
; j
++) {
844 CFStringRef r
= CFArrayGetValueAtIndex(requires, j
);
846 nNew
= CFArrayGetCount(new);
847 for (k
= 0; k
< nNew
; k
++) {
848 bundleInfoRef bundleInfo2
= (bundleInfoRef
)CFArrayGetValueAtIndex(new, k
);
849 CFStringRef bundleID2
= CFBundleGetIdentifier(bundleInfo2
->bundle
);
851 if (bundleID2
&& CFEqual(bundleID2
, r
)) {
857 /* all dependencies are met, append */
858 CFArrayAppendValue(new, bundleInfo1
);
859 CFArrayRemoveValueAtIndex(orig
, i
);
865 if (inserted
== FALSE
) {
866 SCLog(TRUE
, LOG_NOTICE
, CFSTR("Bundles have circular dependency!!!"));
870 if (CFArrayGetCount(orig
) > 0) {
871 /* we have a circular dependency, append remaining items on new array */
872 CFArrayAppendArray(new, orig
, CFRangeMake(0, CFArrayGetCount(orig
)));
875 /* new one is a sorted version of original */
878 CFArrayRemoveAllValues(orig
);
879 CFArrayAppendArray(orig
, new, CFRangeMake(0, CFArrayGetCount(new)));
888 * An alternate CFRelease() that we can use to fake out the
891 static __inline__
void
892 ALT_CFRelease(CFTypeRef cf
)
900 plugin_exec(void *arg
)
904 /* keep track of bundles */
905 allBundles
= CFArrayCreateMutable(NULL
, 0, NULL
);
907 /* allow plug-ins to exec child/helper processes */
908 _SCDPluginExecInit();
911 char path
[MAXPATHLEN
];
912 NSSearchPathEnumerationState state
;
915 * identify and load all bundles
917 state
= NSStartSearchPathEnumeration(NSLibraryDirectory
,
919 while ((state
= NSGetNextSearchPathEnumeration(state
, path
))) {
923 /* load any available bundle */
924 strlcat(path
, BUNDLE_DIRECTORY
, sizeof(path
));
925 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("searching for bundles in \".\""));
926 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
930 bundles
= CFBundleCreateBundlesFromDirectory(NULL
, url
, CFSTR(".bundle"));
933 if (bundles
!= NULL
) {
937 n
= CFArrayGetCount(bundles
);
938 for (i
= 0; i
< n
; i
++) {
941 bundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundles
, i
);
942 addBundle(bundle
, FALSE
);
944 // The CFBundleCreateBundlesFromDirectory() API has
945 // a known/outstanding bug in that it over-retains the
946 // returned bundles. Since we do not expect this to
947 // be fixed we release the extra references.
949 // See <rdar://problems/4912137&6078752> for more info.
951 // Also, we use the hack below to keep the static
953 ALT_CFRelease(bundle
);
959 sortBundles(allBundles
);
965 * load (only) the specified bundle
967 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
971 bundle
= CFBundleCreate(NULL
, url
);
972 if (bundle
!= NULL
) {
973 addBundle(bundle
, TRUE
);
980 traceBundle("before loading any plugins", NULL
);
986 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("loading bundles"));
987 CFArrayApplyFunction(allBundles
,
988 CFRangeMake(0, CFArrayGetCount(allBundles
)),
993 * If defined, call each bundles load() function. This function (or
994 * the start() function) should initialize any variables, open any
995 * sessions with "configd", and register any needed notifications.
997 * Note: Establishing initial information in the store should be
998 * deferred until the prime() initialization function so that
999 * any bundles which want to receive a notification that the
1000 * data has changed will have an opportunity to install a
1001 * notification handler.
1003 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("calling bundle load() functions"));
1004 CFArrayApplyFunction(allBundles
,
1005 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1010 // if no bundles loaded
1015 * If defined, call each bundles start() function. This function is
1016 * called after the bundle has been loaded and its load() function has
1017 * been called. It should initialize any variables, open any sessions
1018 * with "configd", and register any needed notifications.
1020 * Note: Establishing initial information in the store should be
1021 * deferred until the prime() initialization function so that
1022 * any bundles which want to receive a notification that the
1023 * data has changed will have an opportunity to install a
1024 * notification handler.
1026 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("calling bundle start() functions"));
1027 CFArrayApplyFunction(allBundles
,
1028 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1033 * If defined, call each bundles prime() function. This function is
1034 * called after the bundle has been loaded and its load() and start()
1035 * functions have been called. It should initialize any configuration
1036 * information and/or state in the store.
1038 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("calling bundle prime() functions"));
1039 CFArrayApplyFunction(allBundles
,
1040 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1045 if (arg
== NULL
&& (nLoaded
> 0)) {
1046 CFRunLoopTimerRef timer
;
1048 /* allocate a periodic event (to help show we're not blocking) */
1049 timer
= CFRunLoopTimerCreate(NULL
, /* allocator */
1050 CFAbsoluteTimeGetCurrent() + 1.0, /* fireDate */
1054 timerCallback
, /* callout */
1055 NULL
); /* context */
1056 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
);
1062 traceBundle("about to start plugin CFRunLoop", NULL
);
1066 * The assumption is that each loaded plugin will establish CFMachPortRef,
1067 * CFSocketRef, and CFRunLoopTimerRef input sources to handle any events
1068 * and register these sources with this threads run loop. If the plugin
1069 * needs to wait and/or block at any time it should do so only in its a
1072 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("starting plugin CFRunLoop"));
1073 plugin_runLoop
= CFRunLoopGetCurrent();
1074 pthread_setname_np("Main plugin thread");
1079 SCLog(_configd_verbose
, LOG_INFO
, CFSTR("No more work for the \"configd\" plugins"));
1080 plugin_runLoop
= NULL
;
1089 pthread_attr_t tattr
;
1092 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("Starting thread for plug-ins..."));
1093 pthread_attr_init(&tattr
);
1094 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
1095 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
1096 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
1097 pthread_create(&tid
, &tattr
, plugin_exec
, NULL
);
1098 pthread_attr_destroy(&tattr
);
1099 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR(" thread id=0x%08x"), tid
);