]> git.saurik.com Git - apple/configd.git/blame - configd.tproj/plugin_support.c
configd-137.2.tar.gz
[apple/configd.git] / configd.tproj / plugin_support.c
CommitLineData
5958d7c0 1/*
d6c893b2 2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
5958d7c0
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
009ee3c6 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.
12 *
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.
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 <mach-o/dyld.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <sys/param.h>
44#include <dirent.h>
dbf6a266 45#include <sysexits.h>
5958d7c0
A
46#include <unistd.h>
47#include <NSSystemDirectories.h>
48
49#include "configd.h"
dbf6a266 50#include "configd_server.h"
0fae82ee 51#include <SystemConfiguration/SCDPlugin.h>
a5f60add 52void _SCDPluginExecInit();
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
dbf6a266
A
62typedef struct {
63 CFBundleRef bundle;
64 Boolean loaded;
65 Boolean builtin;
66 Boolean verbose;
67 SCDynamicStoreBundleLoadFunction load;
68 SCDynamicStoreBundleStartFunction start;
69 SCDynamicStoreBundlePrimeFunction prime;
70 SCDynamicStoreBundleStopFunction stop;
71} *bundleInfoRef;
72
73
74// all loaded bundles
75static CFMutableArrayRef allBundles = NULL;
76
77// exiting bundles
78static CFMutableDictionaryRef exiting = NULL;
79
80// plugin CFRunLoopRef
81static CFRunLoopRef plugin_runLoop = NULL;
82
83
84#ifdef ppc
ba83da55
A
85extern SCDynamicStoreBundleLoadFunction load_ATconfig;
86extern SCDynamicStoreBundleStopFunction stop_ATconfig;
dbf6a266
A
87#endif /* ppc */
88extern SCDynamicStoreBundleLoadFunction load_IPMonitor;
89extern SCDynamicStoreBundlePrimeFunction prime_IPMonitor;
90extern SCDynamicStoreBundleLoadFunction load_InterfaceNamer;
91extern SCDynamicStoreBundleLoadFunction load_KernelEventMonitor;
92extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor;
93extern SCDynamicStoreBundleLoadFunction load_Kicker;
94extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration;
95extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor;
96extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor;
97extern SCDynamicStoreBundleStopFunction stop_PreferencesMonitor;
98
99
100typedef struct {
101 const CFStringRef bundleID;
102 const void *load; // SCDynamicStoreBundleLoadFunction
103 const void *start; // SCDynamicStoreBundleStartFunction
104 const void *prime; // SCDynamicStoreBundlePrimeFunction
105 const void *stop; // SCDynamicStoreBundleStopFunction
106} builtin, *builtinRef;
107
108
109static const builtin builtin_plugins[] = {
110#ifdef ppc
ba83da55
A
111 {
112 CFSTR("com.apple.SystemConfiguration.ATconfig"),
113 &load_ATconfig,
114 NULL,
115 NULL,
116 &stop_ATconfig
117 },
dbf6a266
A
118#endif /* ppc */
119 {
120 CFSTR("com.apple.SystemConfiguration.IPMonitor"),
121 &load_IPMonitor,
122 NULL,
123 &prime_IPMonitor,
124 NULL
125 },
126 {
127 CFSTR("com.apple.SystemConfiguration.InterfaceNamer"),
128 &load_InterfaceNamer,
129 NULL,
130 NULL,
131 NULL
132 },
133 {
134 CFSTR("com.apple.SystemConfiguration.KernelEventMonitor"),
135 &load_KernelEventMonitor,
136 NULL,
137 &prime_KernelEventMonitor,
138 NULL
139 },
140 {
141 CFSTR("com.apple.SystemConfiguration.Kicker"),
142 &load_Kicker,
143 NULL,
144 NULL,
145 NULL
146 },
147 {
148 CFSTR("com.apple.SystemConfiguration.LinkConfiguration"),
149 &load_LinkConfiguration,
150 NULL,
151 NULL,
152 NULL
153 },
154 {
155 CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"),
156 &load_PreferencesMonitor,
157 NULL,
158 &prime_PreferencesMonitor,
159 &stop_PreferencesMonitor
5958d7c0 160 }
dbf6a266 161};
5958d7c0
A
162
163
dbf6a266
A
164static void
165addBundle(CFBundleRef bundle)
5958d7c0 166{
dbf6a266
A
167 CFDictionaryRef bundleDict;
168 bundleInfoRef bundleInfo;
d6c893b2 169
dbf6a266
A
170 bundleInfo = CFAllocatorAllocate(NULL, sizeof(*bundleInfo), 0);
171 bundleInfo->bundle = (CFBundleRef)CFRetain(bundle);
172 bundleInfo->loaded = FALSE;
173 bundleInfo->builtin = FALSE;
174 bundleInfo->verbose = FALSE;
175 bundleInfo->load = NULL;
176 bundleInfo->start = NULL;
177 bundleInfo->prime = NULL;
178 bundleInfo->stop = NULL;
d6c893b2 179
dbf6a266
A
180 bundleDict = CFBundleGetInfoDictionary(bundle);
181 if (isA_CFDictionary(bundleDict)) {
182 CFBooleanRef bVal;
183
184 bVal = CFDictionaryGetValue(bundleDict, kSCBundleIsBuiltinKey);
185 if (isA_CFBoolean(bVal) && CFBooleanGetValue(bVal)) {
186 bundleInfo->builtin = TRUE;
187 }
5958d7c0 188
dbf6a266
A
189 bVal = CFDictionaryGetValue(bundleDict, kSCBundleVerboseKey);
190 if (isA_CFBoolean(bVal) && CFBooleanGetValue(bVal)) {
191 bundleInfo->verbose = TRUE;
192 }
193 }
5958d7c0 194
dbf6a266
A
195 CFArrayAppendValue(allBundles, bundleInfo);
196 return;
5958d7c0
A
197}
198
199
0fae82ee
A
200static CFStringRef
201shortBundleIdentifier(CFStringRef bundleID)
5958d7c0 202{
dbf6a266
A
203 CFIndex len = CFStringGetLength(bundleID);
204 CFRange range;
0fae82ee
A
205 CFStringRef shortID = NULL;
206
207 if (CFStringFindWithOptions(bundleID,
208 CFSTR("."),
209 CFRangeMake(0, len),
210 kCFCompareBackwards,
211 &range)) {
212 range.location = range.location + range.length;
213 range.length = len - range.location;
214 shortID = CFStringCreateWithSubstring(NULL, bundleID, range);
215 }
5958d7c0 216
0fae82ee
A
217 return shortID;
218}
5958d7c0 219
5958d7c0 220
dbf6a266
A
221static void *
222getBundleSymbol(CFBundleRef bundle, CFStringRef functionName, CFStringRef shortID)
223{
224 void *func;
0fae82ee 225
dbf6a266
A
226 // search for load(), start(), prime(), stop(), ...
227 func = CFBundleGetFunctionPointerForName(bundle, functionName);
228 if (func != NULL) {
229 return func;
5958d7c0
A
230 }
231
dbf6a266
A
232 if (shortID != NULL) {
233 CFStringRef altFunctionName;
234
235 // search for load_XXX(), ...
236 altFunctionName = CFStringCreateWithFormat(NULL,
237 NULL,
238 CFSTR("%@_%@"),
239 functionName,
240 shortID);
241 func = CFBundleGetFunctionPointerForName(bundle, altFunctionName);
242 CFRelease(altFunctionName);
5958d7c0
A
243 }
244
dbf6a266
A
245 return func;
246}
5958d7c0 247
dbf6a266
A
248
249static void
250loadBundle(const void *value, void *context) {
251 CFStringRef bundleID;
252 bundleInfoRef bundleInfo = (bundleInfoRef)value;
253 Boolean bundleExclude;
254 CFIndex *nLoaded = (CFIndex *)context;
255 CFStringRef shortID;
256
257 bundleID = CFBundleGetIdentifier(bundleInfo->bundle);
258 if (bundleID == NULL) {
259 // sorry, no bundles without a bundle identifier
260 SCLog(TRUE, LOG_DEBUG, CFSTR("skipped %@"), bundleInfo->bundle);
0fae82ee
A
261 return;
262 }
5958d7c0 263
dbf6a266 264 shortID = shortBundleIdentifier(bundleID);
5958d7c0 265
dbf6a266
A
266 bundleExclude = CFSetContainsValue(_plugins_exclude, bundleID);
267 if (bundleExclude) {
268 if (shortID != NULL) {
269 bundleExclude = CFSetContainsValue(_plugins_exclude, shortID);
270 }
5958d7c0
A
271 }
272
dbf6a266
A
273 if (bundleExclude) {
274 // sorry, this bundle has been excluded
275 SCLog(TRUE, LOG_DEBUG, CFSTR("excluded %@"), bundleID);
276 goto done;
5958d7c0
A
277 }
278
dbf6a266
A
279 if (!bundleInfo->verbose) {
280 bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, bundleID);
281 if (!bundleInfo->verbose) {
282 if (shortID != NULL) {
283 bundleInfo->verbose = CFSetContainsValue(_plugins_verbose, shortID);
284 }
285 }
5958d7c0
A
286 }
287
dbf6a266
A
288 if (bundleInfo->builtin) {
289 int i;
5958d7c0 290
dbf6a266 291 SCLog(TRUE, LOG_DEBUG, CFSTR("adding %@"), bundleID);
5958d7c0 292
dbf6a266
A
293 for (i = 0; i < sizeof(builtin_plugins)/sizeof(builtin_plugins[0]); i++) {
294 if (CFEqual(bundleID, builtin_plugins[i].bundleID)) {
295 bundleInfo->load = builtin_plugins[i].load;
296 bundleInfo->start = builtin_plugins[i].start;
297 bundleInfo->prime = builtin_plugins[i].prime;
298 bundleInfo->stop = builtin_plugins[i].stop;
299 break;
300 }
301 }
302 } else {
303 SCLog(TRUE, LOG_DEBUG, CFSTR("loading %@"), bundleID);
5958d7c0 304
dbf6a266
A
305 if (!CFBundleLoadExecutable(bundleInfo->bundle)) {
306 SCLog(TRUE, LOG_NOTICE, CFSTR("%@ load failed"), bundleID);
307 goto done;
0fae82ee 308 }
dbf6a266
A
309
310 // get bundle entry points
311 bundleInfo->load = getBundleSymbol(bundleInfo->bundle, CFSTR("load" ), shortID);
312 bundleInfo->start = getBundleSymbol(bundleInfo->bundle, CFSTR("start"), shortID);
313 bundleInfo->prime = getBundleSymbol(bundleInfo->bundle, CFSTR("prime"), shortID);
314 bundleInfo->stop = getBundleSymbol(bundleInfo->bundle, CFSTR("stop" ), shortID);
5958d7c0
A
315 }
316
dbf6a266
A
317 /* mark this bundle as having been loaded */
318 bundleInfo->loaded = TRUE;
5958d7c0 319
dbf6a266
A
320 /* bump the count of loaded bundles */
321 *nLoaded = *nLoaded + 1;
322
323 done :
5958d7c0 324
dbf6a266 325 if (shortID != NULL) CFRelease(shortID);
0fae82ee 326 return;
5958d7c0
A
327}
328
329
dbf6a266
A
330void
331callLoadFunction(const void *value, void *context) {
332 bundleInfoRef bundleInfo = (bundleInfoRef)value;
0fae82ee 333
dbf6a266 334 if (!bundleInfo->loaded) {
0fae82ee 335 return;
5958d7c0 336 }
5958d7c0 337
dbf6a266
A
338 if (bundleInfo->load == NULL) {
339 // if no load() function
340 return;
341 }
342
343 (*bundleInfo->load)(bundleInfo->bundle, bundleInfo->verbose);
344 return;
345}
346
347
348void
349callStartFunction(const void *value, void *context) {
350 bundleInfoRef bundleInfo = (bundleInfoRef)value;
351 CFURLRef bundleURL;
352 char bundleName[MAXNAMLEN + 1];
353 char bundlePath[MAXPATHLEN];
354 char *cp;
355 int len;
356 Boolean ok;
357
358 if (!bundleInfo->loaded) {
0fae82ee
A
359 return;
360 }
5958d7c0 361
dbf6a266
A
362 if (bundleInfo->start == NULL) {
363 // if no start() function
0fae82ee
A
364 return;
365 }
5958d7c0 366
dbf6a266
A
367 bundleURL = CFBundleCopyBundleURL(bundleInfo->bundle);
368 if (bundleURL == NULL) {
0fae82ee 369 return;
5958d7c0 370 }
5958d7c0 371
0fae82ee
A
372 ok = CFURLGetFileSystemRepresentation(bundleURL,
373 TRUE,
374 (UInt8 *)&bundlePath,
375 sizeof(bundlePath));
376 CFRelease(bundleURL);
377 if (!ok) {
378 return;
379 }
5958d7c0 380
0fae82ee
A
381 cp = strrchr(bundlePath, '/');
382 if (cp) {
383 cp++;
384 } else {
385 cp = bundlePath;
386 }
5958d7c0
A
387
388 /* check if this directory entry is a valid bundle name */
0fae82ee 389 len = strlen(cp);
009ee3c6 390 if (len <= (int)sizeof(BUNDLE_DIR_EXTENSION)) {
5958d7c0
A
391 /* if entry name isn't long enough */
392 return;
393 }
394
395 len -= sizeof(BUNDLE_DIR_EXTENSION) - 1;
0fae82ee 396 if (strcmp(&cp[len], BUNDLE_DIR_EXTENSION) != 0) {
5958d7c0
A
397 /* if entry name doesn end with ".bundle" */
398 return;
399 }
400
5958d7c0 401 /* get (just) the bundle's name */
0fae82ee
A
402 bundleName[0] = '\0';
403 (void) strncat(bundleName, cp, len);
5958d7c0 404
dbf6a266
A
405 (*bundleInfo->start)(bundleName, bundlePath);
406 return;
407}
408
409
410void
411callPrimeFunction(const void *value, void *context) {
412 bundleInfoRef bundleInfo = (bundleInfoRef)value;
413
414 if (!bundleInfo->loaded) {
415 return;
416 }
417
418 if (bundleInfo->prime == NULL) {
419 // if no prime() function
420 return;
421 }
422
423 (*bundleInfo->prime)();
5958d7c0
A
424 return;
425}
426
427
428static void
dbf6a266
A
429stopComplete(void *info)
430{
431 CFBundleRef bundle = (CFBundleRef)info;
432 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
433 CFRunLoopSourceRef stopRls;
434
435 SCLog(TRUE, LOG_DEBUG, CFSTR("** %@ complete (%f)"), bundleID, CFAbsoluteTimeGetCurrent());
436
437 stopRls = (CFRunLoopSourceRef)CFDictionaryGetValue(exiting, bundle);
438 CFRunLoopSourceInvalidate(stopRls);
439
440 CFDictionaryRemoveValue(exiting, bundle);
441
442 if (CFDictionaryGetCount(exiting) == 0) {
443 int status;
444
445 // if all of the plugins are happy
446 status = server_shutdown();
447 SCLog(TRUE, LOG_DEBUG, CFSTR("server shutdown complete (%f)"), CFAbsoluteTimeGetCurrent());
448 exit (status);
449 }
5958d7c0 450
dbf6a266
A
451 return;
452}
453
454
455static void
456stopDelayed(CFRunLoopTimerRef timer, void *info)
457{
458 const void **keys;
459 CFIndex i;
460 CFIndex n;
461 int status;
462
463 SCLog(TRUE, LOG_ERR, CFSTR("server shutdown was delayed, unresponsive plugins:"));
464
465 /*
466 * we've asked our plugins to shutdown but someone
467 * isn't listening.
468 */
469 n = CFDictionaryGetCount(exiting);
470 keys = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
471 CFDictionaryGetKeysAndValues(exiting, keys, NULL);
472 for (i = 0; i < n; i++) {
473 CFBundleRef bundle;
474 CFStringRef bundleID;
475
476 bundle = (CFBundleRef)keys[i];
477 bundleID = CFBundleGetIdentifier(bundle);
478 SCLog(TRUE, LOG_ERR, CFSTR("** %@"), bundleID);
479 }
480 CFAllocatorDeallocate(NULL, keys);
481
482 status = server_shutdown();
483 exit (status);
484}
485
486static void
487stopBundle(const void *value, void *context) {
488 bundleInfoRef bundleInfo = (bundleInfoRef)value;
489 CFRunLoopSourceRef stopRls;
490 CFRunLoopSourceContext stopContext = { 0 // version
491 , bundleInfo->bundle // info
492 , CFRetain // retain
493 , CFRelease // release
494 , CFCopyDescription // copyDescription
495 , CFEqual // equal
496 , CFHash // hash
497 , NULL // schedule
498 , NULL // cancel
499 , stopComplete // perform
500 };
501
502 if (!bundleInfo->loaded) {
5958d7c0
A
503 return;
504 }
505
dbf6a266
A
506 if (bundleInfo->stop == NULL) {
507 // if no stop() function
0fae82ee 508 return;
5958d7c0
A
509 }
510
dbf6a266
A
511 stopRls = CFRunLoopSourceCreate(NULL, 0, &stopContext);
512 CFRunLoopAddSource(CFRunLoopGetCurrent(), stopRls, kCFRunLoopDefaultMode);
513 CFDictionaryAddValue(exiting, bundleInfo->bundle, stopRls);
514 CFRelease(stopRls);
515
516 (*bundleInfo->stop)(stopRls);
517
518 return;
519}
520
521
522static void
523stopBundles()
524{
525 /*
526 * If defined, call each bundles stop() function. This function is
527 * called when configd has been asked to shut down (via a SIGTERM). The
528 * function should signal the provided run loop source when it is "ready"
529 * for the shut down to proceeed.
530 */
531 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle stop() functions"));
532 CFArrayApplyFunction(allBundles,
533 CFRangeMake(0, CFArrayGetCount(allBundles)),
534 stopBundle,
535 NULL);
536
537 if (CFDictionaryGetCount(exiting) == 0) {
538 int status;
539
540 // if all of the plugins are happy
541 status = server_shutdown();
542 SCLog(TRUE, LOG_DEBUG, CFSTR("server shutdown complete (%f)"), CFAbsoluteTimeGetCurrent());
543 exit (status);
544 } else {
545 CFRunLoopTimerRef timer;
546
547 /* sorry, we're not going to wait longer than 20 seconds */
548 timer = CFRunLoopTimerCreate(NULL, /* allocator */
549 CFAbsoluteTimeGetCurrent() + 20.0, /* fireDate (in 20 seconds) */
550 0.0, /* interval (== one-shot) */
551 0, /* flags */
552 0, /* order */
553 stopDelayed, /* callout */
554 NULL); /* context */
555 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
556 CFRelease(timer);
557 }
558
5958d7c0
A
559 return;
560}
561
562
dbf6a266
A
563__private_extern__
564Boolean
565plugin_term(int *status)
566{
567 CFRunLoopSourceRef stopRls;
568 CFRunLoopSourceContext stopContext = { 0 // version
569 , NULL // info
570 , NULL // retain
571 , NULL // release
572 , NULL // copyDescription
573 , NULL // equal
574 , NULL // hash
575 , NULL // schedule
576 , NULL // cancel
577 , stopBundles // perform
578 };
579
580 if (plugin_runLoop == NULL) {
581 // if no plugins
582 *status = EX_OK;
583 return FALSE; // don't delay shutdown
584 }
585
586 if (exiting != NULL) {
587 // if shutdown already active
588 return TRUE;
589 }
590
591 SCLog(TRUE, LOG_DEBUG, CFSTR("starting server shutdown (%f)"), CFAbsoluteTimeGetCurrent());
592
593 exiting = CFDictionaryCreateMutable(NULL,
594 0,
595 &kCFTypeDictionaryKeyCallBacks,
596 &kCFTypeDictionaryValueCallBacks);
597
598 stopRls = CFRunLoopSourceCreate(NULL, 0, &stopContext);
599 CFRunLoopAddSource(plugin_runLoop, stopRls, kCFRunLoopDefaultMode);
600 CFRunLoopSourceSignal(stopRls);
601 CFRelease(stopRls);
602 CFRunLoopWakeUp(plugin_runLoop);
603
604 return TRUE;
605}
606
607
a5f60add
A
608#ifdef DEBUG
609
0fae82ee 610static void
5958d7c0
A
611timerCallback(CFRunLoopTimerRef timer, void *info)
612{
0fae82ee
A
613 SCLog(_configd_verbose,
614 LOG_INFO,
615 CFSTR("the CFRunLoop is waiting for something to happen...."));
616 return;
617}
618
a5f60add
A
619#endif /* DEBUG */
620
0fae82ee
A
621
622static void
623sortBundles(CFMutableArrayRef orig)
624{
dbf6a266 625 CFMutableArrayRef new;
0fae82ee 626
dbf6a266 627 new = CFArrayCreateMutable(NULL, 0, NULL);
0fae82ee
A
628 while (CFArrayGetCount(orig) > 0) {
629 int i;
009ee3c6
A
630 Boolean inserted = FALSE;
631 int nOrig = CFArrayGetCount(orig);
0fae82ee 632
009ee3c6 633 for (i = 0; i < nOrig; i++) {
dbf6a266
A
634 bundleInfoRef bundleInfo1 = (bundleInfoRef)CFArrayGetValueAtIndex(orig, i);
635 CFStringRef bundleID1 = CFBundleGetIdentifier(bundleInfo1->bundle);
0fae82ee
A
636 int count;
637 CFDictionaryRef dict;
638 int j;
009ee3c6 639 int nRequires;
0fae82ee
A
640 CFArrayRef requires = NULL;
641
dbf6a266 642 dict = isA_CFDictionary(CFBundleGetInfoDictionary(bundleInfo1->bundle));
0fae82ee 643 if (dict) {
dbf6a266 644 requires = CFDictionaryGetValue(dict, kSCBundleRequiresKey);
0fae82ee
A
645 requires = isA_CFArray(requires);
646 }
647 if (bundleID1 == NULL || requires == NULL) {
dbf6a266 648 CFArrayInsertValueAtIndex(new, 0, bundleInfo1);
0fae82ee
A
649 CFArrayRemoveValueAtIndex(orig, i);
650 inserted = TRUE;
651 break;
652 }
009ee3c6
A
653 count = nRequires = CFArrayGetCount(requires);
654 for (j = 0; j < nRequires; j++) {
0fae82ee 655 int k;
009ee3c6 656 int nNew;
0fae82ee
A
657 CFStringRef r = CFArrayGetValueAtIndex(requires, j);
658
009ee3c6
A
659 nNew = CFArrayGetCount(new);
660 for (k = 0; k < nNew; k++) {
dbf6a266
A
661 bundleInfoRef bundleInfo2 = (bundleInfoRef)CFArrayGetValueAtIndex(new, k);
662 CFStringRef bundleID2 = CFBundleGetIdentifier(bundleInfo2->bundle);
0fae82ee
A
663
664 if (bundleID2 && CFEqual(bundleID2, r)) {
665 count--;
666 }
667 }
668 }
669 if (count == 0) {
670 /* all dependencies are met, append */
dbf6a266 671 CFArrayAppendValue(new, bundleInfo1);
0fae82ee
A
672 CFArrayRemoveValueAtIndex(orig, i);
673 inserted = TRUE;
674 break;
675 }
676 }
677
678 if (inserted == FALSE) {
679 SCLog(TRUE, LOG_NOTICE, CFSTR("Bundles have circular dependency!!!"));
680 break;
681 }
682 }
683 if (CFArrayGetCount(orig) > 0) {
684 /* we have a circular dependency, append remaining items on new array */
685 CFArrayAppendArray(new, orig, CFRangeMake(0, CFArrayGetCount(orig)));
686 }
687 else {
688 /* new one is a sorted version of original */
689 }
690
691 CFArrayRemoveAllValues(orig);
692 CFArrayAppendArray(orig, new, CFRangeMake(0, CFArrayGetCount(new)));
693 CFRelease(new);
5958d7c0
A
694 return;
695}
696
697
009ee3c6 698__private_extern__
5958d7c0
A
699void *
700plugin_exec(void *arg)
701{
dbf6a266 702 CFIndex nLoaded = 0;
5958d7c0 703
0fae82ee 704 /* keep track of bundles */
dbf6a266 705 allBundles = CFArrayCreateMutable(NULL, 0, NULL);
5958d7c0 706
009ee3c6
A
707 /* allow plug-ins to exec child/helper processes */
708 _SCDPluginExecInit();
a5f60add 709
5958d7c0 710 if (arg == NULL) {
0fae82ee
A
711 char path[MAXPATHLEN];
712 NSSearchPathEnumerationState state;
713
5958d7c0 714 /*
0fae82ee 715 * identify and load all bundles
5958d7c0
A
716 */
717 state = NSStartSearchPathEnumeration(NSLibraryDirectory,
dbf6a266 718 NSSystemDomainMask);
5958d7c0 719 while ((state = NSGetNextSearchPathEnumeration(state, path))) {
0fae82ee
A
720 CFArrayRef bundles;
721 CFURLRef url;
722
723 /* load any available bundle */
5958d7c0 724 strcat(path, BUNDLE_DIRECTORY);
0fae82ee
A
725 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("searching for bundles in \".\""));
726 url = CFURLCreateFromFileSystemRepresentation(NULL,
d6c893b2 727 (UInt8 *)path,
0fae82ee
A
728 strlen(path),
729 TRUE);
730 bundles = CFBundleCreateBundlesFromDirectory(NULL, url, CFSTR(".bundle"));
731 CFRelease(url);
732
dbf6a266
A
733 if (bundles != NULL) {
734 CFIndex i;
735 CFIndex n;
736
737 n = CFArrayGetCount(bundles);
738 for (i = 0; i < n; i++) {
739 CFBundleRef bundle;
d6c893b2 740
dbf6a266
A
741 bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundles, i);
742 addBundle(bundle);
743 }
0fae82ee
A
744 CFRelease(bundles);
745 }
5958d7c0
A
746 }
747
0fae82ee 748 sortBundles(allBundles);
5958d7c0 749 } else {
0fae82ee
A
750 CFBundleRef bundle;
751 CFURLRef url;
752
5958d7c0 753 /*
0fae82ee 754 * load (only) the specified bundle
5958d7c0 755 */
0fae82ee 756 url = CFURLCreateFromFileSystemRepresentation(NULL,
d6c893b2 757 (UInt8 *)arg,
0fae82ee
A
758 strlen((char *)arg),
759 TRUE);
760 bundle = CFBundleCreate(NULL, url);
dbf6a266
A
761 if (bundle != NULL) {
762 addBundle(bundle);
0fae82ee
A
763 CFRelease(bundle);
764 }
765 CFRelease(url);
766 }
5958d7c0 767
0fae82ee 768 /*
dbf6a266
A
769 * load each bundle.
770 */
771 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("loading bundles"));
772 CFArrayApplyFunction(allBundles,
773 CFRangeMake(0, CFArrayGetCount(allBundles)),
774 loadBundle,
775 &nLoaded);
776
777 /*
778 * If defined, call each bundles load() function. This function (or
779 * the start() function) should initialize any variables, open any
780 * sessions with "configd", and register any needed notifications.
0fae82ee
A
781 *
782 * Note: Establishing initial information in the store should be
783 * deferred until the prime() initialization function so that
784 * any bundles which want to receive a notification that the
785 * data has changed will have an opportunity to install a
786 * notification handler.
787 */
788 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle load() functions"));
789 CFArrayApplyFunction(allBundles,
790 CFRangeMake(0, CFArrayGetCount(allBundles)),
dbf6a266
A
791 callLoadFunction,
792 NULL);
5958d7c0 793
0fae82ee
A
794 /*
795 * If defined, call each bundles start() function. This function is
796 * called after the bundle has been loaded and its load() function has
797 * been called. It should initialize any variables, open any sessions
798 * with "configd", and register any needed notifications.
799 *
800 * Note: Establishing initial information in the store should be
801 * deferred until the prime() initialization function so that
802 * any bundles which want to receive a notification that the
803 * data has changed will have an opportunity to install a
804 * notification handler.
805 */
806 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle start() functions"));
807 CFArrayApplyFunction(allBundles,
808 CFRangeMake(0, CFArrayGetCount(allBundles)),
dbf6a266 809 callStartFunction,
0fae82ee 810 NULL);
5958d7c0 811
0fae82ee
A
812 /*
813 * If defined, call each bundles prime() function. This function is
814 * called after the bundle has been loaded and its load() and start()
815 * functions have been called. It should initialize any configuration
816 * information and/or state in the store.
817 */
818 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("calling bundle prime() functions"));
819 CFArrayApplyFunction(allBundles,
820 CFRangeMake(0, CFArrayGetCount(allBundles)),
dbf6a266 821 callPrimeFunction,
0fae82ee 822 NULL);
5958d7c0 823
a5f60add 824#ifdef DEBUG
0fae82ee
A
825 if (arg == NULL && (nLoaded > 0)) {
826 CFRunLoopTimerRef timer;
5958d7c0
A
827
828 /* allocate a periodic event (to help show we're not blocking) */
a5f60add
A
829 timer = CFRunLoopTimerCreate(NULL, /* allocator */
830 CFAbsoluteTimeGetCurrent() + 1.0, /* fireDate */
831 60.0, /* interval */
832 0, /* flags */
833 0, /* order */
834 timerCallback, /* callout */
835 NULL); /* context */
836 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
837 CFRelease(timer);
838 }
839#endif /* DEBUG */
5958d7c0 840
5958d7c0
A
841 /*
842 * The assumption is that each loaded plugin will establish CFMachPortRef,
843 * CFSocketRef, and CFRunLoopTimerRef input sources to handle any events
844 * and register these sources with this threads run loop. If the plugin
845 * needs to wait and/or block at any time it should do so only in its a
846 * private thread.
847 */
0fae82ee 848 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("starting plugin CFRunLoop"));
dbf6a266 849 plugin_runLoop = CFRunLoopGetCurrent();
5958d7c0 850 CFRunLoopRun();
dbf6a266
A
851
852 SCLog(_configd_verbose, LOG_INFO, CFSTR("No more work for the \"configd\" plugins"));
853 plugin_runLoop = NULL;
5958d7c0
A
854 return NULL;
855}
856
857
009ee3c6 858__private_extern__
5958d7c0
A
859void
860plugin_init()
861{
862 pthread_attr_t tattr;
863 pthread_t tid;
864
0fae82ee 865 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Starting thread for plug-ins..."));
5958d7c0
A
866 pthread_attr_init(&tattr);
867 pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
868 pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
869// pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
870 pthread_create(&tid, &tattr, plugin_exec, NULL);
871 pthread_attr_destroy(&tattr);
0fae82ee 872 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" thread id=0x%08x"), tid);
5958d7c0
A
873
874 return;
875}