2 * Copyright (c) 2000-2017 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>
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"
62 #define PLUGIN_ALL(p) CFSTR(p)
64 #define PLUGIN_MACOSX(p) CFSTR(p)
65 #define PLUGIN_IOS(p) NULL
66 #else // !TARGET_OS_IPHONE
67 #define PLUGIN_MACOSX(p) NULL
68 #define PLUGIN_IOS(p) CFSTR(p)
69 #endif // !TARGET_OS_IPHONE
71 // white-listed (ok-to-load) bundle identifiers
72 static const CFStringRef pluginWhitelist
[] = {
73 PLUGIN_MACOSX("com.apple.SystemConfiguration.ApplicationFirewall"),
74 PLUGIN_ALL ("com.apple.SystemConfiguration.EAPOLController"),
75 PLUGIN_ALL ("com.apple.SystemConfiguration.IPConfiguration"),
76 PLUGIN_ALL ("com.apple.SystemConfiguration.IPMonitor"),
77 PLUGIN_MACOSX("com.apple.SystemConfiguration.ISPreference"),
78 PLUGIN_ALL ("com.apple.SystemConfiguration.InterfaceNamer"),
79 PLUGIN_ALL ("com.apple.SystemConfiguration.KernelEventMonitor"),
80 PLUGIN_ALL ("com.apple.SystemConfiguration.LinkConfiguration"),
81 PLUGIN_ALL ("com.apple.SystemConfiguration.PPPController"),
82 PLUGIN_ALL ("com.apple.SystemConfiguration.PreferencesMonitor"),
83 PLUGIN_ALL ("com.apple.SystemConfiguration.QoSMarking"),
84 PLUGIN_MACOSX("com.apple.print.notification"),
86 #define N_PLUGIN_WHITELIST (sizeof(pluginWhitelist) / sizeof(pluginWhitelist[0]))
96 SCDynamicStoreBundleLoadFunction load
;
97 SCDynamicStoreBundleStartFunction start
;
98 SCDynamicStoreBundlePrimeFunction prime
;
99 SCDynamicStoreBundleStopFunction stop
;
103 // all loaded bundles
104 static CFMutableArrayRef allBundles
= NULL
;
107 static CFMutableDictionaryRef exiting
= NULL
;
109 // plugin CFRunLoopRef
111 CFRunLoopRef plugin_runLoop
= NULL
;
114 extern SCDynamicStoreBundleLoadFunction load_IPMonitor
;
115 extern SCDynamicStoreBundlePrimeFunction prime_IPMonitor
;
116 #if !TARGET_OS_SIMULATOR
117 extern SCDynamicStoreBundleLoadFunction load_InterfaceNamer
;
118 extern SCDynamicStoreBundleLoadFunction load_KernelEventMonitor
;
119 extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor
;
120 extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration
;
121 extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor
;
122 extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor
;
123 extern SCDynamicStoreBundleLoadFunction load_QoSMarking
;
124 #endif // !TARGET_OS_SIMULATOR
128 const CFStringRef bundleID
;
129 const void *load
; // SCDynamicStoreBundleLoadFunction
130 const void *start
; // SCDynamicStoreBundleStartFunction
131 const void *prime
; // SCDynamicStoreBundlePrimeFunction
132 const void *stop
; // SCDynamicStoreBundleStopFunction
133 } builtin
, *builtinRef
;
136 static const builtin builtin_plugins
[] = {
138 CFSTR("com.apple.SystemConfiguration.IPMonitor"),
144 #if !TARGET_OS_SIMULATOR
146 CFSTR("com.apple.SystemConfiguration.InterfaceNamer"),
147 &load_InterfaceNamer
,
153 CFSTR("com.apple.SystemConfiguration.KernelEventMonitor"),
154 &load_KernelEventMonitor
,
156 &prime_KernelEventMonitor
,
160 CFSTR("com.apple.SystemConfiguration.LinkConfiguration"),
161 &load_LinkConfiguration
,
167 CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
168 &load_PreferencesMonitor
,
170 &prime_PreferencesMonitor
,
174 CFSTR("com.apple.SystemConfiguration.QoSMarking"),
180 #endif // !TARGET_OS_SIMULATOR
185 addBundle(CFBundleRef bundle
, Boolean forceEnabled
)
187 CFDictionaryRef bundleDict
;
188 bundleInfoRef bundleInfo
;
190 bundleInfo
= CFAllocatorAllocate(NULL
, sizeof(*bundleInfo
), 0);
191 bundleInfo
->bundle
= (CFBundleRef
)CFRetain(bundle
);
192 bundleInfo
->loaded
= FALSE
;
193 bundleInfo
->builtin
= FALSE
;
194 bundleInfo
->enabled
= TRUE
;
195 bundleInfo
->forced
= forceEnabled
;
196 bundleInfo
->verbose
= FALSE
;
197 bundleInfo
->load
= NULL
;
198 bundleInfo
->start
= NULL
;
199 bundleInfo
->prime
= NULL
;
200 bundleInfo
->stop
= NULL
;
202 bundleDict
= CFBundleGetInfoDictionary(bundle
);
203 if (isA_CFDictionary(bundleDict
)) {
206 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleIsBuiltinKey
);
207 if (isA_CFBoolean(bVal
)) {
208 bundleInfo
->builtin
= CFBooleanGetValue(bVal
);
211 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleEnabledKey
);
212 if (isA_CFBoolean(bVal
)) {
213 bundleInfo
->enabled
= CFBooleanGetValue(bVal
);
216 bVal
= CFDictionaryGetValue(bundleDict
, kSCBundleVerboseKey
);
217 if (isA_CFBoolean(bVal
)) {
218 bundleInfo
->verbose
= CFBooleanGetValue(bVal
);
222 CFArrayAppendValue(allBundles
, bundleInfo
);
227 static CF_RETURNS_RETAINED CFStringRef
228 shortBundleIdentifier(CFStringRef bundleID
)
230 CFIndex len
= CFStringGetLength(bundleID
);
232 CFStringRef shortID
= NULL
;
234 if (CFStringFindWithOptions(bundleID
,
239 range
.location
= range
.location
+ range
.length
;
240 range
.length
= len
- range
.location
;
241 shortID
= CFStringCreateWithSubstring(NULL
, bundleID
, range
);
249 getBundleSymbol(CFBundleRef bundle
, CFStringRef functionName
, CFStringRef shortID
)
253 // search for load(), start(), prime(), stop(), ...
254 func
= CFBundleGetFunctionPointerForName(bundle
, functionName
);
259 if (shortID
!= NULL
) {
260 CFStringRef altFunctionName
;
262 // search for load_XXX(), ...
263 altFunctionName
= CFStringCreateWithFormat(NULL
,
268 func
= CFBundleGetFunctionPointerForName(bundle
, altFunctionName
);
269 CFRelease(altFunctionName
);
277 getBundleDirNameAndPath(CFBundleRef bundle
, char *buf
, size_t buf_len
)
284 url
= CFBundleCopyBundleURL(bundle
);
289 ok
= CFURLGetFileSystemRepresentation(url
, TRUE
, (UInt8
*)buf
, buf_len
);
295 cp
= strrchr(buf
, '/');
302 /* check if this directory entry is a valid bundle name */
304 if (len
<= sizeof(BUNDLE_DIR_EXTENSION
)) {
305 /* if entry name isn't long enough */
309 len
-= sizeof(BUNDLE_DIR_EXTENSION
) - 1;
310 if (strcmp(&cp
[len
], BUNDLE_DIR_EXTENSION
) != 0) {
311 /* if entry name doesn't end with ".bundle" */
324 loadBundle(const void *value
, void *context
) {
325 CFStringRef bundleID
;
326 Boolean bundleAllowed
;
327 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
328 Boolean bundleExclude
;
329 CFIndex
*nLoaded
= (CFIndex
*)context
;
332 bundleID
= CFBundleGetIdentifier(bundleInfo
->bundle
);
333 if (bundleID
== NULL
) {
334 // sorry, no bundles without a bundle identifier
335 SC_log(LOG_NOTICE
, "skipped %@ (no bundle ID)", bundleInfo
->bundle
);
339 shortID
= shortBundleIdentifier(bundleID
);
341 bundleAllowed
= ((CFSetGetCount(_plugins_allowed
) == 0) || // if no white-listing
342 CFSetContainsValue(_plugins_allowed
, bundleID
) || // if [bundleID] white-listed
343 ((shortID
!= NULL
) &&
344 CFSetContainsValue(_plugins_allowed
, shortID
))|| // if [short bundleID] white-listed
345 bundleInfo
->forced
// if "testing" plugin
347 if (!bundleAllowed
) {
348 SC_log(LOG_INFO
, "skipped %@ (not allowed)", bundleID
);
352 bundleExclude
= (CFSetContainsValue(_plugins_exclude
, bundleID
) || // if [bundleID] excluded
353 ((shortID
!= NULL
) &&
354 CFSetContainsValue(_plugins_exclude
, shortID
)) // if [short bundleID] excluded
357 // sorry, this bundle has been excluded
358 SC_log(LOG_INFO
, "skipped %@ (excluded)", bundleID
);
362 if (!bundleInfo
->enabled
&& !bundleInfo
->forced
) {
363 // sorry, this bundle has not been enabled
364 SC_log(LOG_INFO
, "skipped %@ (disabled)", bundleID
);
368 if (!bundleInfo
->verbose
) {
369 bundleInfo
->verbose
= CFSetContainsValue(_plugins_verbose
, bundleID
);
370 if (!bundleInfo
->verbose
) {
371 if (shortID
!= NULL
) {
372 bundleInfo
->verbose
= CFSetContainsValue(_plugins_verbose
, shortID
);
377 if (bundleInfo
->builtin
) {
378 SC_log(LOG_INFO
, "adding %@", bundleID
);
380 for (size_t i
= 0; i
< sizeof(builtin_plugins
)/sizeof(builtin_plugins
[0]); i
++) {
381 if (CFEqual(bundleID
, builtin_plugins
[i
].bundleID
)) {
382 bundleInfo
->load
= builtin_plugins
[i
].load
;
383 bundleInfo
->start
= builtin_plugins
[i
].start
;
384 bundleInfo
->prime
= builtin_plugins
[i
].prime
;
385 bundleInfo
->stop
= builtin_plugins
[i
].stop
;
390 if ((bundleInfo
->load
== NULL
) &&
391 (bundleInfo
->start
== NULL
) &&
392 (bundleInfo
->prime
== NULL
) &&
393 (bundleInfo
->stop
== NULL
)) {
394 SC_log(LOG_NOTICE
, "%@ add failed", bundleID
);
398 CFErrorRef error
= NULL
;
400 SC_log(LOG_INFO
, "loading %@", bundleID
);
402 if (!CFBundleLoadExecutableAndReturnError(bundleInfo
->bundle
, &error
)) {
403 CFDictionaryRef user_info
;
405 SC_log(LOG_NOTICE
, "%@ load failed", bundleID
);
406 user_info
= CFErrorCopyUserInfo(error
);
407 if (user_info
!= NULL
) {
408 CFStringRef link_error_string
;
410 link_error_string
= CFDictionaryGetValue(user_info
,
411 CFSTR("NSDebugDescription"));
412 if (link_error_string
!= NULL
) {
413 SC_log(LOG_NOTICE
, "%@", link_error_string
);
415 CFRelease(user_info
);
421 // get bundle entry points
422 bundleInfo
->load
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("load" ), shortID
);
423 bundleInfo
->start
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("start"), shortID
);
424 bundleInfo
->prime
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("prime"), shortID
);
425 bundleInfo
->stop
= getBundleSymbol(bundleInfo
->bundle
, CFSTR("stop" ), shortID
);
428 /* mark this bundle as having been loaded */
429 bundleInfo
->loaded
= TRUE
;
431 /* bump the count of loaded bundles */
432 *nLoaded
= *nLoaded
+ 1;
436 if (shortID
!= NULL
) CFRelease(shortID
);
442 callLoadFunction(const void *value
, void *context
)
444 #pragma unused(context)
445 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
447 if (!bundleInfo
->loaded
) {
451 if (bundleInfo
->load
== NULL
) {
452 // if no load() function
456 SC_log(LOG_DEBUG
, "calling load() for %@",
457 CFBundleGetIdentifier(bundleInfo
->bundle
));
459 (*bundleInfo
->load
)(bundleInfo
->bundle
, bundleInfo
->verbose
);
470 callStartFunction(const void *value
, void *context
)
472 #pragma unused(context)
473 const char *bundleDirName
;
474 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
475 char bundleName
[MAXNAMLEN
+ 1];
476 char bundlePath
[MAXPATHLEN
];
479 if (!bundleInfo
->loaded
) {
483 if (bundleInfo
->start
== NULL
) {
484 // if no start() function
488 /* copy the bundle's path */
489 bundleDirName
= getBundleDirNameAndPath(bundleInfo
->bundle
, bundlePath
, sizeof(bundlePath
));
490 if (bundleDirName
== NULL
) {
491 // if we have a problem with the bundle's path
495 /* copy (just) the bundle's name */
496 if (strlcpy(bundleName
, bundleDirName
, sizeof(bundleName
)) > sizeof(bundleName
)) {
497 // if we have a problem with the bundle's name
500 len
= strlen(bundleName
) - (sizeof(BUNDLE_DIR_EXTENSION
) - 1);
501 bundleName
[len
] = '\0';
503 SC_log(LOG_DEBUG
, "calling start() for %@",
504 CFBundleGetIdentifier(bundleInfo
->bundle
));
506 (*bundleInfo
->start
)(bundleName
, bundlePath
);
517 callPrimeFunction(const void *value
, void *context
)
519 #pragma unused(context)
520 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
522 if (!bundleInfo
->loaded
) {
526 if (bundleInfo
->prime
== NULL
) {
527 // if no prime() function
531 SC_log(LOG_DEBUG
, "calling prime() for %@",
532 CFBundleGetIdentifier(bundleInfo
->bundle
));
534 (*bundleInfo
->prime
)();
545 stopComplete(void *info
)
547 CFBundleRef bundle
= (CFBundleRef
)info
;
548 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
549 CFRunLoopSourceRef stopRls
;
551 SC_log(LOG_INFO
, "** %@ complete (%f)", bundleID
, CFAbsoluteTimeGetCurrent());
553 stopRls
= (CFRunLoopSourceRef
)CFDictionaryGetValue(exiting
, bundle
);
554 if (stopRls
== NULL
) {
558 CFRunLoopSourceInvalidate(stopRls
);
560 CFDictionaryRemoveValue(exiting
, bundle
);
562 if (CFDictionaryGetCount(exiting
) == 0) {
565 // if all of the plugins are happy
566 status
= server_shutdown();
567 SC_log(LOG_INFO
, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent());
576 stopDelayed(CFRunLoopTimerRef timer
, void *info
)
578 #pragma unused(timer)
585 SC_log(LOG_INFO
, "server shutdown was delayed, unresponsive plugins:");
588 * we've asked our plugins to shutdown but someone
591 n
= CFDictionaryGetCount(exiting
);
592 keys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFTypeRef
), 0);
593 CFDictionaryGetKeysAndValues(exiting
, keys
, NULL
);
594 for (i
= 0; i
< n
; i
++) {
596 CFStringRef bundleID
;
598 bundle
= (CFBundleRef
)keys
[i
];
599 bundleID
= CFBundleGetIdentifier(bundle
);
600 SC_log(LOG_NOTICE
, "** %@", bundleID
);
602 CFAllocatorDeallocate(NULL
, keys
);
604 status
= server_shutdown();
609 stopRLSCopyDescription(const void *info
)
611 CFBundleRef bundle
= (CFBundleRef
)info
;
613 return CFStringCreateWithFormat(NULL
,
615 CFSTR("<stopRLS %p> {bundleID = %@}"),
617 CFBundleGetIdentifier(bundle
));
622 stopBundle(const void *value
, void *context
)
624 #pragma unused(context)
625 bundleInfoRef bundleInfo
= (bundleInfoRef
)value
;
626 CFRunLoopSourceRef stopRls
;
627 CFRunLoopSourceContext stopContext
= { 0 // version
628 , bundleInfo
->bundle
// info
630 , CFRelease
// release
631 , stopRLSCopyDescription
// copyDescription
636 , stopComplete
// perform
639 if (!bundleInfo
->loaded
) {
643 if (bundleInfo
->stop
== NULL
) {
644 // if no stop() function
648 stopRls
= CFRunLoopSourceCreate(NULL
, 0, &stopContext
);
649 CFRunLoopAddSource(CFRunLoopGetCurrent(), stopRls
, kCFRunLoopDefaultMode
);
650 CFDictionaryAddValue(exiting
, bundleInfo
->bundle
, stopRls
);
653 (*bundleInfo
->stop
)(stopRls
);
663 * If defined, call each bundles stop() function. This function is
664 * called when configd has been asked to shut down (via a SIGTERM). The
665 * function should signal the provided run loop source when it is "ready"
666 * for the shut down to proceeed.
668 SC_log(LOG_DEBUG
, "calling bundle stop() functions");
669 CFArrayApplyFunction(allBundles
,
670 CFRangeMake(0, CFArrayGetCount(allBundles
)),
674 if (CFDictionaryGetCount(exiting
) == 0) {
677 // if all of the plugins are happy
678 status
= server_shutdown();
679 SC_log(LOG_INFO
, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent());
682 CFRunLoopTimerRef timer
;
685 * launchd will only wait 20 seconds before sending us a
686 * SIGKILL and because we want to know what's stuck before
687 * that time so set our own "we're not waiting any longer"
688 * timeout for 15 seconds.
690 timer
= CFRunLoopTimerCreate(NULL
, /* allocator */
691 CFAbsoluteTimeGetCurrent() + 15.0, /* fireDate (in 15 seconds) */
692 0.0, /* interval (== one-shot) */
695 stopDelayed
, /* callout */
697 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer
, kCFRunLoopDefaultMode
);
710 termRLSCopyDescription(const void *info
)
713 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SIGTERM RLS>"));
719 plugin_term(int *status
)
721 CFRunLoopSourceContext termContext
= { 0 // version
725 , termRLSCopyDescription
// copyDescription
730 , stopBundles
// perform
732 CFRunLoopSourceRef termRls
;
734 if (plugin_runLoop
== NULL
) {
737 return FALSE
; // don't delay shutdown
740 if (exiting
!= NULL
) {
741 // if shutdown already active
745 SC_log(LOG_INFO
, "starting server shutdown (%f)", CFAbsoluteTimeGetCurrent());
747 exiting
= CFDictionaryCreateMutable(NULL
,
749 &kCFTypeDictionaryKeyCallBacks
,
750 &kCFTypeDictionaryValueCallBacks
);
752 termRls
= CFRunLoopSourceCreate(NULL
, 0, &termContext
);
753 CFRunLoopAddSource(plugin_runLoop
, termRls
, kCFRunLoopDefaultMode
);
754 CFRunLoopSourceSignal(termRls
);
756 CFRunLoopWakeUp(plugin_runLoop
);
763 #pragma mark initialization
767 sortBundles(CFMutableArrayRef orig
)
771 CFMutableArrayRef
new;
772 CFMutableSetRef orig_bundleIDs
;
774 orig_bundleIDs
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
776 n
= CFArrayGetCount(orig
);
777 for (i
= 0; i
< n
; i
++) {
778 bundleInfoRef bundleInfo
= (bundleInfoRef
)CFArrayGetValueAtIndex(orig
, i
);
779 CFStringRef bundleID
= CFBundleGetIdentifier(bundleInfo
->bundle
);
781 if (bundleID
!= NULL
) {
782 CFSetAddValue(orig_bundleIDs
, bundleID
);
786 new = CFArrayCreateMutable(NULL
, 0, NULL
);
788 Boolean inserted
= FALSE
;
790 for (i
= 0; i
< n
; i
++) {
791 bundleInfoRef bundleInfo1
= (bundleInfoRef
)CFArrayGetValueAtIndex(orig
, i
);
792 CFStringRef bundleID1
= CFBundleGetIdentifier(bundleInfo1
->bundle
);
794 CFDictionaryRef dict
;
797 CFArrayRef
requires = NULL
;
799 dict
= isA_CFDictionary(CFBundleGetInfoDictionary(bundleInfo1
->bundle
));
801 requires = CFDictionaryGetValue(dict
, kSCBundleRequiresKey
);
802 requires = isA_CFArray(requires);
804 if (bundleID1
== NULL
|| requires == NULL
) {
805 CFArrayInsertValueAtIndex(new, 0, bundleInfo1
);
806 CFArrayRemoveValueAtIndex(orig
, i
);
810 count
= nRequires
= CFArrayGetCount(requires);
811 for (j
= 0; j
< nRequires
; j
++) {
814 CFStringRef r
= CFArrayGetValueAtIndex(requires, j
);
816 if (!CFSetContainsValue(orig_bundleIDs
, r
)) {
817 // if dependency not present
822 nNew
= CFArrayGetCount(new);
823 for (k
= 0; k
< nNew
; k
++) {
824 bundleInfoRef bundleInfo2
= (bundleInfoRef
)CFArrayGetValueAtIndex(new, k
);
825 CFStringRef bundleID2
= CFBundleGetIdentifier(bundleInfo2
->bundle
);
827 if (bundleID2
&& CFEqual(bundleID2
, r
)) {
833 /* all dependencies are met, append */
834 CFArrayAppendValue(new, bundleInfo1
);
835 CFArrayRemoveValueAtIndex(orig
, i
);
842 SC_log(LOG_NOTICE
, "Bundles have circular dependency!!!");
846 n
= CFArrayGetCount(orig
);
848 if (CFArrayGetCount(orig
) > 0) {
849 /* we have a circular dependency, append remaining items on new array */
850 CFArrayAppendArray(new, orig
, CFRangeMake(0, CFArrayGetCount(orig
)));
853 /* new one is a sorted version of original */
856 CFArrayRemoveAllValues(orig
);
857 CFArrayAppendArray(orig
, new, CFRangeMake(0, CFArrayGetCount(new)));
859 CFRelease(orig_bundleIDs
);
867 * An alternate CFRelease() that we can use to fake out the
870 static __inline__
void
871 ALT_CFRelease(CFTypeRef cf
)
879 plugin_exec(void *arg
)
883 /* keep track of bundles */
884 allBundles
= CFArrayCreateMutable(NULL
, 0, NULL
);
886 /* add white-listed plugins to those we'll allow to be loaded */
887 for (size_t i
= 0; i
< N_PLUGIN_WHITELIST
; i
++) {
888 if (pluginWhitelist
[i
] != NULL
) {
889 CFSetSetValue(_plugins_allowed
, pluginWhitelist
[i
]);
893 /* allow plug-ins to exec child/helper processes */
894 _SCDPluginExecInit();
897 char path
[MAXPATHLEN
];
898 sysdir_search_path_enumeration_state state
;
901 * identify and load all bundles
903 state
= sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_LIBRARY
,
904 SYSDIR_DOMAIN_MASK_SYSTEM
);
905 while ((state
= sysdir_get_next_search_path_enumeration(state
, path
))) {
909 #if TARGET_OS_SIMULATOR
910 const char *path_sim_prefix
;
912 path_sim_prefix
= getenv("IPHONE_SIMULATOR_ROOT");
913 if ((path_sim_prefix
!= NULL
) && (strcmp(path_sim_prefix
, ".") != 0)) {
914 char path_sim
[MAXPATHLEN
];
916 strlcpy(path_sim
, path_sim_prefix
, sizeof(path_sim
));
917 strlcat(path_sim
, path
, sizeof(path_sim
));
918 strlcpy(path
, path_sim
, sizeof(path
));
922 #endif // TARGET_OS_SIMULATOR
924 /* load any available bundle */
925 strlcat(path
, BUNDLE_DIRECTORY
, sizeof(path
));
926 SC_log(LOG_DEBUG
, "searching for bundles in \"%s\"", path
);
927 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
931 bundles
= CFBundleCreateBundlesFromDirectory(NULL
, url
, CFSTR(".bundle"));
934 if (bundles
!= NULL
) {
938 n
= CFArrayGetCount(bundles
);
939 for (i
= 0; i
< n
; i
++) {
942 bundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundles
, i
);
943 addBundle(bundle
, FALSE
);
945 // The CFBundleCreateBundlesFromDirectory() API has
946 // a known/outstanding bug in that it over-retains the
947 // returned bundles. Since we do not expect this to
948 // be fixed we release the extra references.
950 // See <rdar://problems/4912137&6078752> for more info.
952 // Also, we use the hack below to keep the static
954 ALT_CFRelease(bundle
);
960 sortBundles(allBundles
);
966 * load (only) the specified bundle
968 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
972 bundle
= CFBundleCreate(NULL
, url
);
973 if (bundle
!= NULL
) {
974 addBundle(bundle
, TRUE
);
981 * Look for the InterfaceNamer plugin, and move it to the start
984 * Load the InterfaceNamer plugin (and thereby start its thread)
985 * first in an attempt to minimize the amount of time that
986 * opendirectoryd has to wait for the platform UUID to appear in
989 * InterfaceNamer is responsible for creating the platform UUID on
990 * platforms without a UUID in ROM. Until the platform UUID is created
991 * and stashed in nvram, all calls to opendirectoryd to do things like
992 * getpwuid() will block, because opendirectoryd will block while trying
993 * to read the platform UUID from the kernel.
995 * As an example, dlopen() causes XPC to do some intialization, and
996 * part of that initialization involves communicating with xpcd.
997 * Since xpcd calls getpwuid_r() during its initialization, it will
998 * block until the platform UUID is available.
1000 for (CFIndex i
= 0; i
< CFArrayGetCount(allBundles
); i
++) {
1001 bundleInfoRef bi
= (bundleInfoRef
)CFArrayGetValueAtIndex(allBundles
, i
);
1002 CFStringRef bundleID
= CFBundleGetIdentifier(bi
->bundle
);
1004 if (_SC_CFEqual(bundleID
,
1005 CFSTR("com.apple.SystemConfiguration.InterfaceNamer")))
1007 CFArrayRemoveValueAtIndex(allBundles
, i
);
1008 CFArrayInsertValueAtIndex(allBundles
, 0, bi
);
1016 SC_log(LOG_DEBUG
, "loading bundles");
1017 CFArrayApplyFunction(allBundles
,
1018 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1023 * If defined, call each bundles load() function. This function (or
1024 * the start() function) should initialize any variables, open any
1025 * sessions with "configd", and register any needed notifications.
1027 * Note: Establishing initial information in the store should be
1028 * deferred until the prime() initialization function so that
1029 * any bundles which want to receive a notification that the
1030 * data has changed will have an opportunity to install a
1031 * notification handler.
1033 SC_log(LOG_DEBUG
, "calling bundle load() functions");
1034 CFArrayApplyFunction(allBundles
,
1035 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1040 // if no bundles loaded
1045 * If defined, call each bundles start() function. This function is
1046 * called after the bundle has been loaded and its load() function has
1047 * been called. It should initialize any variables, open any sessions
1048 * with "configd", and register any needed notifications.
1050 * Note: Establishing initial information in the store should be
1051 * deferred until the prime() initialization function so that
1052 * any bundles which want to receive a notification that the
1053 * data has changed will have an opportunity to install a
1054 * notification handler.
1056 SC_log(LOG_DEBUG
, "calling bundle start() functions");
1057 CFArrayApplyFunction(allBundles
,
1058 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1063 * If defined, call each bundles prime() function. This function is
1064 * called after the bundle has been loaded and its load() and start()
1065 * functions have been called. It should initialize any configuration
1066 * information and/or state in the store.
1068 SC_log(LOG_DEBUG
, "calling bundle prime() functions");
1069 CFArrayApplyFunction(allBundles
,
1070 CFRangeMake(0, CFArrayGetCount(allBundles
)),
1075 * The assumption is that each loaded plugin will establish CFMachPortRef,
1076 * CFSocketRef, and CFRunLoopTimerRef input sources to handle any events
1077 * and register these sources with this threads run loop. If the plugin
1078 * needs to wait and/or block at any time it should do so only in its a
1081 SC_log(LOG_DEBUG
, "starting plugin CFRunLoop");
1082 plugin_runLoop
= CFRunLoopGetCurrent();
1083 pthread_setname_np("Main plugin thread");
1088 SC_log(LOG_INFO
, "No more work for the \"configd\" plugin thread");
1089 plugin_runLoop
= NULL
;
1098 pthread_attr_t tattr
;
1101 SC_log(LOG_DEBUG
, "Starting \"configd\" plugin thread");
1102 pthread_attr_init(&tattr
);
1103 pthread_attr_setscope(&tattr
, PTHREAD_SCOPE_SYSTEM
);
1104 pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
1105 // pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
1106 pthread_create(&tid
, &tattr
, plugin_exec
, NULL
);
1107 pthread_attr_destroy(&tattr
);
1108 SC_log(LOG_DEBUG
, " thread id=%p", tid
);