#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <dirent.h>
#include <sysdir.h>
#include <sysexits.h>
#include <unistd.h>
#include "configd.h"
#include "configd_server.h"
#include <SystemConfiguration/SCDPlugin.h>
#include "SystemConfigurationInternal.h"
#define BUNDLE_DIRECTORY "/SystemConfiguration"
#define BUNDLE_DIR_EXTENSION ".bundle"
#define PLUGIN_ALL(p) CFSTR(p)
#if !TARGET_OS_IPHONE
#define PLUGIN_MACOSX(p) CFSTR(p)
#define PLUGIN_IOS(p) NULL
#else // !TARGET_OS_IPHONE
#define PLUGIN_MACOSX(p) NULL
#define PLUGIN_IOS(p) CFSTR(p)
#endif // !TARGET_OS_IPHONE
static const CFStringRef pluginWhitelist[] = {
PLUGIN_MACOSX("com.apple.SystemConfiguration.ApplicationFirewall"),
PLUGIN_ALL ("com.apple.SystemConfiguration.EAPOLController"),
PLUGIN_ALL ("com.apple.SystemConfiguration.IPConfiguration"),
PLUGIN_ALL ("com.apple.SystemConfiguration.IPMonitor"),
PLUGIN_MACOSX("com.apple.SystemConfiguration.ISPreference"),
PLUGIN_ALL ("com.apple.SystemConfiguration.InterfaceNamer"),
PLUGIN_ALL ("com.apple.SystemConfiguration.KernelEventMonitor"),
PLUGIN_ALL ("com.apple.SystemConfiguration.LinkConfiguration"),
PLUGIN_ALL ("com.apple.SystemConfiguration.PPPController"),
PLUGIN_ALL ("com.apple.SystemConfiguration.PreferencesMonitor"),
PLUGIN_ALL ("com.apple.SystemConfiguration.QoSMarking"),
PLUGIN_MACOSX("com.apple.print.notification"),
};
#define N_PLUGIN_WHITELIST (sizeof(pluginWhitelist) / sizeof(pluginWhitelist[0]))
typedef struct {
CFBundleRef bundle;
Boolean loaded;
Boolean builtin;
Boolean enabled;
Boolean forced;
Boolean verbose;
SCDynamicStoreBundleLoadFunction *load;
SCDynamicStoreBundleStartFunction *start;
SCDynamicStoreBundlePrimeFunction *prime;
SCDynamicStoreBundleStopFunction *stop;
} *bundleInfoRef;
static CFMutableArrayRef allBundles = NULL;
static CFMutableDictionaryRef exiting = NULL;
extern SCDynamicStoreBundleLoadFunction load_IPMonitor;
extern SCDynamicStoreBundlePrimeFunction prime_IPMonitor;
#if !TARGET_OS_SIMULATOR
extern SCDynamicStoreBundleLoadFunction load_InterfaceNamer;
extern SCDynamicStoreBundleLoadFunction load_KernelEventMonitor;
extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor;
extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration;
extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor;
extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor;
extern SCDynamicStoreBundleLoadFunction load_QoSMarking;
#endif // !TARGET_OS_SIMULATOR
typedef struct {
const CFStringRef bundleID;
SCDynamicStoreBundleLoadFunction *load;
SCDynamicStoreBundleStartFunction *start;
SCDynamicStoreBundlePrimeFunction *prime;
SCDynamicStoreBundleStopFunction *stop;
} builtin, *builtinRef;
static const builtin builtin_plugins[] = {
{
CFSTR("com.apple.SystemConfiguration.IPMonitor"),
load_IPMonitor,
NULL,
prime_IPMonitor,
NULL
},
#if !TARGET_OS_SIMULATOR
{
CFSTR("com.apple.SystemConfiguration.InterfaceNamer"),
load_InterfaceNamer,
NULL,
NULL,
NULL
},
{
CFSTR("com.apple.SystemConfiguration.KernelEventMonitor"),
load_KernelEventMonitor,
NULL,
prime_KernelEventMonitor,
NULL
},
{
CFSTR("com.apple.SystemConfiguration.LinkConfiguration"),
load_LinkConfiguration,
NULL,
NULL,
NULL
},
{
CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
load_PreferencesMonitor,
NULL,
prime_PreferencesMonitor,
NULL
},
{
CFSTR("com.apple.SystemConfiguration.QoSMarking"),
load_QoSMarking,
NULL,
NULL,
NULL
},
#endif // !TARGET_OS_SIMULATOR
};
static void
addBundle(CFBundleRef bundle, Boolean forceEnabled)
{
CFDictionaryRef bundleDict;
bundleInfoRef bundleInfo;
bundleInfo = CFAllocatorAllocate(NULL, sizeof(*bundleInfo), 0);
bundleInfo->bundle = (CFBundleRef)CFRetain(bundle);
bundleInfo->loaded = FALSE;
bundleInfo->builtin = FALSE;
bundleInfo->enabled = TRUE;
bundleInfo->forced = forceEnabled;
bundleInfo->verbose = FALSE;
bundleInfo->load = NULL;
bundleInfo->start = NULL;
bundleInfo->prime = NULL;
bundleInfo->stop = NULL;
bundleDict = CFBundleGetInfoDictionary(bundle);
if (isA_CFDictionary(bundleDict)) {
CFBooleanRef bVal;
bVal = CFDictionaryGetValue(bundleDict, kSCBundleIsBuiltinKey);
if (isA_CFBoolean(bVal)) {
bundleInfo->builtin = CFBooleanGetValue(bVal);
}
bVal = CFDictionaryGetValue(bundleDict, kSCBundleEnabledKey);
if (isA_CFBoolean(bVal)) {
bundleInfo->enabled = CFBooleanGetValue(bVal);
}
bVal = CFDictionaryGetValue(bundleDict, kSCBundleVerboseKey);
if (isA_CFBoolean(bVal)) {
bundleInfo->verbose = CFBooleanGetValue(bVal);
}
}
CFArrayAppendValue(allBundles, bundleInfo);
return;
}
static CF_RETURNS_RETAINED CFStringRef
shortBundleIdentifier(CFStringRef bundleID)
{
CFIndex len = CFStringGetLength(bundleID);
CFRange range;
CFStringRef shortID = NULL;
if (CFStringFindWithOptions(bundleID,
CFSTR("."),
CFRangeMake(0, len),
kCFCompareBackwards,
&range)) {
range.location = range.location + range.length;
range.length = len - range.location;
shortID = CFStringCreateWithSubstring(NULL, bundleID, range);
}
return shortID;
}
static void *
getBundleSymbol(CFBundleRef bundle, CFStringRef functionName, CFStringRef shortID)
{
void *func;
func = CFBundleGetFunctionPointerForName(bundle, functionName);
if (func != NULL) {
return func;
}
if (shortID != NULL) {
CFStringRef altFunctionName;
altFunctionName = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("%@_%@"),
functionName,
shortID);
func = CFBundleGetFunctionPointerForName(bundle, altFunctionName);
CFRelease(altFunctionName);
}
return func;
}
static const char *
getBundleDirNameAndPath(CFBundleRef bundle, char *buf, size_t buf_len)
{
char *cp;
size_t len;
Boolean ok;
CFURLRef url;
url = CFBundleCopyBundleURL(bundle);
if (url == NULL) {
return NULL;
}
ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)buf, buf_len);
CFRelease(url);
if (!ok) {
return NULL;
}
cp = strrchr(buf, '/');
if (cp != NULL) {
cp++;
} else {
cp = buf;
}
len = strlen(cp);
if (len <= sizeof(BUNDLE_DIR_EXTENSION)) {
return NULL;
}
len -= sizeof(BUNDLE_DIR_EXTENSION) - 1;
if (strcmp(&cp[len], BUNDLE_DIR_EXTENSION) != 0) {
return NULL;
}
return cp;
}
#pragma mark -
#pragma mark load
static void
loadBundle(const void *value, void *context) {
CFStringRef bundleID;
Boolean bundleAllowed;
bundleInfoRef bundleInfo = (bundleInfoRef)value;
Boolean bundleExclude;
CFIndex *nLoaded = (CFIndex *)context;
CFStringRef shortID;
bundleID = CFBundleGetIdentifier(bundleInfo->bundle);
if (bundleID == NULL) {
SC_log(LOG_NOTICE, "skipped %@ (no bundle ID)", bundleInfo->bundle);
return;
}
shortID = shortBundleIdentifier(bundleID);
bundleAllowed = ((CFSetGetCount(_plugins_allowed) == 0) || CFSetContainsValue(_plugins_allowed, bundleID) || ((shortID != NULL) &&
CFSetContainsValue(_plugins_allowed, shortID))|| bundleInfo->forced );
if (!bundleAllowed) {
SC_log(LOG_INFO, "skipped %@ (not allowed)", bundleID);
goto done;
}
bundleExclude = (CFSetContainsValue(_plugins_exclude, bundleID) || ((shortID != NULL) &&
CFSetContainsValue(_plugins_exclude, shortID)) );
if (bundleExclude) {
SC_log(LOG_INFO, "skipped %@ (excluded)", bundleID);
goto done;
}
if (!bundleInfo->enabled && !bundleInfo->forced) {
SC_log(LOG_INFO, "skipped %@ (disabled)", bundleID);
goto done;
}
if (!bundleInfo->verbose) {
bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, bundleID);
if (!bundleInfo->verbose) {
if (shortID != NULL) {
bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, shortID);
}
}
}
if (bundleInfo->builtin) {
SC_log(LOG_INFO, "adding %@", bundleID);
for (size_t i = 0; i < sizeof(builtin_plugins)/sizeof(builtin_plugins[0]); i++) {
if (CFEqual(bundleID, builtin_plugins[i].bundleID)) {
bundleInfo->load = builtin_plugins[i].load;
bundleInfo->start = builtin_plugins[i].start;
bundleInfo->prime = builtin_plugins[i].prime;
bundleInfo->stop = builtin_plugins[i].stop;
break;
}
}
if ((bundleInfo->load == NULL) &&
(bundleInfo->start == NULL) &&
(bundleInfo->prime == NULL) &&
(bundleInfo->stop == NULL)) {
SC_log(LOG_NOTICE, "%@ add failed", bundleID);
goto done;
}
} else {
CFErrorRef error = NULL;
SC_log(LOG_INFO, "loading %@", bundleID);
if (!CFBundleLoadExecutableAndReturnError(bundleInfo->bundle, &error)) {
CFDictionaryRef user_info;
SC_log(LOG_NOTICE, "%@ load failed", bundleID);
user_info = CFErrorCopyUserInfo(error);
if (user_info != NULL) {
CFStringRef link_error_string;
link_error_string = CFDictionaryGetValue(user_info,
CFSTR("NSDebugDescription"));
if (link_error_string != NULL) {
SC_log(LOG_NOTICE, "%@", link_error_string);
}
CFRelease(user_info);
}
CFRelease(error);
goto done;
}
bundleInfo->load = getBundleSymbol(bundleInfo->bundle, CFSTR("load" ), shortID);
bundleInfo->start = getBundleSymbol(bundleInfo->bundle, CFSTR("start"), shortID);
bundleInfo->prime = getBundleSymbol(bundleInfo->bundle, CFSTR("prime"), shortID);
bundleInfo->stop = getBundleSymbol(bundleInfo->bundle, CFSTR("stop" ), shortID);
}
bundleInfo->loaded = TRUE;
*nLoaded = *nLoaded + 1;
done :
if (shortID != NULL) CFRelease(shortID);
return;
}
void
callLoadFunction(const void *value, void *context)
{
#pragma unused(context)
bundleInfoRef bundleInfo = (bundleInfoRef)value;
if (!bundleInfo->loaded) {
return;
}
if (bundleInfo->load == NULL) {
return;
}
SC_log(LOG_DEBUG, "calling load() for %@",
CFBundleGetIdentifier(bundleInfo->bundle));
(*bundleInfo->load)(bundleInfo->bundle, bundleInfo->verbose);
return;
}
#pragma mark -
#pragma mark start
void
callStartFunction(const void *value, void *context)
{
#pragma unused(context)
const char *bundleDirName;
bundleInfoRef bundleInfo = (bundleInfoRef)value;
char bundleName[MAXNAMLEN + 1];
char bundlePath[MAXPATHLEN];
size_t len;
if (!bundleInfo->loaded) {
return;
}
if (bundleInfo->start == NULL) {
return;
}
bundleDirName = getBundleDirNameAndPath(bundleInfo->bundle, bundlePath, sizeof(bundlePath));
if (bundleDirName == NULL) {
return;
}
if (strlcpy(bundleName, bundleDirName, sizeof(bundleName)) > sizeof(bundleName)) {
return;
}
len = strlen(bundleName) - (sizeof(BUNDLE_DIR_EXTENSION) - 1);
bundleName[len] = '\0';
SC_log(LOG_DEBUG, "calling start() for %@",
CFBundleGetIdentifier(bundleInfo->bundle));
(*bundleInfo->start)(bundleName, bundlePath);
return;
}
#pragma mark -
#pragma mark prime
void
callPrimeFunction(const void *value, void *context)
{
#pragma unused(context)
bundleInfoRef bundleInfo = (bundleInfoRef)value;
if (!bundleInfo->loaded) {
return;
}
if (bundleInfo->prime == NULL) {
return;
}
SC_log(LOG_DEBUG, "calling prime() for %@",
CFBundleGetIdentifier(bundleInfo->bundle));
(*bundleInfo->prime)();
return;
}
#pragma mark -
#pragma mark stop
static void
stopComplete(void *info)
{
CFBundleRef bundle = (CFBundleRef)info;
CFStringRef bundleID = CFBundleGetIdentifier(bundle);
CFRunLoopSourceRef stopRls;
SC_log(LOG_INFO, "** %@ complete (%f)", bundleID, CFAbsoluteTimeGetCurrent());
stopRls = (CFRunLoopSourceRef)CFDictionaryGetValue(exiting, bundle);
if (stopRls == NULL) {
return;
}
CFRunLoopSourceInvalidate(stopRls);
CFDictionaryRemoveValue(exiting, bundle);
if (CFDictionaryGetCount(exiting) == 0) {
SC_log(LOG_INFO, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent());
exit (EX_OK);
}
return;
}
static void
stopDelayed(CFRunLoopTimerRef timer, void *info)
{
#pragma unused(timer)
#pragma unused(info)
const void **keys;
CFIndex i;
CFIndex n;
SC_log(LOG_INFO, "server shutdown was delayed, unresponsive plugins:");
n = CFDictionaryGetCount(exiting);
keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
CFDictionaryGetKeysAndValues(exiting, keys, NULL);
for (i = 0; i < n; i++) {
CFBundleRef bundle;
CFStringRef bundleID;
bundle = (CFBundleRef)keys[i];
bundleID = CFBundleGetIdentifier(bundle);
SC_log(LOG_NOTICE, "** %@", bundleID);
}
CFAllocatorDeallocate(NULL, keys);
exit (EX_OK);
}
static CFStringRef
stopRLSCopyDescription(const void *info)
{
CFBundleRef bundle = (CFBundleRef)info;
return CFStringCreateWithFormat(NULL,
NULL,
CFSTR("<stopRLS %p> {bundleID = %@}"),
info,
CFBundleGetIdentifier(bundle));
}
static void
stopBundle(const void *value, void *context)
{
#pragma unused(context)
bundleInfoRef bundleInfo = (bundleInfoRef)value;
CFRunLoopSourceRef stopRls;
CFRunLoopSourceContext stopContext = { 0 , bundleInfo->bundle , CFRetain , CFRelease , stopRLSCopyDescription , CFEqual , CFHash , NULL , NULL , stopComplete };
if (!bundleInfo->loaded) {
return;
}
if (bundleInfo->stop == NULL) {
return;
}
stopRls = CFRunLoopSourceCreate(NULL, 0, &stopContext);
CFRunLoopAddSource(CFRunLoopGetCurrent(), stopRls, kCFRunLoopDefaultMode);
CFDictionaryAddValue(exiting, bundleInfo->bundle, stopRls);
(*bundleInfo->stop)(stopRls);
CFRelease(stopRls);
return;
}
static void
stopBundles()
{
SC_log(LOG_DEBUG, "calling bundle stop() functions");
CFArrayApplyFunction(allBundles,
CFRangeMake(0, CFArrayGetCount(allBundles)),
stopBundle,
NULL);
if (CFDictionaryGetCount(exiting) == 0) {
SC_log(LOG_INFO, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent());
exit (EX_OK);
} else {
CFRunLoopTimerRef timer;
timer = CFRunLoopTimerCreate(NULL,
CFAbsoluteTimeGetCurrent() + 15.0,
0.0,
0,
0,
stopDelayed,
NULL);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
CFRelease(timer);
}
return;
}
#pragma mark -
#pragma mark term
__private_extern__
Boolean
plugin_term(int *status)
{
if (CFArrayGetCount(allBundles) == 0) {
*status = EX_OK;
return FALSE; }
if (exiting != NULL) {
return TRUE;
}
SC_log(LOG_INFO, "starting server shutdown (%f)", CFAbsoluteTimeGetCurrent());
exiting = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
stopBundles();
return TRUE;
}
#pragma mark -
#pragma mark initialization
static void
sortBundles(CFMutableArrayRef orig)
{
CFIndex i;
CFIndex n;
CFMutableArrayRef new;
CFMutableSetRef orig_bundleIDs;
orig_bundleIDs = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
n = CFArrayGetCount(orig);
for (i = 0; i < n; i++) {
bundleInfoRef bundleInfo = (bundleInfoRef)CFArrayGetValueAtIndex(orig, i);
CFStringRef bundleID = CFBundleGetIdentifier(bundleInfo->bundle);
if (bundleID != NULL) {
CFSetAddValue(orig_bundleIDs, bundleID);
}
}
new = CFArrayCreateMutable(NULL, 0, NULL);
while (n > 0) {
Boolean inserted = FALSE;
for (i = 0; i < n; i++) {
bundleInfoRef bundleInfo1 = (bundleInfoRef)CFArrayGetValueAtIndex(orig, i);
CFStringRef bundleID1 = CFBundleGetIdentifier(bundleInfo1->bundle);
CFIndex count;
CFDictionaryRef dict;
CFIndex j;
CFIndex nRequires;
CFArrayRef requires = NULL;
dict = isA_CFDictionary(CFBundleGetInfoDictionary(bundleInfo1->bundle));
if (dict) {
requires = CFDictionaryGetValue(dict, kSCBundleRequiresKey);
requires = isA_CFArray(requires);
}
if (bundleID1 == NULL || requires == NULL) {
CFArrayInsertValueAtIndex(new, 0, bundleInfo1);
CFArrayRemoveValueAtIndex(orig, i);
inserted = TRUE;
break;
}
count = nRequires = CFArrayGetCount(requires);
for (j = 0; j < nRequires; j++) {
CFIndex k;
CFIndex nNew;
CFStringRef r = CFArrayGetValueAtIndex(requires, j);
if (!CFSetContainsValue(orig_bundleIDs, r)) {
count--;
continue;
}
nNew = CFArrayGetCount(new);
for (k = 0; k < nNew; k++) {
bundleInfoRef bundleInfo2 = (bundleInfoRef)CFArrayGetValueAtIndex(new, k);
CFStringRef bundleID2 = CFBundleGetIdentifier(bundleInfo2->bundle);
if (bundleID2 && CFEqual(bundleID2, r)) {
count--;
}
}
}
if (count == 0) {
CFArrayAppendValue(new, bundleInfo1);
CFArrayRemoveValueAtIndex(orig, i);
inserted = TRUE;
break;
}
}
if (!inserted) {
SC_log(LOG_NOTICE, "Bundles have circular dependency!!!");
break;
}
n = CFArrayGetCount(orig);
}
if (CFArrayGetCount(orig) > 0) {
CFArrayAppendArray(new, orig, CFRangeMake(0, CFArrayGetCount(orig)));
}
else {
}
CFArrayRemoveAllValues(orig);
CFArrayAppendArray(orig, new, CFRangeMake(0, CFArrayGetCount(new)));
CFRelease(new);
CFRelease(orig_bundleIDs);
return;
}
static __inline__ void
ALT_CFRelease(CFTypeRef cf)
{
CFRelease(cf);
}
__private_extern__
void
plugin_exec(void *arg)
{
CFIndex nLoaded = 0;
allBundles = CFArrayCreateMutable(NULL, 0, NULL);
for (size_t i = 0; i < N_PLUGIN_WHITELIST; i++) {
if (pluginWhitelist[i] != NULL) {
CFSetSetValue(_plugins_allowed, pluginWhitelist[i]);
}
}
_SCDPluginExecInit();
if (arg == NULL) {
char path[MAXPATHLEN];
sysdir_search_path_enumeration_state state;
state = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_LIBRARY,
SYSDIR_DOMAIN_MASK_SYSTEM);
while ((state = sysdir_get_next_search_path_enumeration(state, path))) {
CFArrayRef bundles;
CFURLRef url;
#if TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST
const char *path_sim_prefix;
path_sim_prefix = getenv("IPHONE_SIMULATOR_ROOT");
if ((path_sim_prefix != NULL) && (strcmp(path_sim_prefix, ".") != 0)) {
char path_sim[MAXPATHLEN];
strlcpy(path_sim, path_sim_prefix, sizeof(path_sim));
strlcat(path_sim, path, sizeof(path_sim));
strlcpy(path, path_sim, sizeof(path));
} else {
path[0] = '\0';
}
#endif // TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST
strlcat(path, BUNDLE_DIRECTORY, sizeof(path));
SC_log(LOG_DEBUG, "searching for bundles in \"%s\"", path);
url = CFURLCreateFromFileSystemRepresentation(NULL,
(UInt8 *)path,
strlen(path),
TRUE);
bundles = CFBundleCreateBundlesFromDirectory(NULL, url, CFSTR(".bundle"));
CFRelease(url);
if (bundles != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(bundles);
for (i = 0; i < n; i++) {
CFBundleRef bundle;
bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundles, i);
addBundle(bundle, FALSE);
ALT_CFRelease(bundle);
}
CFRelease(bundles);
}
}
sortBundles(allBundles);
} else {
CFBundleRef bundle;
CFURLRef url;
url = CFURLCreateFromFileSystemRepresentation(NULL,
(UInt8 *)arg,
strlen((char *)arg),
TRUE);
bundle = CFBundleCreate(NULL, url);
if (bundle != NULL) {
addBundle(bundle, TRUE);
CFRelease(bundle);
}
CFRelease(url);
}
for (CFIndex i = 0; i < CFArrayGetCount(allBundles); i++) {
bundleInfoRef bi = (bundleInfoRef)CFArrayGetValueAtIndex(allBundles, i);
CFStringRef bundleID = CFBundleGetIdentifier(bi->bundle);
if (_SC_CFEqual(bundleID,
CFSTR("com.apple.SystemConfiguration.InterfaceNamer")))
{
CFArrayRemoveValueAtIndex(allBundles, i);
CFArrayInsertValueAtIndex(allBundles, 0, bi);
break;
}
}
SC_log(LOG_DEBUG, "loading bundles");
CFArrayApplyFunction(allBundles,
CFRangeMake(0, CFArrayGetCount(allBundles)),
loadBundle,
&nLoaded);
SC_log(LOG_DEBUG, "calling bundle load() functions");
CFArrayApplyFunction(allBundles,
CFRangeMake(0, CFArrayGetCount(allBundles)),
callLoadFunction,
NULL);
if (nLoaded == 0) {
return;
}
SC_log(LOG_DEBUG, "calling bundle start() functions");
CFArrayApplyFunction(allBundles,
CFRangeMake(0, CFArrayGetCount(allBundles)),
callStartFunction,
NULL);
SC_log(LOG_DEBUG, "calling bundle prime() functions");
CFArrayApplyFunction(allBundles,
CFRangeMake(0, CFArrayGetCount(allBundles)),
callPrimeFunction,
NULL);
return;
}