]> git.saurik.com Git - apple/configd.git/blob - Plugins/PreferencesMonitor/prefsmon.c
configd-453.16.tar.gz
[apple/configd.git] / Plugins / PreferencesMonitor / prefsmon.c
1 /*
2 * Copyright (c) 2000-2008, 2010, 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * April 2, 2004 Allan Nathanson <ajn@apple.com>
28 * - use SCPreference notification APIs
29 *
30 * June 24, 2001 Allan Nathanson <ajn@apple.com>
31 * - update to public SystemConfiguration.framework APIs
32 *
33 * November 10, 2000 Allan Nathanson <ajn@apple.com>
34 * - initial revision
35 */
36
37
38 #include <TargetConditionals.h>
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43
44
45 #include <SystemConfiguration/SystemConfiguration.h>
46 #include <SystemConfiguration/SCPrivate.h>
47 #include <SystemConfiguration/SCValidation.h>
48
49
50
51
52 /* globals */
53 static SCPreferencesRef prefs = NULL;
54 static SCDynamicStoreRef store = NULL;
55
56 /* preferences "initialization" globals */
57 static CFStringRef initKey = NULL;
58 static CFRunLoopSourceRef initRls = NULL;
59
60 /* SCDynamicStore (Setup:) */
61 static CFMutableDictionaryRef currentPrefs; /* current prefs */
62 static CFMutableDictionaryRef newPrefs; /* new prefs */
63 static CFMutableArrayRef unchangedPrefsKeys; /* new prefs keys which match current */
64 static CFMutableArrayRef removedPrefsKeys; /* old prefs keys to be removed */
65
66 static Boolean rofs = FALSE;
67 static Boolean _verbose = FALSE;
68
69
70 static Boolean
71 establishNewPreferences()
72 {
73 CFBundleRef bundle;
74 SCNetworkSetRef current = NULL;
75 CFStringRef new_model;
76 Boolean ok = FALSE;
77 int sc_status = kSCStatusFailed;
78 SCNetworkSetRef set = NULL;
79 CFStringRef setName = NULL;
80 Boolean updated = FALSE;
81
82 while (TRUE) {
83 ok = SCPreferencesLock(prefs, TRUE);
84 if (ok) {
85 break;
86 }
87
88 sc_status = SCError();
89 if (sc_status == kSCStatusStale) {
90 SCPreferencesSynchronize(prefs);
91 } else {
92 SCLog(TRUE, LOG_ERR,
93 CFSTR("Could not acquire network configuration lock: %s"),
94 SCErrorString(sc_status));
95 return FALSE;
96 }
97 }
98
99 /* Ensure that the preferences has the new model */
100 new_model = _SC_hw_model();
101
102 /* Need to regenerate the new configuration for new model */
103 if (new_model != NULL) {
104 CFStringRef old_model;
105
106 old_model = SCPreferencesGetValue(prefs, MODEL);
107 if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
108 CFIndex count;
109 CFIndex index;
110 CFArrayRef keys;
111
112 keys = SCPreferencesCopyKeyList(prefs);
113 count = (keys != NULL) ? CFArrayGetCount(keys) : 0;
114 // if new hardware
115 for (index = 0; index < count; index++) {
116 CFStringRef existing_key;
117
118 existing_key = CFArrayGetValueAtIndex(keys, index);
119
120 if (isA_CFString(existing_key) != NULL) {
121 CFStringRef new_key;
122 CFPropertyListRef value;
123
124 /* If it already contains a Model
125 or if it already contains a MODEL:KEY key skip it*/
126 if (CFEqual(existing_key, MODEL)
127 || CFStringFind(existing_key, CFSTR(":"), 0).location
128 != kCFNotFound) {
129 continue;
130 }
131
132 value = SCPreferencesGetValue(prefs, existing_key);
133
134 /* Create a new key as OLD_MODEL:OLD_KEY */
135 new_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"),
136 old_model, existing_key);
137 SCPreferencesSetValue(prefs, new_key, value);
138 SCPreferencesRemoveValue(prefs, existing_key);
139 CFRelease(new_key);
140 }
141 }
142
143 if (keys != NULL) {
144 CFRelease(keys);
145 }
146 }
147
148 /* Set the new model */
149 SCPreferencesSetValue(prefs, MODEL, new_model);
150 }
151
152 current = SCNetworkSetCopyCurrent(prefs);
153 if (current != NULL) {
154 set = current;
155 }
156
157 if (set == NULL) {
158 set = SCNetworkSetCreate(prefs);
159 if (set == NULL) {
160 ok = FALSE;
161 sc_status = SCError();
162 goto done;
163 }
164
165 bundle = _SC_CFBundleGet();
166 if (bundle != NULL) {
167 setName = CFBundleCopyLocalizedString(bundle,
168 CFSTR("DEFAULT_SET_NAME"),
169 CFSTR("Automatic"),
170 NULL);
171 }
172
173 ok = SCNetworkSetSetName(set, (setName != NULL) ? setName : CFSTR("Automatic"));
174 if (!ok) {
175 sc_status = SCError();
176 goto done;
177 }
178
179 ok = SCNetworkSetSetCurrent(set);
180 if (!ok) {
181 sc_status = SCError();
182 goto done;
183 }
184 }
185
186 ok = SCNetworkSetEstablishDefaultConfiguration(set);
187 if (!ok) {
188 sc_status = SCError();
189 goto done;
190 }
191
192 done :
193
194 if (ok) {
195 ok = SCPreferencesCommitChanges(prefs);
196 if (ok) {
197 SCLog(TRUE, LOG_NOTICE, CFSTR("New network configuration saved"));
198 updated = TRUE;
199 } else {
200 sc_status = SCError();
201 if (sc_status == EROFS) {
202 /* a read-only fileysstem is OK */
203 ok = TRUE;
204
205 /* ... but we don't want to synchronize */
206 rofs = TRUE;
207 }
208 }
209
210 /* apply (committed or temporary/read-only) changes */
211 (void) SCPreferencesApplyChanges(prefs);
212 } else if ((current == NULL) && (set != NULL)) {
213 (void) SCNetworkSetRemove(set);
214 }
215
216 if (!ok) {
217 SCLog(TRUE, LOG_ERR,
218 CFSTR("Could not establish network configuration: %s"),
219 SCErrorString(sc_status));
220 }
221
222 (void)SCPreferencesUnlock(prefs);
223 if (setName != NULL) CFRelease(setName);
224 if (set != NULL) CFRelease(set);
225 return updated;
226 }
227
228
229 static Boolean
230 quiet(Boolean *timeout)
231 {
232 CFDictionaryRef dict;
233 Boolean _quiet = FALSE;
234 Boolean _timeout = FALSE;
235
236 // check if quiet
237 dict = SCDynamicStoreCopyValue(store, initKey);
238 if (dict != NULL) {
239 if (isA_CFDictionary(dict)) {
240 if (CFDictionaryContainsKey(dict, CFSTR("*QUIET*"))) {
241 _quiet = TRUE;
242 }
243 if (CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*"))) {
244 _timeout = TRUE;
245 }
246 }
247 CFRelease(dict);
248 }
249
250 if (timeout != NULL) {
251 *timeout = _timeout;
252 }
253 return _quiet;
254 }
255
256
257 static void
258 watchQuietDisable()
259 {
260 if ((initKey == NULL) || (initRls == NULL)) {
261 return;
262 }
263
264 (void) SCDynamicStoreSetNotificationKeys(store, NULL, NULL);
265
266 CFRunLoopSourceInvalidate(initRls);
267 CFRelease(initRls);
268 initRls = NULL;
269
270 CFRelease(initKey);
271 initKey = NULL;
272
273 return;
274 }
275
276
277 static void
278 watchQuietEnable()
279 {
280 CFArrayRef keys;
281 Boolean ok;
282
283 initKey = SCDynamicStoreKeyCreate(NULL,
284 CFSTR("%@" "InterfaceNamer"),
285 kSCDynamicStoreDomainPlugin);
286
287 initRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
288 CFRunLoopAddSource(CFRunLoopGetCurrent(), initRls, kCFRunLoopDefaultMode);
289
290 keys = CFArrayCreate(NULL, (const void **)&initKey, 1, &kCFTypeArrayCallBacks);
291 ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
292 CFRelease(keys);
293 if (!ok) {
294 SCLog(TRUE, LOG_ERR,
295 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
296 watchQuietDisable();
297 }
298
299 return;
300 }
301
302 static void
303 watchQuietCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
304 {
305 Boolean _quiet;
306 Boolean _timeout = FALSE;
307
308 _quiet = quiet(&_timeout);
309 if (_quiet
310 #if !TARGET_OS_IPHONE
311 || _timeout
312 #endif /* !TARGET_OS_IPHONE */
313 ) {
314 watchQuietDisable();
315 }
316
317 if (_quiet || _timeout) {
318 static int logged = 0;
319
320 (void) establishNewPreferences();
321 if (_timeout && (logged++ == 0)) {
322 SCLog(TRUE, LOG_NOTICE,
323 CFSTR("Network configuration creation timed out waiting for IORegistry"));
324 }
325 }
326
327 return;
328 }
329
330
331 static void
332 updateCache(const void *key, const void *value, void *context)
333 {
334 CFStringRef configKey = (CFStringRef)key;
335 CFPropertyListRef configData = (CFPropertyListRef)value;
336 CFPropertyListRef cacheData;
337 CFIndex i;
338
339 cacheData = CFDictionaryGetValue(currentPrefs, configKey);
340 if (cacheData) {
341 /* key exists */
342 if (CFEqual(cacheData, configData)) {
343 /*
344 * if the old & new property list values have
345 * not changed then we don't need to update
346 * the preference.
347 */
348 CFArrayAppendValue(unchangedPrefsKeys, configKey);
349 }
350 }
351
352 /* in any case, this key should not be removed */
353 i = CFArrayGetFirstIndexOfValue(removedPrefsKeys,
354 CFRangeMake(0, CFArrayGetCount(removedPrefsKeys)),
355 configKey);
356 if (i != kCFNotFound) {
357 CFArrayRemoveValueAtIndex(removedPrefsKeys, i);
358 }
359
360 return;
361 }
362
363
364 static void
365 flatten(SCPreferencesRef prefs,
366 CFStringRef key,
367 CFDictionaryRef base)
368 {
369 CFDictionaryRef subset;
370 CFStringRef link;
371 CFMutableDictionaryRef myDict;
372 CFStringRef myKey;
373 CFIndex i;
374 CFIndex nKeys;
375 const void **keys;
376 const void **vals;
377
378 if (!CFDictionaryGetValueIfPresent(base, kSCResvLink, (const void **)&link)) {
379 /* if this dictionary is not linked */
380 subset = base;
381 } else {
382 /* if __LINK__ key is present */
383 subset = SCPreferencesPathGetValue(prefs, link);
384 if (!subset) {
385 /* if error with link */
386 SCLog(TRUE, LOG_ERR,
387 CFSTR("SCPreferencesPathGetValue(,%@,) failed: %s"),
388 link,
389 SCErrorString(SCError()));
390 return;
391 }
392 }
393
394 if (CFDictionaryContainsKey(subset, kSCResvInactive)) {
395 /* if __INACTIVE__ key is present */
396 return;
397 }
398
399 myKey = CFStringCreateWithFormat(NULL,
400 NULL,
401 CFSTR("%@%@"),
402 kSCDynamicStoreDomainSetup,
403 key);
404
405 myDict = (CFMutableDictionaryRef)CFDictionaryGetValue(newPrefs, myKey);
406 if (myDict) {
407 myDict = CFDictionaryCreateMutableCopy(NULL,
408 0,
409 (CFDictionaryRef)myDict);
410 } else {
411 myDict = CFDictionaryCreateMutable(NULL,
412 0,
413 &kCFTypeDictionaryKeyCallBacks,
414 &kCFTypeDictionaryValueCallBacks);
415 }
416
417 nKeys = CFDictionaryGetCount(subset);
418 if (nKeys > 0) {
419 keys = CFAllocatorAllocate(NULL, nKeys * sizeof(CFStringRef) , 0);
420 vals = CFAllocatorAllocate(NULL, nKeys * sizeof(CFPropertyListRef), 0);
421 CFDictionaryGetKeysAndValues(subset, keys, vals);
422 for (i = 0; i < nKeys; i++) {
423 if (CFGetTypeID((CFTypeRef)vals[i]) != CFDictionaryGetTypeID()) {
424 /* add this key/value to the current dictionary */
425 CFDictionarySetValue(myDict, keys[i], vals[i]);
426 } else {
427 CFStringRef subKey;
428
429 /* flatten [sub]dictionaries */
430 subKey = CFStringCreateWithFormat(NULL,
431 NULL,
432 CFSTR("%@%s%@"),
433 key,
434 CFEqual(key, CFSTR("/")) ? "" : "/",
435 keys[i]);
436 flatten(prefs, subKey, vals[i]);
437 CFRelease(subKey);
438 }
439 }
440 CFAllocatorDeallocate(NULL, keys);
441 CFAllocatorDeallocate(NULL, vals);
442 }
443
444 if (CFDictionaryGetCount(myDict) > 0) {
445 /* add this dictionary to the new preferences */
446 CFDictionarySetValue(newPrefs, myKey, myDict);
447 }
448
449 CFRelease(myDict);
450 CFRelease(myKey);
451
452 return;
453 }
454
455
456 static void
457 updateSCDynamicStore(SCPreferencesRef prefs)
458 {
459 CFStringRef current = NULL;
460 CFDateRef date = NULL;
461 CFMutableDictionaryRef dict = NULL;
462 CFDictionaryRef global = NULL;
463 CFIndex i;
464 CFArrayRef keys;
465 CFIndex n;
466 CFStringRef pattern;
467 CFMutableArrayRef patterns;
468 CFDictionaryRef set = NULL;
469
470 /*
471 * initialize old preferences, new preferences, an array
472 * of keys which have not changed, and an array of keys
473 * to be removed (cleaned up).
474 */
475
476 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
477 pattern = CFStringCreateWithFormat(NULL,
478 NULL,
479 CFSTR("^%@.*"),
480 kSCDynamicStoreDomainSetup);
481 CFArrayAppendValue(patterns, pattern);
482 dict = (CFMutableDictionaryRef)SCDynamicStoreCopyMultiple(store, NULL, patterns);
483 CFRelease(patterns);
484 CFRelease(pattern);
485 if (dict) {
486 currentPrefs = CFDictionaryCreateMutableCopy(NULL, 0, dict);
487 CFRelease(dict);
488 } else {
489 currentPrefs = CFDictionaryCreateMutable(NULL,
490 0,
491 &kCFTypeDictionaryKeyCallBacks,
492 &kCFTypeDictionaryValueCallBacks);
493 }
494
495 unchangedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
496
497 i = CFDictionaryGetCount(currentPrefs);
498 if (i > 0) {
499 const void **currentKeys;
500 CFArrayRef array;
501
502 currentKeys = CFAllocatorAllocate(NULL, i * sizeof(CFStringRef), 0);
503 CFDictionaryGetKeysAndValues(currentPrefs, currentKeys, NULL);
504 array = CFArrayCreate(NULL, currentKeys, i, &kCFTypeArrayCallBacks);
505 removedPrefsKeys = CFArrayCreateMutableCopy(NULL, 0, array);
506 CFRelease(array);
507 CFAllocatorDeallocate(NULL, currentKeys);
508 } else {
509 removedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
510 }
511
512 /*
513 * The "newPrefs" dictionary will contain the new / updated
514 * configuration which will be written to the configuration cache.
515 */
516 newPrefs = CFDictionaryCreateMutable(NULL,
517 0,
518 &kCFTypeDictionaryKeyCallBacks,
519 &kCFTypeDictionaryValueCallBacks);
520
521 /*
522 * create status dictionary associated with current configuration
523 * information including:
524 * - current set "name" to cache
525 * - time stamp indicating when the cache preferences were
526 * last updated.
527 */
528 dict = CFDictionaryCreateMutable(NULL,
529 0,
530 &kCFTypeDictionaryKeyCallBacks,
531 &kCFTypeDictionaryValueCallBacks);
532 date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
533
534 /*
535 * load preferences
536 */
537 keys = SCPreferencesCopyKeyList(prefs);
538 if ((keys == NULL) || (CFArrayGetCount(keys) == 0)) {
539 SCLog(TRUE, LOG_NOTICE, CFSTR("updateConfiguration(): no preferences."));
540 goto done;
541 }
542
543 /*
544 * get "global" system preferences
545 */
546 global = SCPreferencesGetValue(prefs, kSCPrefSystem);
547 if (!global) {
548 /* if no global preferences are defined */
549 goto getSet;
550 }
551
552 if (!isA_CFDictionary(global)) {
553 SCLog(TRUE, LOG_ERR,
554 CFSTR("updateConfiguration(): %@ is not a dictionary."),
555 kSCPrefSystem);
556 goto done;
557 }
558
559 /* flatten property list */
560 flatten(prefs, CFSTR("/"), global);
561
562 getSet :
563
564 /*
565 * get current set name
566 */
567 current = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
568 if (!current) {
569 /* if current set not defined */
570 goto done;
571 }
572
573 if (!isA_CFString(current)) {
574 SCLog(TRUE, LOG_ERR,
575 CFSTR("updateConfiguration(): %@ is not a string."),
576 kSCPrefCurrentSet);
577 goto done;
578 }
579
580 /*
581 * get current set
582 */
583 set = SCPreferencesPathGetValue(prefs, current);
584 if (!set) {
585 /* if error with path */
586 SCLog(TRUE, LOG_ERR,
587 CFSTR("%@ value (%@) not valid"),
588 kSCPrefCurrentSet,
589 current);
590 goto done;
591 }
592
593 if (!isA_CFDictionary(set)) {
594 SCLog(TRUE, LOG_ERR,
595 CFSTR("updateConfiguration(): %@ is not a dictionary."),
596 current);
597 goto done;
598 }
599
600 /* flatten property list */
601 flatten(prefs, CFSTR("/"), set);
602
603 CFDictionarySetValue(dict, kSCDynamicStorePropSetupCurrentSet, current);
604
605 done :
606
607 /* add last updated time stamp */
608 CFDictionarySetValue(dict, kSCDynamicStorePropSetupLastUpdated, date);
609
610 /* add Setup: key */
611 CFDictionarySetValue(newPrefs, kSCDynamicStoreDomainSetup, dict);
612
613 /* compare current and new preferences */
614 CFDictionaryApplyFunction(newPrefs, updateCache, NULL);
615
616 /* remove those keys which have not changed from the update */
617 n = CFArrayGetCount(unchangedPrefsKeys);
618 for (i = 0; i < n; i++) {
619 CFStringRef key;
620
621 key = CFArrayGetValueAtIndex(unchangedPrefsKeys, i);
622 CFDictionaryRemoveValue(newPrefs, key);
623 }
624
625 /* Update the dynamic store */
626 #ifndef MAIN
627 if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
628 SCLog(TRUE, LOG_ERR,
629 CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
630 SCErrorString(SCError()));
631 }
632 #else // !MAIN
633 SCLog(TRUE, LOG_NOTICE,
634 CFSTR("SCDynamicStore\nset: %@\nremove: %@\n"),
635 newPrefs,
636 removedPrefsKeys);
637 #endif // !MAIN
638
639 CFRelease(currentPrefs);
640 CFRelease(newPrefs);
641 CFRelease(unchangedPrefsKeys);
642 CFRelease(removedPrefsKeys);
643 if (dict) CFRelease(dict);
644 if (date) CFRelease(date);
645 if (keys) CFRelease(keys);
646 return;
647 }
648
649
650 static void
651 updateConfiguration(SCPreferencesRef prefs,
652 SCPreferencesNotification notificationType,
653 void *info)
654 {
655
656
657 #if !TARGET_OS_IPHONE
658 if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
659 SCNetworkSetRef current;
660
661 current = SCNetworkSetCopyCurrent(prefs);
662 if (current != NULL) {
663 /* network configuration available, disable template creation */
664 watchQuietDisable();
665 CFRelease(current);
666 }
667 }
668 #endif /* !TARGET_OS_IPHONE */
669
670 if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
671 return;
672 }
673
674 SCLog(_verbose, LOG_DEBUG, CFSTR("updating configuration"));
675
676 /* update SCDynamicStore (Setup:) */
677 updateSCDynamicStore(prefs);
678
679 /* finished with current prefs, wait for changes */
680 if (!rofs) {
681 SCPreferencesSynchronize(prefs);
682 }
683
684 return;
685 }
686
687
688 __private_extern__
689 void
690 prime_PreferencesMonitor()
691 {
692 SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
693
694 /* load the initial configuration from the database */
695 updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
696
697 return;
698 }
699
700
701 __private_extern__
702 void
703 load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
704 {
705 Boolean initPrefs = TRUE;
706
707 if (bundleVerbose) {
708 _verbose = TRUE;
709 }
710
711 SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
712 SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
713
714 /* open a SCDynamicStore session to allow cache updates */
715 store = SCDynamicStoreCreate(NULL,
716 CFSTR("PreferencesMonitor.bundle"),
717 watchQuietCallback,
718 NULL);
719 if (store == NULL) {
720 SCLog(TRUE, LOG_ERR,
721 CFSTR("SCDynamicStoreCreate() failed: %s"),
722 SCErrorString(SCError()));
723 goto error;
724 }
725
726 /* open a SCPreferences session */
727 #ifndef MAIN
728 prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
729 #else // !MAIN
730 prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
731 #endif // !MAIN
732 if (prefs != NULL) {
733 Boolean need_update = FALSE;
734 CFStringRef new_model;
735
736 new_model = _SC_hw_model();
737
738 /* Need to regenerate the new configuration for new model */
739 if (new_model != NULL) {
740 CFStringRef old_model;
741
742 old_model = SCPreferencesGetValue(prefs, MODEL);
743 if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) {
744 // if new hardware
745 need_update = TRUE;
746 }
747 }
748
749 if (need_update == FALSE) {
750 SCNetworkSetRef current;
751
752 current = SCNetworkSetCopyCurrent(prefs);
753 if (current != NULL) {
754 /* network configuration available, disable template creation */
755 initPrefs = FALSE;
756 CFRelease(current);
757 }
758 }
759 } else {
760 SCLog(TRUE, LOG_ERR,
761 CFSTR("SCPreferencesCreate() failed: %s"),
762 SCErrorString(SCError()));
763 goto error;
764 }
765
766 /*
767 * register for change notifications.
768 */
769 if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
770 SCLog(TRUE, LOG_ERR,
771 CFSTR("SCPreferencesSetCallBack() failed: %s"),
772 SCErrorString(SCError()));
773 goto error;
774 }
775
776 if (!SCPreferencesScheduleWithRunLoop(prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
777 SCLog(TRUE, LOG_ERR,
778 CFSTR("SCPreferencesScheduleWithRunLoop() failed: %s"),
779 SCErrorString(SCError()));
780 goto error;
781 }
782
783 /*
784 * if no preferences, initialize with a template (now or
785 * when IOKit has quiesced).
786 */
787 if (initPrefs) {
788 watchQuietEnable();
789 watchQuietCallback(store, NULL, NULL);
790 }
791
792 return;
793
794 error :
795
796 watchQuietDisable();
797 if (store != NULL) CFRelease(store);
798 if (prefs != NULL) CFRelease(prefs);
799
800 return;
801 }
802
803
804 #ifdef MAIN
805 int
806 main(int argc, char **argv)
807 {
808 _sc_log = FALSE;
809 _sc_verbose = (argc > 1) ? TRUE : FALSE;
810
811 load_PreferencesMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
812 prime_PreferencesMonitor();
813 CFRunLoopRun();
814 /* not reached */
815 exit(0);
816 return 0;
817 }
818 #endif