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