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 */ 53static SCPreferencesRef prefs = NULL; 54static SCDynamicStoreRef store = NULL; 55 56/* preferences "initialization" globals */ 57static CFStringRef initKey = NULL; 58static CFRunLoopSourceRef initRls = NULL; 59 60/* SCDynamicStore (Setup:) */ 61static CFMutableDictionaryRef currentPrefs; /* current prefs */ 62static CFMutableDictionaryRef newPrefs; /* new prefs */ 63static CFMutableArrayRef unchangedPrefsKeys; /* new prefs keys which match current */ 64static CFMutableArrayRef removedPrefsKeys; /* old prefs keys to be removed */ 65 66static Boolean rofs = FALSE; 67static Boolean _verbose = FALSE; 68 69 70static Boolean 71establishNewPreferences() 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 232static Boolean 233quiet(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 260static void 261watchQuietDisable() 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 280static void 281watchQuietEnable() 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 308static void 309watchQuietCallback(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 337static void 338updateCache(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 370static void 371flatten(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 462static void 463updateSCDynamicStore(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 656static void 657updateConfiguration(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__ 695void 696prime_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__ 708void 709load_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 811int 812main(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 825