]>
Commit | Line | Data |
---|---|---|
5958d7c0 | 1 | /* |
c956c85e | 2 | * Copyright (c) 2000-2019 Apple Inc. All rights reserved. |
5958d7c0 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
9de8ab86 | 5 | * |
009ee3c6 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
9de8ab86 | 12 | * |
009ee3c6 A |
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 | |
5958d7c0 A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
009ee3c6 A |
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. | |
9de8ab86 | 20 | * |
5958d7c0 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
0fae82ee A |
24 | /* |
25 | * Modification History | |
26 | * | |
dbf6a266 A |
27 | * October 30, 2003 Allan Nathanson <ajn@apple.com> |
28 | * - add plugin "stop()" function support | |
29 | * | |
0fae82ee A |
30 | * June 11, 2001 Allan Nathanson <ajn@apple.com> |
31 | * - start using CFBundle code | |
32 | * | |
33 | * June 1, 2001 Allan Nathanson <ajn@apple.com> | |
34 | * - public API conversion | |
35 | * | |
36 | * May 26, 2000 Allan Nathanson <ajn@apple.com> | |
37 | * - initial revision | |
38 | */ | |
39 | ||
5958d7c0 A |
40 | #include <sys/types.h> |
41 | #include <sys/stat.h> | |
42 | #include <sys/param.h> | |
edebe297 | 43 | #include <sys/wait.h> |
5958d7c0 | 44 | #include <dirent.h> |
942cecd7 | 45 | #include <sysdir.h> |
dbf6a266 | 46 | #include <sysexits.h> |
5958d7c0 | 47 | #include <unistd.h> |
5958d7c0 A |
48 | |
49 | #include "configd.h" | |
dbf6a266 | 50 | #include "configd_server.h" |
0fae82ee | 51 | #include <SystemConfiguration/SCDPlugin.h> |
f715d946 | 52 | #include "SystemConfigurationInternal.h" |
5958d7c0 A |
53 | |
54 | ||
55 | /* | |
0fae82ee | 56 | * path components, extensions, entry points, ... |
5958d7c0 | 57 | */ |
0fae82ee A |
58 | #define BUNDLE_DIRECTORY "/SystemConfiguration" /* [/System/Library]/... */ |
59 | #define BUNDLE_DIR_EXTENSION ".bundle" | |
5958d7c0 | 60 | |
5958d7c0 | 61 | |
17d3ee29 | 62 | #define PLUGIN_ALL(p) CFSTR(p) |
5e9ce69e | 63 | #if !TARGET_OS_IPHONE |
17d3ee29 A |
64 | #define PLUGIN_MACOSX(p) CFSTR(p) |
65 | #define PLUGIN_IOS(p) NULL | |
5e9ce69e | 66 | #else // !TARGET_OS_IPHONE |
17d3ee29 A |
67 | #define PLUGIN_MACOSX(p) NULL |
68 | #define PLUGIN_IOS(p) CFSTR(p) | |
5e9ce69e | 69 | #endif // !TARGET_OS_IPHONE |
17d3ee29 A |
70 | |
71 | // white-listed (ok-to-load) bundle identifiers | |
72 | static const CFStringRef pluginWhitelist[] = { | |
17d3ee29 | 73 | PLUGIN_MACOSX("com.apple.SystemConfiguration.ApplicationFirewall"), |
17d3ee29 A |
74 | PLUGIN_ALL ("com.apple.SystemConfiguration.EAPOLController"), |
75 | PLUGIN_ALL ("com.apple.SystemConfiguration.IPConfiguration"), | |
76 | PLUGIN_ALL ("com.apple.SystemConfiguration.IPMonitor"), | |
78403150 | 77 | PLUGIN_MACOSX("com.apple.SystemConfiguration.ISPreference"), |
17d3ee29 A |
78 | PLUGIN_ALL ("com.apple.SystemConfiguration.InterfaceNamer"), |
79 | PLUGIN_ALL ("com.apple.SystemConfiguration.KernelEventMonitor"), | |
80 | PLUGIN_ALL ("com.apple.SystemConfiguration.LinkConfiguration"), | |
17d3ee29 A |
81 | PLUGIN_ALL ("com.apple.SystemConfiguration.PPPController"), |
82 | PLUGIN_ALL ("com.apple.SystemConfiguration.PreferencesMonitor"), | |
1ef45fa4 | 83 | PLUGIN_ALL ("com.apple.SystemConfiguration.QoSMarking"), |
17d3ee29 A |
84 | PLUGIN_MACOSX("com.apple.print.notification"), |
85 | }; | |
86 | #define N_PLUGIN_WHITELIST (sizeof(pluginWhitelist) / sizeof(pluginWhitelist[0])) | |
87 | ||
88 | ||
dbf6a266 A |
89 | typedef struct { |
90 | CFBundleRef bundle; | |
91 | Boolean loaded; | |
92 | Boolean builtin; | |
edebe297 | 93 | Boolean enabled; |
17d3ee29 | 94 | Boolean forced; |
dbf6a266 | 95 | Boolean verbose; |
f715d946 A |
96 | SCDynamicStoreBundleLoadFunction *load; |
97 | SCDynamicStoreBundleStartFunction *start; | |
98 | SCDynamicStoreBundlePrimeFunction *prime; | |
99 | SCDynamicStoreBundleStopFunction *stop; | |
dbf6a266 A |
100 | } *bundleInfoRef; |
101 | ||
102 | ||
103 | // all loaded bundles | |
edebe297 | 104 | static CFMutableArrayRef allBundles = NULL; |
dbf6a266 A |
105 | |
106 | // exiting bundles | |
edebe297 | 107 | static CFMutableDictionaryRef exiting = NULL; |
dbf6a266 | 108 | |
dbf6a266 | 109 | |
dbf6a266 A |
110 | extern SCDynamicStoreBundleLoadFunction load_IPMonitor; |
111 | extern SCDynamicStoreBundlePrimeFunction prime_IPMonitor; | |
942cecd7 | 112 | #if !TARGET_OS_SIMULATOR |
dbf6a266 A |
113 | extern SCDynamicStoreBundleLoadFunction load_InterfaceNamer; |
114 | extern SCDynamicStoreBundleLoadFunction load_KernelEventMonitor; | |
115 | extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor; | |
dbf6a266 A |
116 | extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration; |
117 | extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor; | |
118 | extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor; | |
942cecd7 | 119 | extern SCDynamicStoreBundleLoadFunction load_QoSMarking; |
942cecd7 | 120 | #endif // !TARGET_OS_SIMULATOR |
dbf6a266 A |
121 | |
122 | ||
123 | typedef struct { | |
f715d946 A |
124 | const CFStringRef bundleID; |
125 | SCDynamicStoreBundleLoadFunction *load; | |
126 | SCDynamicStoreBundleStartFunction *start; | |
127 | SCDynamicStoreBundlePrimeFunction *prime; | |
128 | SCDynamicStoreBundleStopFunction *stop; | |
dbf6a266 A |
129 | } builtin, *builtinRef; |
130 | ||
131 | ||
132 | static const builtin builtin_plugins[] = { | |
dbf6a266 A |
133 | { |
134 | CFSTR("com.apple.SystemConfiguration.IPMonitor"), | |
f715d946 | 135 | load_IPMonitor, |
dbf6a266 | 136 | NULL, |
f715d946 | 137 | prime_IPMonitor, |
dbf6a266 A |
138 | NULL |
139 | }, | |
942cecd7 | 140 | #if !TARGET_OS_SIMULATOR |
dbf6a266 A |
141 | { |
142 | CFSTR("com.apple.SystemConfiguration.InterfaceNamer"), | |
f715d946 | 143 | load_InterfaceNamer, |
dbf6a266 A |
144 | NULL, |
145 | NULL, | |
146 | NULL | |
147 | }, | |
148 | { | |
149 | CFSTR("com.apple.SystemConfiguration.KernelEventMonitor"), | |
f715d946 | 150 | load_KernelEventMonitor, |
dbf6a266 | 151 | NULL, |
f715d946 | 152 | prime_KernelEventMonitor, |
dbf6a266 A |
153 | NULL |
154 | }, | |
dbf6a266 A |
155 | { |
156 | CFSTR("com.apple.SystemConfiguration.LinkConfiguration"), | |
f715d946 | 157 | load_LinkConfiguration, |
dbf6a266 A |
158 | NULL, |
159 | NULL, | |
160 | NULL | |
161 | }, | |
edebe297 | 162 | { |
17d3ee29 | 163 | CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"), |
f715d946 | 164 | load_PreferencesMonitor, |
edebe297 | 165 | NULL, |
f715d946 | 166 | prime_PreferencesMonitor, |
a40a14f8 | 167 | NULL |
edebe297 | 168 | }, |
942cecd7 A |
169 | { |
170 | CFSTR("com.apple.SystemConfiguration.QoSMarking"), | |
f715d946 | 171 | load_QoSMarking, |
942cecd7 A |
172 | NULL, |
173 | NULL, | |
174 | NULL | |
175 | }, | |
942cecd7 | 176 | #endif // !TARGET_OS_SIMULATOR |
dbf6a266 | 177 | }; |
5958d7c0 A |
178 | |
179 | ||
edebe297 A |
180 | static void |
181 | addBundle(CFBundleRef bundle, Boolean forceEnabled) | |
5958d7c0 | 182 | { |
dbf6a266 A |
183 | CFDictionaryRef bundleDict; |
184 | bundleInfoRef bundleInfo; | |
d6c893b2 | 185 | |
dbf6a266 A |
186 | bundleInfo = CFAllocatorAllocate(NULL, sizeof(*bundleInfo), 0); |
187 | bundleInfo->bundle = (CFBundleRef)CFRetain(bundle); | |
188 | bundleInfo->loaded = FALSE; | |
189 | bundleInfo->builtin = FALSE; | |
edebe297 | 190 | bundleInfo->enabled = TRUE; |
17d3ee29 | 191 | bundleInfo->forced = forceEnabled; |
dbf6a266 A |
192 | bundleInfo->verbose = FALSE; |
193 | bundleInfo->load = NULL; | |
194 | bundleInfo->start = NULL; | |
195 | bundleInfo->prime = NULL; | |
196 | bundleInfo->stop = NULL; | |
d6c893b2 | 197 | |
dbf6a266 A |
198 | bundleDict = CFBundleGetInfoDictionary(bundle); |
199 | if (isA_CFDictionary(bundleDict)) { | |
200 | CFBooleanRef bVal; | |
201 | ||
202 | bVal = CFDictionaryGetValue(bundleDict, kSCBundleIsBuiltinKey); | |
edebe297 A |
203 | if (isA_CFBoolean(bVal)) { |
204 | bundleInfo->builtin = CFBooleanGetValue(bVal); | |
205 | } | |
206 | ||
207 | bVal = CFDictionaryGetValue(bundleDict, kSCBundleEnabledKey); | |
208 | if (isA_CFBoolean(bVal)) { | |
209 | bundleInfo->enabled = CFBooleanGetValue(bVal); | |
dbf6a266 | 210 | } |
5958d7c0 | 211 | |
dbf6a266 | 212 | bVal = CFDictionaryGetValue(bundleDict, kSCBundleVerboseKey); |
edebe297 A |
213 | if (isA_CFBoolean(bVal)) { |
214 | bundleInfo->verbose = CFBooleanGetValue(bVal); | |
dbf6a266 A |
215 | } |
216 | } | |
5958d7c0 | 217 | |
dbf6a266 A |
218 | CFArrayAppendValue(allBundles, bundleInfo); |
219 | return; | |
5958d7c0 A |
220 | } |
221 | ||
222 | ||
17d3ee29 | 223 | static CF_RETURNS_RETAINED CFStringRef |
0fae82ee | 224 | shortBundleIdentifier(CFStringRef bundleID) |
5958d7c0 | 225 | { |
dbf6a266 A |
226 | CFIndex len = CFStringGetLength(bundleID); |
227 | CFRange range; | |
0fae82ee A |
228 | CFStringRef shortID = NULL; |
229 | ||
230 | if (CFStringFindWithOptions(bundleID, | |
231 | CFSTR("."), | |
232 | CFRangeMake(0, len), | |
233 | kCFCompareBackwards, | |
234 | &range)) { | |
235 | range.location = range.location + range.length; | |
236 | range.length = len - range.location; | |
237 | shortID = CFStringCreateWithSubstring(NULL, bundleID, range); | |
238 | } | |
5958d7c0 | 239 | |
0fae82ee A |
240 | return shortID; |
241 | } | |
5958d7c0 | 242 | |
5958d7c0 | 243 | |
dbf6a266 A |
244 | static void * |
245 | getBundleSymbol(CFBundleRef bundle, CFStringRef functionName, CFStringRef shortID) | |
246 | { | |
247 | void *func; | |
0fae82ee | 248 | |
dbf6a266 A |
249 | // search for load(), start(), prime(), stop(), ... |
250 | func = CFBundleGetFunctionPointerForName(bundle, functionName); | |
251 | if (func != NULL) { | |
252 | return func; | |
5958d7c0 A |
253 | } |
254 | ||
dbf6a266 A |
255 | if (shortID != NULL) { |
256 | CFStringRef altFunctionName; | |
257 | ||
258 | // search for load_XXX(), ... | |
259 | altFunctionName = CFStringCreateWithFormat(NULL, | |
260 | NULL, | |
261 | CFSTR("%@_%@"), | |
262 | functionName, | |
263 | shortID); | |
264 | func = CFBundleGetFunctionPointerForName(bundle, altFunctionName); | |
265 | CFRelease(altFunctionName); | |
5958d7c0 A |
266 | } |
267 | ||
dbf6a266 A |
268 | return func; |
269 | } | |
5958d7c0 | 270 | |
dbf6a266 | 271 | |
a40a14f8 A |
272 | static const char * |
273 | getBundleDirNameAndPath(CFBundleRef bundle, char *buf, size_t buf_len) | |
274 | { | |
275 | char *cp; | |
78403150 | 276 | size_t len; |
a40a14f8 A |
277 | Boolean ok; |
278 | CFURLRef url; | |
279 | ||
280 | url = CFBundleCopyBundleURL(bundle); | |
281 | if (url == NULL) { | |
282 | return NULL; | |
283 | } | |
284 | ||
285 | ok = CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)buf, buf_len); | |
286 | CFRelease(url); | |
287 | if (!ok) { | |
288 | return NULL; | |
289 | } | |
290 | ||
291 | cp = strrchr(buf, '/'); | |
292 | if (cp != NULL) { | |
293 | cp++; | |
294 | } else { | |
295 | cp = buf; | |
296 | } | |
297 | ||
298 | /* check if this directory entry is a valid bundle name */ | |
299 | len = strlen(cp); | |
78403150 | 300 | if (len <= sizeof(BUNDLE_DIR_EXTENSION)) { |
a40a14f8 A |
301 | /* if entry name isn't long enough */ |
302 | return NULL; | |
303 | } | |
304 | ||
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" */ | |
308 | return NULL; | |
309 | } | |
310 | ||
311 | return cp; | |
312 | } | |
313 | ||
314 | ||
315 | #pragma mark - | |
316 | #pragma mark load | |
317 | ||
318 | ||
dbf6a266 A |
319 | static void |
320 | loadBundle(const void *value, void *context) { | |
321 | CFStringRef bundleID; | |
17d3ee29 | 322 | Boolean bundleAllowed; |
dbf6a266 A |
323 | bundleInfoRef bundleInfo = (bundleInfoRef)value; |
324 | Boolean bundleExclude; | |
325 | CFIndex *nLoaded = (CFIndex *)context; | |
326 | CFStringRef shortID; | |
327 | ||
328 | bundleID = CFBundleGetIdentifier(bundleInfo->bundle); | |
329 | if (bundleID == NULL) { | |
330 | // sorry, no bundles without a bundle identifier | |
9de8ab86 | 331 | SC_log(LOG_NOTICE, "skipped %@ (no bundle ID)", bundleInfo->bundle); |
0fae82ee A |
332 | return; |
333 | } | |
5958d7c0 | 334 | |
dbf6a266 | 335 | shortID = shortBundleIdentifier(bundleID); |
5958d7c0 | 336 | |
17d3ee29 A |
337 | bundleAllowed = ((CFSetGetCount(_plugins_allowed) == 0) || // if no white-listing |
338 | CFSetContainsValue(_plugins_allowed, bundleID) || // if [bundleID] white-listed | |
339 | ((shortID != NULL) && | |
340 | CFSetContainsValue(_plugins_allowed, shortID))|| // if [short bundleID] white-listed | |
341 | bundleInfo->forced // if "testing" plugin | |
342 | ); | |
343 | if (!bundleAllowed) { | |
9de8ab86 | 344 | SC_log(LOG_INFO, "skipped %@ (not allowed)", bundleID); |
17d3ee29 | 345 | goto done; |
5958d7c0 A |
346 | } |
347 | ||
17d3ee29 A |
348 | bundleExclude = (CFSetContainsValue(_plugins_exclude, bundleID) || // if [bundleID] excluded |
349 | ((shortID != NULL) && | |
350 | CFSetContainsValue(_plugins_exclude, shortID)) // if [short bundleID] excluded | |
351 | ); | |
dbf6a266 A |
352 | if (bundleExclude) { |
353 | // sorry, this bundle has been excluded | |
9de8ab86 | 354 | SC_log(LOG_INFO, "skipped %@ (excluded)", bundleID); |
edebe297 A |
355 | goto done; |
356 | } | |
357 | ||
17d3ee29 | 358 | if (!bundleInfo->enabled && !bundleInfo->forced) { |
a40a14f8 | 359 | // sorry, this bundle has not been enabled |
9de8ab86 | 360 | SC_log(LOG_INFO, "skipped %@ (disabled)", bundleID); |
a40a14f8 A |
361 | goto done; |
362 | } | |
363 | ||
dbf6a266 A |
364 | if (!bundleInfo->verbose) { |
365 | bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, bundleID); | |
366 | if (!bundleInfo->verbose) { | |
367 | if (shortID != NULL) { | |
368 | bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, shortID); | |
369 | } | |
370 | } | |
5958d7c0 A |
371 | } |
372 | ||
dbf6a266 | 373 | if (bundleInfo->builtin) { |
9de8ab86 | 374 | SC_log(LOG_INFO, "adding %@", bundleID); |
5958d7c0 | 375 | |
1ef45fa4 | 376 | for (size_t i = 0; i < sizeof(builtin_plugins)/sizeof(builtin_plugins[0]); i++) { |
dbf6a266 A |
377 | if (CFEqual(bundleID, builtin_plugins[i].bundleID)) { |
378 | bundleInfo->load = builtin_plugins[i].load; | |
379 | bundleInfo->start = builtin_plugins[i].start; | |
380 | bundleInfo->prime = builtin_plugins[i].prime; | |
381 | bundleInfo->stop = builtin_plugins[i].stop; | |
382 | break; | |
383 | } | |
384 | } | |
edebe297 A |
385 | |
386 | if ((bundleInfo->load == NULL) && | |
387 | (bundleInfo->start == NULL) && | |
388 | (bundleInfo->prime == NULL) && | |
389 | (bundleInfo->stop == NULL)) { | |
9de8ab86 | 390 | SC_log(LOG_NOTICE, "%@ add failed", bundleID); |
edebe297 A |
391 | goto done; |
392 | } | |
dbf6a266 | 393 | } else { |
a40a14f8 A |
394 | CFErrorRef error = NULL; |
395 | ||
9de8ab86 | 396 | SC_log(LOG_INFO, "loading %@", bundleID); |
5958d7c0 | 397 | |
a40a14f8 | 398 | if (!CFBundleLoadExecutableAndReturnError(bundleInfo->bundle, &error)) { |
78403150 | 399 | CFDictionaryRef user_info; |
9de8ab86 A |
400 | |
401 | SC_log(LOG_NOTICE, "%@ load failed", bundleID); | |
78403150 A |
402 | user_info = CFErrorCopyUserInfo(error); |
403 | if (user_info != NULL) { | |
404 | CFStringRef link_error_string; | |
405 | ||
406 | link_error_string = CFDictionaryGetValue(user_info, | |
407 | CFSTR("NSDebugDescription")); | |
408 | if (link_error_string != NULL) { | |
9de8ab86 | 409 | SC_log(LOG_NOTICE, "%@", link_error_string); |
78403150 A |
410 | } |
411 | CFRelease(user_info); | |
412 | } | |
a40a14f8 | 413 | CFRelease(error); |
dbf6a266 | 414 | goto done; |
0fae82ee | 415 | } |
dbf6a266 A |
416 | |
417 | // get bundle entry points | |
418 | bundleInfo->load = getBundleSymbol(bundleInfo->bundle, CFSTR("load" ), shortID); | |
419 | bundleInfo->start = getBundleSymbol(bundleInfo->bundle, CFSTR("start"), shortID); | |
420 | bundleInfo->prime = getBundleSymbol(bundleInfo->bundle, CFSTR("prime"), shortID); | |
421 | bundleInfo->stop = getBundleSymbol(bundleInfo->bundle, CFSTR("stop" ), shortID); | |
5958d7c0 A |
422 | } |
423 | ||
dbf6a266 A |
424 | /* mark this bundle as having been loaded */ |
425 | bundleInfo->loaded = TRUE; | |
5958d7c0 | 426 | |
dbf6a266 A |
427 | /* bump the count of loaded bundles */ |
428 | *nLoaded = *nLoaded + 1; | |
429 | ||
430 | done : | |
5958d7c0 | 431 | |
dbf6a266 | 432 | if (shortID != NULL) CFRelease(shortID); |
0fae82ee | 433 | return; |
5958d7c0 A |
434 | } |
435 | ||
436 | ||
dbf6a266 | 437 | void |
1ef45fa4 A |
438 | callLoadFunction(const void *value, void *context) |
439 | { | |
440 | #pragma unused(context) | |
dbf6a266 | 441 | bundleInfoRef bundleInfo = (bundleInfoRef)value; |
0fae82ee | 442 | |
dbf6a266 | 443 | if (!bundleInfo->loaded) { |
0fae82ee | 444 | return; |
5958d7c0 | 445 | } |
5958d7c0 | 446 | |
dbf6a266 A |
447 | if (bundleInfo->load == NULL) { |
448 | // if no load() function | |
449 | return; | |
450 | } | |
451 | ||
942cecd7 A |
452 | SC_log(LOG_DEBUG, "calling load() for %@", |
453 | CFBundleGetIdentifier(bundleInfo->bundle)); | |
edebe297 | 454 | |
dbf6a266 | 455 | (*bundleInfo->load)(bundleInfo->bundle, bundleInfo->verbose); |
edebe297 | 456 | |
dbf6a266 A |
457 | return; |
458 | } | |
459 | ||
460 | ||
a40a14f8 A |
461 | #pragma mark - |
462 | #pragma mark start | |
463 | ||
464 | ||
dbf6a266 | 465 | void |
1ef45fa4 A |
466 | callStartFunction(const void *value, void *context) |
467 | { | |
468 | #pragma unused(context) | |
a40a14f8 | 469 | const char *bundleDirName; |
dbf6a266 | 470 | bundleInfoRef bundleInfo = (bundleInfoRef)value; |
dbf6a266 A |
471 | char bundleName[MAXNAMLEN + 1]; |
472 | char bundlePath[MAXPATHLEN]; | |
78403150 | 473 | size_t len; |
dbf6a266 A |
474 | |
475 | if (!bundleInfo->loaded) { | |
0fae82ee A |
476 | return; |
477 | } | |
5958d7c0 | 478 | |
dbf6a266 A |
479 | if (bundleInfo->start == NULL) { |
480 | // if no start() function | |
0fae82ee A |
481 | return; |
482 | } | |
5958d7c0 | 483 | |
a40a14f8 A |
484 | /* copy the bundle's path */ |
485 | bundleDirName = getBundleDirNameAndPath(bundleInfo->bundle, bundlePath, sizeof(bundlePath)); | |
486 | if (bundleDirName == NULL) { | |
487 | // if we have a problem with the bundle's path | |
5958d7c0 A |
488 | return; |
489 | } | |
490 | ||
a40a14f8 A |
491 | /* copy (just) the bundle's name */ |
492 | if (strlcpy(bundleName, bundleDirName, sizeof(bundleName)) > sizeof(bundleName)) { | |
493 | // if we have a problem with the bundle's name | |
5958d7c0 A |
494 | return; |
495 | } | |
a40a14f8 A |
496 | len = strlen(bundleName) - (sizeof(BUNDLE_DIR_EXTENSION) - 1); |
497 | bundleName[len] = '\0'; | |
5958d7c0 | 498 | |
942cecd7 A |
499 | SC_log(LOG_DEBUG, "calling start() for %@", |
500 | CFBundleGetIdentifier(bundleInfo->bundle)); | |
edebe297 | 501 | |
dbf6a266 | 502 | (*bundleInfo->start)(bundleName, bundlePath); |
edebe297 | 503 | |
dbf6a266 A |
504 | return; |
505 | } | |
506 | ||
507 | ||
a40a14f8 A |
508 | #pragma mark - |
509 | #pragma mark prime | |
510 | ||
511 | ||
dbf6a266 | 512 | void |
1ef45fa4 A |
513 | callPrimeFunction(const void *value, void *context) |
514 | { | |
515 | #pragma unused(context) | |
dbf6a266 A |
516 | bundleInfoRef bundleInfo = (bundleInfoRef)value; |
517 | ||
518 | if (!bundleInfo->loaded) { | |
519 | return; | |
520 | } | |
521 | ||
522 | if (bundleInfo->prime == NULL) { | |
523 | // if no prime() function | |
524 | return; | |
525 | } | |
526 | ||
942cecd7 A |
527 | SC_log(LOG_DEBUG, "calling prime() for %@", |
528 | CFBundleGetIdentifier(bundleInfo->bundle)); | |
edebe297 | 529 | |
dbf6a266 | 530 | (*bundleInfo->prime)(); |
edebe297 | 531 | |
5958d7c0 A |
532 | return; |
533 | } | |
534 | ||
535 | ||
a40a14f8 A |
536 | #pragma mark - |
537 | #pragma mark stop | |
538 | ||
539 | ||
5958d7c0 | 540 | static void |
dbf6a266 A |
541 | stopComplete(void *info) |
542 | { | |
543 | CFBundleRef bundle = (CFBundleRef)info; | |
544 | CFStringRef bundleID = CFBundleGetIdentifier(bundle); | |
545 | CFRunLoopSourceRef stopRls; | |
546 | ||
9de8ab86 | 547 | SC_log(LOG_INFO, "** %@ complete (%f)", bundleID, CFAbsoluteTimeGetCurrent()); |
dbf6a266 A |
548 | |
549 | stopRls = (CFRunLoopSourceRef)CFDictionaryGetValue(exiting, bundle); | |
a40a14f8 A |
550 | if (stopRls == NULL) { |
551 | return; | |
552 | } | |
553 | ||
dbf6a266 A |
554 | CFRunLoopSourceInvalidate(stopRls); |
555 | ||
556 | CFDictionaryRemoveValue(exiting, bundle); | |
557 | ||
558 | if (CFDictionaryGetCount(exiting) == 0) { | |
dbf6a266 | 559 | // if all of the plugins are happy |
9de8ab86 | 560 | SC_log(LOG_INFO, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent()); |
afb19109 | 561 | exit (EX_OK); |
dbf6a266 | 562 | } |
5958d7c0 | 563 | |
dbf6a266 A |
564 | return; |
565 | } | |
566 | ||
567 | ||
568 | static void | |
569 | stopDelayed(CFRunLoopTimerRef timer, void *info) | |
570 | { | |
1ef45fa4 A |
571 | #pragma unused(timer) |
572 | #pragma unused(info) | |
dbf6a266 A |
573 | const void **keys; |
574 | CFIndex i; | |
575 | CFIndex n; | |
dbf6a266 | 576 | |
9de8ab86 | 577 | SC_log(LOG_INFO, "server shutdown was delayed, unresponsive plugins:"); |
dbf6a266 A |
578 | |
579 | /* | |
580 | * we've asked our plugins to shutdown but someone | |
581 | * isn't listening. | |
582 | */ | |
583 | n = CFDictionaryGetCount(exiting); | |
584 | keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0); | |
585 | CFDictionaryGetKeysAndValues(exiting, keys, NULL); | |
586 | for (i = 0; i < n; i++) { | |
587 | CFBundleRef bundle; | |
588 | CFStringRef bundleID; | |
589 | ||
590 | bundle = (CFBundleRef)keys[i]; | |
591 | bundleID = CFBundleGetIdentifier(bundle); | |
9de8ab86 | 592 | SC_log(LOG_NOTICE, "** %@", bundleID); |
dbf6a266 A |
593 | } |
594 | CFAllocatorDeallocate(NULL, keys); | |
595 | ||
afb19109 | 596 | exit (EX_OK); |
dbf6a266 A |
597 | } |
598 | ||
edebe297 A |
599 | static CFStringRef |
600 | stopRLSCopyDescription(const void *info) | |
601 | { | |
602 | CFBundleRef bundle = (CFBundleRef)info; | |
603 | ||
604 | return CFStringCreateWithFormat(NULL, | |
605 | NULL, | |
606 | CFSTR("<stopRLS %p> {bundleID = %@}"), | |
607 | info, | |
608 | CFBundleGetIdentifier(bundle)); | |
609 | } | |
610 | ||
611 | ||
dbf6a266 | 612 | static void |
1ef45fa4 A |
613 | stopBundle(const void *value, void *context) |
614 | { | |
615 | #pragma unused(context) | |
dbf6a266 A |
616 | bundleInfoRef bundleInfo = (bundleInfoRef)value; |
617 | CFRunLoopSourceRef stopRls; | |
edebe297 A |
618 | CFRunLoopSourceContext stopContext = { 0 // version |
619 | , bundleInfo->bundle // info | |
620 | , CFRetain // retain | |
621 | , CFRelease // release | |
622 | , stopRLSCopyDescription // copyDescription | |
623 | , CFEqual // equal | |
624 | , CFHash // hash | |
625 | , NULL // schedule | |
626 | , NULL // cancel | |
627 | , stopComplete // perform | |
dbf6a266 A |
628 | }; |
629 | ||
630 | if (!bundleInfo->loaded) { | |
5958d7c0 A |
631 | return; |
632 | } | |
633 | ||
dbf6a266 A |
634 | if (bundleInfo->stop == NULL) { |
635 | // if no stop() function | |
0fae82ee | 636 | return; |
5958d7c0 A |
637 | } |
638 | ||
dbf6a266 A |
639 | stopRls = CFRunLoopSourceCreate(NULL, 0, &stopContext); |
640 | CFRunLoopAddSource(CFRunLoopGetCurrent(), stopRls, kCFRunLoopDefaultMode); | |
641 | CFDictionaryAddValue(exiting, bundleInfo->bundle, stopRls); | |
dbf6a266 | 642 | (*bundleInfo->stop)(stopRls); |
afb19109 | 643 | CFRelease(stopRls); |
dbf6a266 A |
644 | |
645 | return; | |
646 | } | |
647 | ||
648 | ||
649 | static void | |
650 | stopBundles() | |
651 | { | |
652 | /* | |
653 | * If defined, call each bundles stop() function. This function is | |
654 | * called when configd has been asked to shut down (via a SIGTERM). The | |
655 | * function should signal the provided run loop source when it is "ready" | |
656 | * for the shut down to proceeed. | |
657 | */ | |
9de8ab86 | 658 | SC_log(LOG_DEBUG, "calling bundle stop() functions"); |
dbf6a266 A |
659 | CFArrayApplyFunction(allBundles, |
660 | CFRangeMake(0, CFArrayGetCount(allBundles)), | |
661 | stopBundle, | |
662 | NULL); | |
663 | ||
664 | if (CFDictionaryGetCount(exiting) == 0) { | |
dbf6a266 | 665 | // if all of the plugins are happy |
9de8ab86 | 666 | SC_log(LOG_INFO, "server shutdown complete (%f)", CFAbsoluteTimeGetCurrent()); |
afb19109 | 667 | exit (EX_OK); |
dbf6a266 A |
668 | } else { |
669 | CFRunLoopTimerRef timer; | |
670 | ||
6bb65964 A |
671 | /* |
672 | * launchd will only wait 20 seconds before sending us a | |
673 | * SIGKILL and because we want to know what's stuck before | |
674 | * that time so set our own "we're not waiting any longer" | |
675 | * timeout for 15 seconds. | |
676 | */ | |
dbf6a266 | 677 | timer = CFRunLoopTimerCreate(NULL, /* allocator */ |
6bb65964 | 678 | CFAbsoluteTimeGetCurrent() + 15.0, /* fireDate (in 15 seconds) */ |
dbf6a266 A |
679 | 0.0, /* interval (== one-shot) */ |
680 | 0, /* flags */ | |
681 | 0, /* order */ | |
682 | stopDelayed, /* callout */ | |
683 | NULL); /* context */ | |
684 | CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); | |
685 | CFRelease(timer); | |
686 | } | |
687 | ||
5958d7c0 A |
688 | return; |
689 | } | |
690 | ||
691 | ||
a40a14f8 A |
692 | #pragma mark - |
693 | #pragma mark term | |
694 | ||
695 | ||
dbf6a266 A |
696 | __private_extern__ |
697 | Boolean | |
698 | plugin_term(int *status) | |
699 | { | |
c956c85e | 700 | if (CFArrayGetCount(allBundles) == 0) { |
dbf6a266 A |
701 | // if no plugins |
702 | *status = EX_OK; | |
703 | return FALSE; // don't delay shutdown | |
704 | } | |
705 | ||
706 | if (exiting != NULL) { | |
707 | // if shutdown already active | |
708 | return TRUE; | |
709 | } | |
710 | ||
9de8ab86 | 711 | SC_log(LOG_INFO, "starting server shutdown (%f)", CFAbsoluteTimeGetCurrent()); |
dbf6a266 A |
712 | |
713 | exiting = CFDictionaryCreateMutable(NULL, | |
714 | 0, | |
715 | &kCFTypeDictionaryKeyCallBacks, | |
716 | &kCFTypeDictionaryValueCallBacks); | |
717 | ||
c956c85e | 718 | stopBundles(); |
dbf6a266 A |
719 | return TRUE; |
720 | } | |
721 | ||
722 | ||
a40a14f8 A |
723 | #pragma mark - |
724 | #pragma mark initialization | |
725 | ||
726 | ||
0fae82ee A |
727 | static void |
728 | sortBundles(CFMutableArrayRef orig) | |
729 | { | |
5e9ce69e A |
730 | CFIndex i; |
731 | CFIndex n; | |
dbf6a266 | 732 | CFMutableArrayRef new; |
5e9ce69e A |
733 | CFMutableSetRef orig_bundleIDs; |
734 | ||
735 | orig_bundleIDs = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); | |
736 | ||
737 | n = CFArrayGetCount(orig); | |
738 | for (i = 0; i < n; i++) { | |
739 | bundleInfoRef bundleInfo = (bundleInfoRef)CFArrayGetValueAtIndex(orig, i); | |
740 | CFStringRef bundleID = CFBundleGetIdentifier(bundleInfo->bundle); | |
741 | ||
742 | if (bundleID != NULL) { | |
743 | CFSetAddValue(orig_bundleIDs, bundleID); | |
744 | } | |
745 | } | |
0fae82ee | 746 | |
dbf6a266 | 747 | new = CFArrayCreateMutable(NULL, 0, NULL); |
5e9ce69e | 748 | while (n > 0) { |
009ee3c6 | 749 | Boolean inserted = FALSE; |
0fae82ee | 750 | |
5e9ce69e | 751 | for (i = 0; i < n; i++) { |
dbf6a266 A |
752 | bundleInfoRef bundleInfo1 = (bundleInfoRef)CFArrayGetValueAtIndex(orig, i); |
753 | CFStringRef bundleID1 = CFBundleGetIdentifier(bundleInfo1->bundle); | |
78403150 | 754 | CFIndex count; |
0fae82ee | 755 | CFDictionaryRef dict; |
78403150 A |
756 | CFIndex j; |
757 | CFIndex nRequires; | |
0fae82ee A |
758 | CFArrayRef requires = NULL; |
759 | ||
dbf6a266 | 760 | dict = isA_CFDictionary(CFBundleGetInfoDictionary(bundleInfo1->bundle)); |
0fae82ee | 761 | if (dict) { |
dbf6a266 | 762 | requires = CFDictionaryGetValue(dict, kSCBundleRequiresKey); |
0fae82ee A |
763 | requires = isA_CFArray(requires); |
764 | } | |
765 | if (bundleID1 == NULL || requires == NULL) { | |
dbf6a266 | 766 | CFArrayInsertValueAtIndex(new, 0, bundleInfo1); |
0fae82ee A |
767 | CFArrayRemoveValueAtIndex(orig, i); |
768 | inserted = TRUE; | |
769 | break; | |
770 | } | |
009ee3c6 A |
771 | count = nRequires = CFArrayGetCount(requires); |
772 | for (j = 0; j < nRequires; j++) { | |
78403150 A |
773 | CFIndex k; |
774 | CFIndex nNew; | |
0fae82ee A |
775 | CFStringRef r = CFArrayGetValueAtIndex(requires, j); |
776 | ||
5e9ce69e A |
777 | if (!CFSetContainsValue(orig_bundleIDs, r)) { |
778 | // if dependency not present | |
779 | count--; | |
780 | continue; | |
781 | } | |
782 | ||
009ee3c6 A |
783 | nNew = CFArrayGetCount(new); |
784 | for (k = 0; k < nNew; k++) { | |
dbf6a266 A |
785 | bundleInfoRef bundleInfo2 = (bundleInfoRef)CFArrayGetValueAtIndex(new, k); |
786 | CFStringRef bundleID2 = CFBundleGetIdentifier(bundleInfo2->bundle); | |
0fae82ee A |
787 | |
788 | if (bundleID2 && CFEqual(bundleID2, r)) { | |
789 | count--; | |
790 | } | |
791 | } | |
792 | } | |
793 | if (count == 0) { | |
794 | /* all dependencies are met, append */ | |
dbf6a266 | 795 | CFArrayAppendValue(new, bundleInfo1); |
0fae82ee A |
796 | CFArrayRemoveValueAtIndex(orig, i); |
797 | inserted = TRUE; | |
798 | break; | |
799 | } | |
800 | } | |
801 | ||
942cecd7 | 802 | if (!inserted) { |
9de8ab86 | 803 | SC_log(LOG_NOTICE, "Bundles have circular dependency!!!"); |
0fae82ee A |
804 | break; |
805 | } | |
5e9ce69e A |
806 | |
807 | n = CFArrayGetCount(orig); | |
0fae82ee A |
808 | } |
809 | if (CFArrayGetCount(orig) > 0) { | |
810 | /* we have a circular dependency, append remaining items on new array */ | |
811 | CFArrayAppendArray(new, orig, CFRangeMake(0, CFArrayGetCount(orig))); | |
812 | } | |
813 | else { | |
814 | /* new one is a sorted version of original */ | |
815 | } | |
816 | ||
817 | CFArrayRemoveAllValues(orig); | |
818 | CFArrayAppendArray(orig, new, CFRangeMake(0, CFArrayGetCount(new))); | |
819 | CFRelease(new); | |
5e9ce69e | 820 | CFRelease(orig_bundleIDs); |
5958d7c0 A |
821 | return; |
822 | } | |
823 | ||
824 | ||
6bb65964 A |
825 | /* |
826 | * ALT_CFRelease() | |
827 | * | |
828 | * An alternate CFRelease() that we can use to fake out the | |
829 | * static analyzer. | |
830 | */ | |
831 | static __inline__ void | |
832 | ALT_CFRelease(CFTypeRef cf) | |
833 | { | |
834 | CFRelease(cf); | |
835 | } | |
836 | ||
837 | ||
009ee3c6 | 838 | __private_extern__ |
c956c85e | 839 | void |
5958d7c0 A |
840 | plugin_exec(void *arg) |
841 | { | |
dbf6a266 | 842 | CFIndex nLoaded = 0; |
5958d7c0 | 843 | |
0fae82ee | 844 | /* keep track of bundles */ |
dbf6a266 | 845 | allBundles = CFArrayCreateMutable(NULL, 0, NULL); |
5958d7c0 | 846 | |
17d3ee29 | 847 | /* add white-listed plugins to those we'll allow to be loaded */ |
1ef45fa4 | 848 | for (size_t i = 0; i < N_PLUGIN_WHITELIST; i++) { |
17d3ee29 A |
849 | if (pluginWhitelist[i] != NULL) { |
850 | CFSetSetValue(_plugins_allowed, pluginWhitelist[i]); | |
851 | } | |
852 | } | |
853 | ||
009ee3c6 A |
854 | /* allow plug-ins to exec child/helper processes */ |
855 | _SCDPluginExecInit(); | |
a5f60add | 856 | |
5958d7c0 | 857 | if (arg == NULL) { |
942cecd7 A |
858 | char path[MAXPATHLEN]; |
859 | sysdir_search_path_enumeration_state state; | |
0fae82ee | 860 | |
5958d7c0 | 861 | /* |
0fae82ee | 862 | * identify and load all bundles |
5958d7c0 | 863 | */ |
942cecd7 A |
864 | state = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_LIBRARY, |
865 | SYSDIR_DOMAIN_MASK_SYSTEM); | |
866 | while ((state = sysdir_get_next_search_path_enumeration(state, path))) { | |
0fae82ee A |
867 | CFArrayRef bundles; |
868 | CFURLRef url; | |
869 | ||
c956c85e | 870 | #if TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST |
5e9ce69e A |
871 | const char *path_sim_prefix; |
872 | ||
873 | path_sim_prefix = getenv("IPHONE_SIMULATOR_ROOT"); | |
874 | if ((path_sim_prefix != NULL) && (strcmp(path_sim_prefix, ".") != 0)) { | |
875 | char path_sim[MAXPATHLEN]; | |
876 | ||
877 | strlcpy(path_sim, path_sim_prefix, sizeof(path_sim)); | |
878 | strlcat(path_sim, path, sizeof(path_sim)); | |
879 | strlcpy(path, path_sim, sizeof(path)); | |
880 | } else { | |
881 | path[0] = '\0'; | |
882 | } | |
c956c85e | 883 | #endif // TARGET_OS_SIMULATOR && !TARGET_OS_MACCATALYST |
5e9ce69e | 884 | |
0fae82ee | 885 | /* load any available bundle */ |
edebe297 | 886 | strlcat(path, BUNDLE_DIRECTORY, sizeof(path)); |
9de8ab86 | 887 | SC_log(LOG_DEBUG, "searching for bundles in \"%s\"", path); |
0fae82ee | 888 | url = CFURLCreateFromFileSystemRepresentation(NULL, |
d6c893b2 | 889 | (UInt8 *)path, |
0fae82ee A |
890 | strlen(path), |
891 | TRUE); | |
892 | bundles = CFBundleCreateBundlesFromDirectory(NULL, url, CFSTR(".bundle")); | |
893 | CFRelease(url); | |
894 | ||
dbf6a266 A |
895 | if (bundles != NULL) { |
896 | CFIndex i; | |
897 | CFIndex n; | |
898 | ||
899 | n = CFArrayGetCount(bundles); | |
900 | for (i = 0; i < n; i++) { | |
901 | CFBundleRef bundle; | |
d6c893b2 | 902 | |
dbf6a266 | 903 | bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundles, i); |
edebe297 | 904 | addBundle(bundle, FALSE); |
6bb65964 A |
905 | |
906 | // The CFBundleCreateBundlesFromDirectory() API has | |
907 | // a known/outstanding bug in that it over-retains the | |
908 | // returned bundles. Since we do not expect this to | |
909 | // be fixed we release the extra references. | |
910 | // | |
911 | // See <rdar://problems/4912137&6078752> for more info. | |
912 | // | |
913 | // Also, we use the hack below to keep the static | |
914 | // analyzer happy. | |
915 | ALT_CFRelease(bundle); | |
dbf6a266 | 916 | } |
0fae82ee A |
917 | CFRelease(bundles); |
918 | } | |
5958d7c0 A |
919 | } |
920 | ||
0fae82ee | 921 | sortBundles(allBundles); |
5958d7c0 | 922 | } else { |
0fae82ee A |
923 | CFBundleRef bundle; |
924 | CFURLRef url; | |
925 | ||
5958d7c0 | 926 | /* |
0fae82ee | 927 | * load (only) the specified bundle |
5958d7c0 | 928 | */ |
0fae82ee | 929 | url = CFURLCreateFromFileSystemRepresentation(NULL, |
d6c893b2 | 930 | (UInt8 *)arg, |
0fae82ee A |
931 | strlen((char *)arg), |
932 | TRUE); | |
933 | bundle = CFBundleCreate(NULL, url); | |
dbf6a266 | 934 | if (bundle != NULL) { |
edebe297 | 935 | addBundle(bundle, TRUE); |
0fae82ee A |
936 | CFRelease(bundle); |
937 | } | |
938 | CFRelease(url); | |
939 | } | |
5958d7c0 | 940 | |
17d3ee29 A |
941 | /* |
942 | * Look for the InterfaceNamer plugin, and move it to the start | |
943 | * of the list. | |
944 | * | |
945 | * Load the InterfaceNamer plugin (and thereby start its thread) | |
946 | * first in an attempt to minimize the amount of time that | |
947 | * opendirectoryd has to wait for the platform UUID to appear in | |
948 | * nvram. | |
949 | * | |
950 | * InterfaceNamer is responsible for creating the platform UUID on | |
951 | * platforms without a UUID in ROM. Until the platform UUID is created | |
952 | * and stashed in nvram, all calls to opendirectoryd to do things like | |
953 | * getpwuid() will block, because opendirectoryd will block while trying | |
954 | * to read the platform UUID from the kernel. | |
955 | * | |
956 | * As an example, dlopen() causes XPC to do some intialization, and | |
957 | * part of that initialization involves communicating with xpcd. | |
958 | * Since xpcd calls getpwuid_r() during its initialization, it will | |
959 | * block until the platform UUID is available. | |
960 | */ | |
1ef45fa4 | 961 | for (CFIndex i = 0; i < CFArrayGetCount(allBundles); i++) { |
17d3ee29 A |
962 | bundleInfoRef bi = (bundleInfoRef)CFArrayGetValueAtIndex(allBundles, i); |
963 | CFStringRef bundleID = CFBundleGetIdentifier(bi->bundle); | |
964 | ||
965 | if (_SC_CFEqual(bundleID, | |
5e9ce69e | 966 | CFSTR("com.apple.SystemConfiguration.InterfaceNamer"))) |
17d3ee29 A |
967 | { |
968 | CFArrayRemoveValueAtIndex(allBundles, i); | |
969 | CFArrayInsertValueAtIndex(allBundles, 0, bi); | |
970 | break; | |
971 | } | |
972 | } | |
973 | ||
0fae82ee | 974 | /* |
dbf6a266 A |
975 | * load each bundle. |
976 | */ | |
9de8ab86 | 977 | SC_log(LOG_DEBUG, "loading bundles"); |
dbf6a266 A |
978 | CFArrayApplyFunction(allBundles, |
979 | CFRangeMake(0, CFArrayGetCount(allBundles)), | |
980 | loadBundle, | |
981 | &nLoaded); | |
982 | ||
983 | /* | |
984 | * If defined, call each bundles load() function. This function (or | |
985 | * the start() function) should initialize any variables, open any | |
986 | * sessions with "configd", and register any needed notifications. | |
0fae82ee A |
987 | * |
988 | * Note: Establishing initial information in the store should be | |
989 | * deferred until the prime() initialization function so that | |
990 | * any bundles which want to receive a notification that the | |
991 | * data has changed will have an opportunity to install a | |
992 | * notification handler. | |
993 | */ | |
9de8ab86 | 994 | SC_log(LOG_DEBUG, "calling bundle load() functions"); |
0fae82ee A |
995 | CFArrayApplyFunction(allBundles, |
996 | CFRangeMake(0, CFArrayGetCount(allBundles)), | |
dbf6a266 A |
997 | callLoadFunction, |
998 | NULL); | |
5958d7c0 | 999 | |
a40a14f8 A |
1000 | if (nLoaded == 0) { |
1001 | // if no bundles loaded | |
c956c85e | 1002 | return; |
a40a14f8 A |
1003 | } |
1004 | ||
0fae82ee A |
1005 | /* |
1006 | * If defined, call each bundles start() function. This function is | |
1007 | * called after the bundle has been loaded and its load() function has | |
1008 | * been called. It should initialize any variables, open any sessions | |
1009 | * with "configd", and register any needed notifications. | |
1010 | * | |
1011 | * Note: Establishing initial information in the store should be | |
1012 | * deferred until the prime() initialization function so that | |
1013 | * any bundles which want to receive a notification that the | |
1014 | * data has changed will have an opportunity to install a | |
1015 | * notification handler. | |
1016 | */ | |
9de8ab86 | 1017 | SC_log(LOG_DEBUG, "calling bundle start() functions"); |
0fae82ee A |
1018 | CFArrayApplyFunction(allBundles, |
1019 | CFRangeMake(0, CFArrayGetCount(allBundles)), | |
dbf6a266 | 1020 | callStartFunction, |
0fae82ee | 1021 | NULL); |
5958d7c0 | 1022 | |
0fae82ee A |
1023 | /* |
1024 | * If defined, call each bundles prime() function. This function is | |
1025 | * called after the bundle has been loaded and its load() and start() | |
1026 | * functions have been called. It should initialize any configuration | |
1027 | * information and/or state in the store. | |
1028 | */ | |
9de8ab86 | 1029 | SC_log(LOG_DEBUG, "calling bundle prime() functions"); |
0fae82ee A |
1030 | CFArrayApplyFunction(allBundles, |
1031 | CFRangeMake(0, CFArrayGetCount(allBundles)), | |
dbf6a266 | 1032 | callPrimeFunction, |
0fae82ee | 1033 | NULL); |
5958d7c0 | 1034 | |
5958d7c0 | 1035 | /* |
c956c85e A |
1036 | * At this point, the assumption is that each loaded plugin will have |
1037 | * established CFMachPort, CFSocket, and CFRunLoopTimer input sources | |
1038 | * to handle any events and registered these sources with this threads | |
1039 | * run loop and we're ready to go. | |
1040 | * | |
1041 | * Note: it is also assumed that any plugin needing to wait and/or block | |
1042 | * will do so only a private thread (or asynchronously on a non-main | |
1043 | * dispatch queue). | |
5958d7c0 | 1044 | */ |
5958d7c0 A |
1045 | |
1046 | return; | |
1047 | } |