2 * Copyright (c) 2000-2015 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 #include "SCNetworkReachabilityInternal.h"
53 void _SCDPluginExecInit();
57 * path components, extensions, entry points, ...
59 #define BUNDLE_DIRECTORY "/SystemConfiguration" /* [/System/Library]/... */
60 #define BUNDLE_DIR_EXTENSION ".bundle"
63 #define PLUGIN_ALL(p) CFSTR(p)
65 #define PLUGIN_MACOSX(p) CFSTR(p)
66 #define PLUGIN_IOS(p) NULL
67 #else // !TARGET_OS_IPHONE
68 #define PLUGIN_MACOSX(p) NULL
69 #define PLUGIN_IOS(p) CFSTR(p)
70 #endif // !TARGET_OS_IPHONE
72 // white-listed (ok-to-load) bundle identifiers
73 static const CFStringRef pluginWhitelist
[] = {
74 PLUGIN_MACOSX("com.apple.SystemConfiguration.ApplicationFirewall"),
75 PLUGIN_ALL ("com.apple.SystemConfiguration.EAPOLController"),
76 PLUGIN_ALL ("com.apple.SystemConfiguration.IPConfiguration"),
77 PLUGIN_ALL ("com.apple.SystemConfiguration.IPMonitor"),
78 PLUGIN_MACOSX("com.apple.SystemConfiguration.ISPreference"),
79 PLUGIN_ALL ("com.apple.SystemConfiguration.InterfaceNamer"),
80 PLUGIN_ALL ("com.apple.SystemConfiguration.KernelEventMonitor"),
81 PLUGIN_ALL ("com.apple.SystemConfiguration.LinkConfiguration"),
82 PLUGIN_ALL ("com.apple.SystemConfiguration.Logger"),
83 PLUGIN_ALL ("com.apple.SystemConfiguration.PPPController"),
84 PLUGIN_ALL ("com.apple.SystemConfiguration.PreferencesMonitor"),
85 PLUGIN_ALL ("com.apple.SystemConfiguration.SCNetworkReachability"),
86 PLUGIN_MACOSX("com.apple.print.notification"),
88 #define N_PLUGIN_WHITELIST (sizeof(pluginWhitelist) / sizeof(pluginWhitelist[0]))
98 SCDynamicStoreBundleLoadFunction load
;
99 SCDynamicStoreBundleStartFunction start
;
100 SCDynamicStoreBundlePrimeFunction prime
;
101 SCDynamicStoreBundleStopFunction stop
;
105 // all loaded bundles
106 static CFMutableArrayRef allBundles
= NULL
;
109 static CFMutableDictionaryRef exiting
= NULL
;
111 // plugin CFRunLoopRef
113 CFRunLoopRef plugin_runLoop
= NULL
;
116 extern SCDynamicStoreBundleLoadFunction load_IPMonitor
;
117 extern SCDynamicStoreBundlePrimeFunction prime_IPMonitor
;
118 #if !TARGET_IPHONE_SIMULATOR
119 extern SCDynamicStoreBundleLoadFunction load_InterfaceNamer
;
120 extern SCDynamicStoreBundleLoadFunction load_KernelEventMonitor
;
121 extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor
;
122 extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration
;
123 extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor
;
124 extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor
;
125 #endif // !TARGET_IPHONE_SIMULATOR
129 const CFStringRef bundleID
;
130 const void *load
; // SCDynamicStoreBundleLoadFunction
131 const void *start
; // SCDynamicStoreBundleStartFunction
132 const void *prime
; // SCDynamicStoreBundlePrimeFunction
133 const void *stop
; // SCDynamicStoreBundleStopFunction
134 } builtin
, *builtinRef
;
137 static const builtin builtin_plugins
[] = {
139 CFSTR("com.apple.SystemConfiguration.IPMonitor"),
145 #if !TARGET_IPHONE_SIMULATOR
147 CFSTR("com.apple.SystemConfiguration.InterfaceNamer"),
148 &load_InterfaceNamer
,
154 CFSTR("com.apple.SystemConfiguration.KernelEventMonitor"),
155 &load_KernelEventMonitor
,
157 &prime_KernelEventMonitor
,
161 CFSTR("com.apple.SystemConfiguration.LinkConfiguration"),
162 &load_LinkConfiguration
,
168 CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
169 &load_PreferencesMonitor
,
171 &prime_PreferencesMonitor
,
174 #endif // !TARGET_IPHONE_SIMULATOR
180 traceBundle(const char *op
, CFBundleRef bundle
)
182 if (bundle
!= NULL
) {
183 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
185 SC_trace(_configd_trace
, "bundle : %s %@\n",
189 SC_trace(_configd_trace
, "bundle : %s\n",
193 const char *path
= getenv("LOG_CONFIGD_BUNDLE_USAGE");
199 file
= fopen(path
, "a");
204 // let everything settle down before grabbing a snapshot
207 SCPrint(TRUE
, file
, CFSTR("\n--------------------\n\n"), op
);
208 if (bundle
!= NULL
) {
209 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
211 SC_trace(file
, "%s bundle \"%@\"\n\n", op
, bundleID
);
213 SC_trace(file
, "%s\n\n", op
);
215 SCPrint(TRUE
, file
, CFSTR("%@\n\n"), CFRunLoopGetCurrent());
218 if (asprintf(&top_command
, "/usr/bin/top -o+pid -l 1 >> %s", path
) == -1) {
222 status
= system(top_command
);
223 if ((status
== -1) ||
224 !WIFEXITED(status
) ||
225 (WEXITSTATUS(status
) != 0)) {
226 SC_log(LOG_NOTICE
, "system(\"%s\") failed", top_command
);
237 addBundle(CFBundleRef bundle
, Boolean forceEnabled
)
239 CFDictionaryRef bundleDict
;
240 bundleInfoRef bundleInfo
;
242 bundleInfo
= CFAllocatorAllocate(NULL
, sizeof(*bundleInfo
), 0);
243 bundleInfo
->bundle
= (CFBundleRef
)CFRetain(bundle
);
244 bundleInfo
->loaded
= FALSE
;
245 bundleInfo
->builtin
= FALSE
;
246 bundleInfo
->enabled
= TRUE
;
247 bundleInfo
->forced
= forceEnabled
;
248 bundleInfo
->verbose
= FALSE
;
249 bundleInfo
->load
= NULL
;
250 bundleInfo
->start
= NULL
;
251 bundleInfo
->prime
= NULL
;
252 bundleInfo
->stop
= NULL
;
254 bundleDict
= CFBundleGetInfoDictionary(bundle
);
255 if (isA_CFDictionary(bundleDict
)) {
258 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleIsBuiltinKey
);
259 if (isA_CFBoolean(bVal
)) {
260 bundleInfo
->builtin
= CFBooleanGetValue(bVal
);
263 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleEnabledKey
);
264 if (isA_CFBoolean(bVal
)) {
265 bundleInfo
->enabled
= CFBooleanGetValue(bVal
);
268 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleVerboseKey
);
269 if (isA_CFBoolean(bVal
)) {
270 bundleInfo
->verbose
= CFBooleanGetValue(bVal
);
274 CFArrayAppendValue(allBundles
, bundleInfo
);
279 static CF_RETURNS_RETAINED CFStringRef
280 shortBundleIdentifier(CFStringRef bundleID
)
282 CFIndex len
= CFStringGetLength(bundleID
);
284 CFStringRef shortID
= NULL
;
286 if (CFStringFindWithOptions(bundleID
,
291 range
.location
= range
.location
+ range
.length
;
292 range
.length
= len
- range
.location
;
293 shortID
= CFStringCreateWithSubstring(NULL
, bundleID
, range
);
301 getBundleSymbol(CFBundleRef bundle
, CFStringRef functionName
, CFStringRef shortID
)
305 // search for load(), start(), prime(), stop(), ...
306 func
= CFBundleGetFunctionPointerForName(bundle
, functionName
);
311 if (shortID
!= NULL
) {
312 CFStringRef altFunctionName
;
314 // search for load_XXX(), ...
315 altFunctionName
= CFStringCreateWithFormat(NULL
,
320 func
= CFBundleGetFunctionPointerForName(bundle
, altFunctionName
);
321 CFRelease(altFunctionName
);
329 getBundleDirNameAndPath(CFBundleRef bundle
, char *buf
, size_t buf_len
)
336 url
= CFBundleCopyBundleURL(bundle
);
341 ok
= CFURLGetFileSystemRepresentation(url
, TRUE
, (UInt8
*)buf
, buf_len
);
347 cp
= strrchr(buf
, '/');
354 /* check if this directory entry is a valid bundle name */
356 if (len
<= sizeof(BUNDLE_DIR_EXTENSION
)) {
357 /* if entry name isn't long enough */
361 len
-= sizeof(BUNDLE_DIR_EXTENSION
) - 1;
362 if (strcmp(&cp
[len
], BUNDLE_DIR_EXTENSION
) != 0) {
363 /* if entry name doesn't end with ".bundle" */
376 loadBundle(const void *value
, void *context
) {
377 CFStringRef bundleID
;
378 Boolean bundleAllowed
;
379 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
380 Boolean bundleExclude
;
381 CFIndex
*nLoaded
= (CFIndex
*)context
;
384 bundleID
= CFBundleGetIdentifier(bundleInfo
->bundle
);
385 if (bundleID
== NULL
) {
386 // sorry, no bundles without a bundle identifier
387 SC_log(LOG_NOTICE
, "skipped %@ (no bundle ID)", bundleInfo
->bundle
);
391 shortID
= shortBundleIdentifier(bundleID
);
393 bundleAllowed
= ((CFSetGetCount(_plugins_allowed
) == 0) || // if no white-listing
394 CFSetContainsValue(_plugins_allowed
, bundleID
) || // if [bundleID] white-listed
395 ((shortID
!= NULL
) &&
396 CFSetContainsValue(_plugins_allowed
, shortID
))|| // if [short bundleID] white-listed
397 bundleInfo
->forced
// if "testing" plugin
399 if (!bundleAllowed
) {
400 SC_log(LOG_INFO
, "skipped %@ (not allowed)", bundleID
);
404 bundleExclude
= (CFSetContainsValue(_plugins_exclude
, bundleID
) || // if [bundleID] excluded
405 ((shortID
!= NULL
) &&
406 CFSetContainsValue(_plugins_exclude
, shortID
)) // if [short bundleID] excluded
409 // sorry, this bundle has been excluded
410 SC_log(LOG_INFO
, "skipped %@ (excluded)", bundleID
);
414 if (!bundleInfo
->enabled
&& !bundleInfo
->forced
) {
415 // sorry, this bundle has not been enabled
416 SC_log(LOG_INFO
, "skipped %@ (disabled)", bundleID
);
420 if (!bundleInfo
->verbose
) {
421 bundleInfo
->verbose
= CFSetContainsValue(_plugins_verbose
, bundleID
);
422 if (!bundleInfo
->verbose
) {
423 if (shortID
!= NULL
) {
424 bundleInfo
->verbose
= CFSetContainsValue(_plugins_verbose
, shortID
);
429 if (bundleInfo
->builtin
) {
432 SC_log(LOG_INFO
, "adding %@", bundleID
);
434 for (i
= 0; i
< sizeof(builtin_plugins
)/sizeof(builtin_plugins
[0]); i
++) {
435 if (CFEqual(bundleID
, builtin_plugins
[i
].bundleID
)) {
436 bundleInfo
->load
= builtin_plugins
[i
].load
;
437 bundleInfo
->start
= builtin_plugins
[i
].start
;
438 bundleInfo
->prime
= builtin_plugins
[i
].prime
;
439 bundleInfo
->stop
= builtin_plugins
[i
].stop
;
444 if ((bundleInfo
->load
== NULL
) &&
445 (bundleInfo
->start
== NULL
) &&
446 (bundleInfo
->prime
== NULL
) &&
447 (bundleInfo
->stop
== NULL
)) {
448 SC_log(LOG_NOTICE
, "%@ add failed", bundleID
);
452 CFErrorRef error
= NULL
;
454 SC_log(LOG_INFO
, "loading %@", bundleID
);
457 traceBundle("loading", bundleInfo
->bundle
);
460 if (!CFBundleLoadExecutableAndReturnError(bundleInfo
->bundle
, &error
)) {
461 CFDictionaryRef user_info
;
463 SC_log(LOG_NOTICE
, "%@ load failed", bundleID
);
464 user_info
= CFErrorCopyUserInfo(error
);
465 if (user_info
!= NULL
) {
466 CFStringRef link_error_string
;
468 link_error_string
= CFDictionaryGetValue(user_info
,
469 CFSTR("NSDebugDescription"));
470 if (link_error_string
!= NULL
) {
471 SC_log(LOG_NOTICE
, "%@", link_error_string
);
473 CFRelease(user_info
);
479 // get bundle entry points
480 bundleInfo
->load
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("load" ), shortID
);
481 bundleInfo
->start
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("start"), shortID
);
482 bundleInfo
->prime
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("prime"), shortID
);
483 bundleInfo
->stop
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("stop" ), shortID
);
486 /* mark this bundle as having been loaded */
487 bundleInfo
->loaded
= TRUE
;
489 /* bump the count of loaded bundles */
490 *nLoaded
= *nLoaded
+ 1;
494 if (shortID
!= NULL
) CFRelease(shortID
);
500 callLoadFunction(const void *value
, void *context
) {
501 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
503 if (!bundleInfo
->loaded
) {
507 if (bundleInfo
->load
== NULL
) {
508 // if no load() function
513 traceBundle("calling load() for", bundleInfo
->bundle
);
516 (*bundleInfo
->load
)(bundleInfo
->bundle
, bundleInfo
->verbose
);
527 callStartFunction(const void *value
, void *context
) {
528 const char *bundleDirName
;
529 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
530 char bundleName
[MAXNAMLEN
+ 1];
531 char bundlePath
[MAXPATHLEN
];
534 if (!bundleInfo
->loaded
) {
538 if (bundleInfo
->start
== NULL
) {
539 // if no start() function
543 /* copy the bundle's path */
544 bundleDirName
= getBundleDirNameAndPath(bundleInfo
->bundle
, bundlePath
, sizeof(bundlePath
));
545 if (bundleDirName
== NULL
) {
546 // if we have a problem with the bundle's path
550 /* copy (just) the bundle's name */
551 if (strlcpy(bundleName
, bundleDirName
, sizeof(bundleName
)) > sizeof(bundleName
)) {
552 // if we have a problem with the bundle's name
555 len
= strlen(bundleName
) - (sizeof(BUNDLE_DIR_EXTENSION
) - 1);
556 bundleName
[len
] = '\0';
559 traceBundle("calling start() for", bundleInfo
->bundle
);
562 (*bundleInfo
->start
)(bundleName
, bundlePath
);
573 callPrimeFunction(const void *value
, void *context
) {
574 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
576 if (!bundleInfo
->loaded
) {
580 if (bundleInfo
->prime
== NULL
) {
581 // if no prime() function
586 traceBundle("calling prime() for", bundleInfo
->bundle
);
589 (*bundleInfo
->prime
)();
600 stopComplete(void *info
)
602 CFBundleRef bundle
= (CFBundleRef
)info
;
603 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
604 CFRunLoopSourceRef stopRls
;
606 SC_log(LOG_INFO
, "** %@ complete (%f)", bundleID
, CFAbsoluteTimeGetCurrent());
608 stopRls
= (CFRunLoopSourceRef
)CFDictionaryGetValue(exiting
, bundle
);
609 if (stopRls
== NULL
) {
613 CFRunLoopSourceInvalidate(stopRls
);
615 CFDictionaryRemoveValue(exiting
, bundle
);
617 if (CFDictionaryGetCount(exiting
) == 0) {
620 // if all of the plugins are happy
621 status
= server_shutdown();
622 SC_log(LOG_INFO
, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent());
631 stopDelayed(CFRunLoopTimerRef timer
, void *info
)
638 SC_log(LOG_INFO
, "server shutdown was delayed, unresponsive plugins:");
641 * we've asked our plugins to shutdown but someone
644 n
= CFDictionaryGetCount(exiting
);
645 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
646 CFDictionaryGetKeysAndValues(exiting
, keys
, NULL
);
647 for (i
= 0; i
< n
; i
++) {
649 CFStringRef bundleID
;
651 bundle
= (CFBundleRef
)keys
[i
];
652 bundleID
= CFBundleGetIdentifier(bundle
);
653 SC_log(LOG_NOTICE
, "** %@", bundleID
);
655 CFAllocatorDeallocate(NULL
, keys
);
657 status
= server_shutdown();
662 stopRLSCopyDescription(const void *info
)
664 CFBundleRef bundle
= (CFBundleRef
)info
;
666 return CFStringCreateWithFormat(NULL
,
668 CFSTR("<stopRLS %p> {bundleID = %@}"),
670 CFBundleGetIdentifier(bundle
));
675 stopBundle(const void *value
, void *context
) {
676 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
677 CFRunLoopSourceRef stopRls
;
678 CFRunLoopSourceContext stopContext
= { 0 // version
679 , bundleInfo
->bundle
// info
681 , CFRelease
// release
682 , stopRLSCopyDescription
// copyDescription
687 , stopComplete
// perform
690 if (!bundleInfo
->loaded
) {
694 if (bundleInfo
->stop
== NULL
) {
695 // if no stop() function
699 stopRls
= CFRunLoopSourceCreate(NULL
, 0, &stopContext
);
700 CFRunLoopAddSource(CFRunLoopGetCurrent(), stopRls
, kCFRunLoopDefaultMode
);
701 CFDictionaryAddValue(exiting
, bundleInfo
->bundle
, stopRls
);
704 (*bundleInfo
->stop
)(stopRls
);
714 * If defined, call each bundles stop() function. This function is
715 * called when configd has been asked to shut down (via a SIGTERM). The
716 * function should signal the provided run loop source when it is "ready"
717 * for the shut down to proceeed.
719 SC_log(LOG_DEBUG
, "calling bundle stop() functions");
720 CFArrayApplyFunction(allBundles
,
721 CFRangeMake(0, CFArrayGetCount(allBundles
)),
725 if (CFDictionaryGetCount(exiting
) == 0) {
728 // if all of the plugins are happy
729 status
= server_shutdown();
730 SC_log(LOG_INFO
, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent());
733 CFRunLoopTimerRef timer
;
736 * launchd will only wait 20 seconds before sending us a
737 * SIGKILL and because we want to know what's stuck before
738 * that time so set our own "we're not waiting any longer"
739 * timeout for 15 seconds.
741 timer
= CFRunLoopTimerCreate(NULL
, /* allocator */
742 CFAbsoluteTimeGetCurrent() + 15.0, /* fireDate (in 15 seconds) */
743 0.0, /* interval (== one-shot) */
746 stopDelayed
, /* callout */
748 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
);
761 termRLSCopyDescription(const void *info
)
763 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SIGTERM RLS>"));
769 plugin_term(int *status
)
771 CFRunLoopSourceContext termContext
= { 0 // version
775 , termRLSCopyDescription
// copyDescription
780 , stopBundles
// perform
782 CFRunLoopSourceRef termRls
;
784 if (plugin_runLoop
== NULL
) {
787 return FALSE
; // don't delay shutdown
790 if (exiting
!= NULL
) {
791 // if shutdown already active
795 SC_log(LOG_INFO
, "starting server shutdown (%f)", CFAbsoluteTimeGetCurrent());
797 exiting
= CFDictionaryCreateMutable(NULL
,
799 &kCFTypeDictionaryKeyCallBacks
,
800 &kCFTypeDictionaryValueCallBacks
);
802 termRls
= CFRunLoopSourceCreate(NULL
, 0, &termContext
);
803 CFRunLoopAddSource(plugin_runLoop
, termRls
, kCFRunLoopDefaultMode
);
804 CFRunLoopSourceSignal(termRls
);
806 CFRunLoopWakeUp(plugin_runLoop
);
813 #pragma mark initialization
818 timerCallback(CFRunLoopTimerRef timer
, void *info
)
823 if ((pass
> 120) && ((pass
% 60) != 0)) {
827 traceBundle("the [plugin] CFRunLoop is waiting...", NULL
);
834 sortBundles(CFMutableArrayRef orig
)
838 CFMutableArrayRef
new;
839 CFMutableSetRef orig_bundleIDs
;
841 orig_bundleIDs
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
843 n
= CFArrayGetCount(orig
);
844 for (i
= 0; i
< n
; i
++) {
845 bundleInfoRef bundleInfo
= (bundleInfoRef
)CFArrayGetValueAtIndex(orig
, i
);
846 CFStringRef bundleID
= CFBundleGetIdentifier(bundleInfo
->bundle
);
848 if (bundleID
!= NULL
) {
849 CFSetAddValue(orig_bundleIDs
, bundleID
);
853 new = CFArrayCreateMutable(NULL
, 0, NULL
);
855 Boolean inserted
= FALSE
;
857 for (i
= 0; i
< n
; i
++) {
858 bundleInfoRef bundleInfo1
= (bundleInfoRef
)CFArrayGetValueAtIndex(orig
, i
);
859 CFStringRef bundleID1
= CFBundleGetIdentifier(bundleInfo1
->bundle
);
861 CFDictionaryRef dict
;
864 CFArrayRef
requires = NULL
;
866 dict
= isA_CFDictionary(CFBundleGetInfoDictionary(bundleInfo1
->bundle
));
868 requires = CFDictionaryGetValue(dict
, kSCBundleRequiresKey
);
869 requires = isA_CFArray(requires);
871 if (bundleID1
== NULL
|| requires == NULL
) {
872 CFArrayInsertValueAtIndex(new, 0, bundleInfo1
);
873 CFArrayRemoveValueAtIndex(orig
, i
);
877 count
= nRequires
= CFArrayGetCount(requires);
878 for (j
= 0; j
< nRequires
; j
++) {
881 CFStringRef r
= CFArrayGetValueAtIndex(requires, j
);
883 if (!CFSetContainsValue(orig_bundleIDs
, r
)) {
884 // if dependency not present
889 nNew
= CFArrayGetCount(new);
890 for (k
= 0; k
< nNew
; k
++) {
891 bundleInfoRef bundleInfo2
= (bundleInfoRef
)CFArrayGetValueAtIndex(new, k
);
892 CFStringRef bundleID2
= CFBundleGetIdentifier(bundleInfo2
->bundle
);
894 if (bundleID2
&& CFEqual(bundleID2
, r
)) {
900 /* all dependencies are met, append */
901 CFArrayAppendValue(new, bundleInfo1
);
902 CFArrayRemoveValueAtIndex(orig
, i
);
908 if (inserted
== FALSE
) {
909 SC_log(LOG_NOTICE
, "Bundles have circular dependency!!!");
913 n
= CFArrayGetCount(orig
);
915 if (CFArrayGetCount(orig
) > 0) {
916 /* we have a circular dependency, append remaining items on new array */
917 CFArrayAppendArray(new, orig
, CFRangeMake(0, CFArrayGetCount(orig
)));
920 /* new one is a sorted version of original */
923 CFArrayRemoveAllValues(orig
);
924 CFArrayAppendArray(orig
, new, CFRangeMake(0, CFArrayGetCount(new)));
926 CFRelease(orig_bundleIDs
);
934 * An alternate CFRelease() that we can use to fake out the
937 static __inline__
void
938 ALT_CFRelease(CFTypeRef cf
)
946 plugin_exec(void *arg
)
951 /* keep track of bundles */
952 allBundles
= CFArrayCreateMutable(NULL
, 0, NULL
);
954 /* add white-listed plugins to those we'll allow to be loaded */
955 for (i
= 0; i
< N_PLUGIN_WHITELIST
; i
++) {
956 if (pluginWhitelist
[i
] != NULL
) {
957 CFSetSetValue(_plugins_allowed
, pluginWhitelist
[i
]);
961 /* allow plug-ins to exec child/helper processes */
962 _SCDPluginExecInit();
965 char path
[MAXPATHLEN
];
966 NSSearchPathEnumerationState state
;
969 * identify and load all bundles
971 state
= NSStartSearchPathEnumeration(NSLibraryDirectory
,
973 while ((state
= NSGetNextSearchPathEnumeration(state
, path
))) {
977 #if TARGET_IPHONE_SIMULATOR
978 const char *path_sim_prefix
;
980 path_sim_prefix
= getenv("IPHONE_SIMULATOR_ROOT");
981 if ((path_sim_prefix
!= NULL
) && (strcmp(path_sim_prefix
, ".") != 0)) {
982 char path_sim
[MAXPATHLEN
];
984 strlcpy(path_sim
, path_sim_prefix
, sizeof(path_sim
));
985 strlcat(path_sim
, path
, sizeof(path_sim
));
986 strlcpy(path
, path_sim
, sizeof(path
));
990 #endif // TARGET_IPHONE_SIMULATOR
992 /* load any available bundle */
993 strlcat(path
, BUNDLE_DIRECTORY
, sizeof(path
));
994 SC_log(LOG_DEBUG
, "searching for bundles in \"%s\"", path
);
995 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
999 bundles
= CFBundleCreateBundlesFromDirectory(NULL
, url
, CFSTR(".bundle"));
1002 if (bundles
!= NULL
) {
1006 n
= CFArrayGetCount(bundles
);
1007 for (i
= 0; i
< n
; i
++) {
1010 bundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundles
, i
);
1011 addBundle(bundle
, FALSE
);
1013 // The CFBundleCreateBundlesFromDirectory() API has
1014 // a known/outstanding bug in that it over-retains the
1015 // returned bundles. Since we do not expect this to
1016 // be fixed we release the extra references.
1018 // See <rdar://problems/4912137&6078752> for more info.
1020 // Also, we use the hack below to keep the static
1022 ALT_CFRelease(bundle
);
1028 sortBundles(allBundles
);
1034 * load (only) the specified bundle
1036 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
1038 strlen((char *)arg
),
1040 bundle
= CFBundleCreate(NULL
, url
);
1041 if (bundle
!= NULL
) {
1042 addBundle(bundle
, TRUE
);
1049 * Look for the InterfaceNamer plugin, and move it to the start
1052 * Load the InterfaceNamer plugin (and thereby start its thread)
1053 * first in an attempt to minimize the amount of time that
1054 * opendirectoryd has to wait for the platform UUID to appear in
1057 * InterfaceNamer is responsible for creating the platform UUID on
1058 * platforms without a UUID in ROM. Until the platform UUID is created
1059 * and stashed in nvram, all calls to opendirectoryd to do things like
1060 * getpwuid() will block, because opendirectoryd will block while trying
1061 * to read the platform UUID from the kernel.
1063 * As an example, dlopen() causes XPC to do some intialization, and
1064 * part of that initialization involves communicating with xpcd.
1065 * Since xpcd calls getpwuid_r() during its initialization, it will
1066 * block until the platform UUID is available.
1068 for (i
= 0; i
< CFArrayGetCount(allBundles
); i
++) {
1069 bundleInfoRef bi
= (bundleInfoRef
)CFArrayGetValueAtIndex(allBundles
, i
);
1070 CFStringRef bundleID
= CFBundleGetIdentifier(bi
->bundle
);
1072 if (_SC_CFEqual(bundleID
,
1073 CFSTR("com.apple.SystemConfiguration.InterfaceNamer")))
1075 CFArrayRemoveValueAtIndex(allBundles
, i
);
1076 CFArrayInsertValueAtIndex(allBundles
, 0, bi
);
1082 traceBundle("before loading any plugins", NULL
);
1088 SC_log(LOG_DEBUG
, "loading bundles");
1089 CFArrayApplyFunction(allBundles
,
1090 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1095 * If defined, call each bundles load() function. This function (or
1096 * the start() function) should initialize any variables, open any
1097 * sessions with "configd", and register any needed notifications.
1099 * Note: Establishing initial information in the store should be
1100 * deferred until the prime() initialization function so that
1101 * any bundles which want to receive a notification that the
1102 * data has changed will have an opportunity to install a
1103 * notification handler.
1105 SC_log(LOG_DEBUG
, "calling bundle load() functions");
1106 CFArrayApplyFunction(allBundles
,
1107 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1112 // if no bundles loaded
1117 * If defined, call each bundles start() function. This function is
1118 * called after the bundle has been loaded and its load() function has
1119 * been called. It should initialize any variables, open any sessions
1120 * with "configd", and register any needed notifications.
1122 * Note: Establishing initial information in the store should be
1123 * deferred until the prime() initialization function so that
1124 * any bundles which want to receive a notification that the
1125 * data has changed will have an opportunity to install a
1126 * notification handler.
1128 SC_log(LOG_DEBUG
, "calling bundle start() functions");
1129 CFArrayApplyFunction(allBundles
,
1130 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1135 * If defined, call each bundles prime() function. This function is
1136 * called after the bundle has been loaded and its load() and start()
1137 * functions have been called. It should initialize any configuration
1138 * information and/or state in the store.
1140 SC_log(LOG_DEBUG
, "calling bundle prime() functions");
1141 CFArrayApplyFunction(allBundles
,
1142 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1147 if (arg
== NULL
&& (nLoaded
> 0)) {
1148 CFRunLoopTimerRef timer
;
1150 /* allocate a periodic event (to help show we're not blocking) */
1151 timer
= CFRunLoopTimerCreate(NULL
, /* allocator */
1152 CFAbsoluteTimeGetCurrent() + 1.0, /* fireDate */
1156 timerCallback
, /* callout */
1157 NULL
); /* context */
1158 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
);
1164 traceBundle("about to start plugin CFRunLoop", NULL
);
1168 * The assumption is that each loaded plugin will establish CFMachPortRef,
1169 * CFSocketRef, and CFRunLoopTimerRef input sources to handle any events
1170 * and register these sources with this threads run loop. If the plugin
1171 * needs to wait and/or block at any time it should do so only in its a
1174 SC_log(LOG_DEBUG
, "starting plugin CFRunLoop");
1175 plugin_runLoop
= CFRunLoopGetCurrent();
1176 pthread_setname_np("Main plugin thread");
1181 SC_log(LOG_INFO
, "No more work for the \"configd\" plugin thread");
1182 plugin_runLoop
= NULL
;
1191 pthread_attr_t tattr
;
1194 SC_log(LOG_DEBUG
, "Starting \"configd\" plugin thread");
1195 pthread_attr_init(&tattr
);
1196 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
1197 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
1198 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
1199 pthread_create(&tid
, &tattr
, plugin_exec
, NULL
);
1200 pthread_attr_destroy(&tattr
);
1201 SC_log(LOG_DEBUG
, " thread id=%p", tid
);