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