]> git.saurik.com Git - apple/configd.git/blobdiff - Plugins/PreferencesMonitor/prefsmon.c
configd-802.20.7.tar.gz
[apple/configd.git] / Plugins / PreferencesMonitor / prefsmon.c
index c96145789328e76846c8cd96819cee3af814458b..5727a6789f830b52d36c602fb3763a96f362a716 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2008, 2010, 2012-2015 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -17,7 +17,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -35,6 +35,7 @@
  */
 
 
+#include <TargetConditionals.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
 
 
+/* globals */
 static SCPreferencesRef                prefs           = NULL;
 static SCDynamicStoreRef       store           = NULL;
 
+/* preferences "initialization" globals */
+static CFStringRef             initKey         = NULL;
+static CFRunLoopSourceRef      initRls         = NULL;
+
+/* SCDynamicStore (Setup:) */
 static CFMutableDictionaryRef  currentPrefs;           /* current prefs */
 static CFMutableDictionaryRef  newPrefs;               /* new prefs */
 static CFMutableArrayRef       unchangedPrefsKeys;     /* new prefs keys which match current */
 static CFMutableArrayRef       removedPrefsKeys;       /* old prefs keys to be removed */
 
-static Boolean                 _verbose        = FALSE;
+static Boolean                 rofs            = FALSE;
+static Boolean                 restorePrefs    = FALSE;
+
+#define MY_PLUGIN_NAME                 "PreferencesMonitor"
+#define        MY_PLUGIN_ID                    CFSTR("com.apple.SystemConfiguration." MY_PLUGIN_NAME)
+
+static Boolean
+restorePreferences()
+{
+       Boolean                 ok = FALSE;
+       CFStringRef             currentModel = NULL;
+       CFMutableStringRef      modelPrefixStr = NULL;
+       CFArrayRef              keyList = NULL;
+       CFIndex                 keyListCount;
+       CFIndex                 idx;
+       Boolean                 modified = FALSE;
+       int                     sc_status = kSCStatusFailed;
+
+       while (TRUE) {
+               ok = SCPreferencesLock(prefs, TRUE);
+               if (ok) {
+                       break;
+               }
+
+               sc_status = SCError();
+               if (sc_status == kSCStatusStale) {
+                       SCPreferencesSynchronize(prefs);
+               } else {
+                       SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s",
+                              SCErrorString(sc_status));
+                       return FALSE;
+               }
+       }
+
+       keyList = SCPreferencesCopyKeyList(prefs);
+       if (keyList == NULL) {
+               goto error;
+       }
+
+       currentModel = _SC_hw_model(FALSE);
+       if (currentModel == NULL) {
+               goto error;
+       }
+
+       /* Create "model:" string for prefix-check */
+       modelPrefixStr = CFStringCreateMutableCopy(NULL, 0, currentModel);
+       CFStringAppend(modelPrefixStr, CFSTR(":"));
+
+       keyListCount = CFArrayGetCount(keyList);
+       for (idx = 0; idx < keyListCount; idx++) {
+               CFStringRef existingKey = CFArrayGetValueAtIndex(keyList, idx);
+               CFStringRef key;
+               CFArrayRef splitKey = NULL;
+               CFPropertyListRef value;
+
+               if (isA_CFString(existingKey) == NULL) {
+                       continue;
+               }
+
+               if (CFStringHasPrefix(existingKey, modelPrefixStr) == FALSE) {
+                           continue;
+               }
+
+               splitKey = CFStringCreateArrayBySeparatingStrings(NULL, existingKey, CFSTR(":"));
+               key = CFArrayGetValueAtIndex(splitKey, 1);
+               value = SCPreferencesGetValue(prefs, existingKey);
+               SCPreferencesSetValue(prefs, key, value);
+               SCPreferencesRemoveValue(prefs, existingKey);
+               modified = TRUE;
+               CFRelease(splitKey);
+       }
+
+       if (modified == TRUE) {
+               SCPreferencesRef        ni_prefs = NULL;
+               ni_prefs = SCPreferencesCreate(NULL, MY_PLUGIN_ID, CFSTR("NetworkInterfaces.plist"));
+               if (ni_prefs == NULL) {
+                       goto error;
+               }
+
+               ok = _SCNetworkConfigurationCheckValidityWithPreferences(prefs, ni_prefs, NULL);
+               CFRelease(ni_prefs);
+
+               //Commit the changes only if prefs files valid
+               if (ok == TRUE) {
+                       if (!SCPreferencesCommitChanges(prefs)) {
+                               if (SCError() != EROFS) {
+                                       SC_log(LOG_NOTICE, "SCPreferencesCommitChanges() failed: %s",
+                                              SCErrorString(SCError()));
+                               }
+                               goto error;
+
+                       }
+
+                       (void) SCPreferencesApplyChanges(prefs);
+               }
+       }
+
+error:
+       (void) SCPreferencesUnlock(prefs);
+
+       if (keyList != NULL) {
+               CFRelease(keyList);
+       }
+       if (modelPrefixStr != NULL) {
+               CFRelease(modelPrefixStr);
+       }
+
+       return modified;
+}
+
+static Boolean
+establishNewPreferences()
+{
+       CFBundleRef     bundle;
+       SCNetworkSetRef current         = NULL;
+       CFStringRef     new_model;
+       Boolean         ok              = FALSE;
+       int             sc_status       = kSCStatusFailed;
+       SCNetworkSetRef set             = NULL;
+       CFStringRef     setName         = NULL;
+       Boolean         updated         = FALSE;
+
+       while (TRUE) {
+               ok = SCPreferencesLock(prefs, TRUE);
+               if (ok) {
+                       break;
+               }
+
+               sc_status = SCError();
+               if (sc_status == kSCStatusStale) {
+                       SCPreferencesSynchronize(prefs);
+               } else {
+                       SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s",
+                              SCErrorString(sc_status));
+                       return FALSE;
+               }
+       }
+
+       /* Ensure that the preferences has the new model */
+       new_model = _SC_hw_model(FALSE);
+
+       /* Need to regenerate the new configuration for new model */
+       if (new_model != NULL) {
+               CFStringRef     old_model;
+
+               old_model = SCPreferencesGetValue(prefs, MODEL);
+               if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
+                       CFIndex         count;
+                       CFIndex         index;
+                       CFArrayRef      keys;
+
+                       keys = SCPreferencesCopyKeyList(prefs);
+                       count = (keys != NULL) ? CFArrayGetCount(keys) : 0;
+                       // if new hardware
+                       for (index = 0; index < count; index++) {
+                               CFStringRef             existing_key;
+
+                               existing_key = CFArrayGetValueAtIndex(keys, index);
+                               if (isA_CFString(existing_key) != NULL) {
+                                       CFStringRef             new_key;
+                                       CFPropertyListRef       value;
+
+                                       /* If it already contains a Model
+                                          or if it already contains a MODEL:KEY key skip it*/
+                                       if (CFEqual(existing_key, MODEL)
+                                           || CFStringFind(existing_key, CFSTR(":"), 0).location
+                                           != kCFNotFound) {
+                                               continue;
+                                       }
+
+                                       value = SCPreferencesGetValue(prefs, existing_key);
+
+                                       /* Create a new key as OLD_MODEL:OLD_KEY */
+                                       new_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"),
+                                                                          old_model, existing_key);
+                                       SCPreferencesSetValue(prefs, new_key, value);
+                                       if (!CFEqual(existing_key, kSCPrefSystem)) {
+                                               /* preserve existing host names */
+                                               SCPreferencesRemoveValue(prefs, existing_key);
+                                       }
+                                       CFRelease(new_key);
+                               }
+                       }
+
+                       if (keys != NULL) {
+                               CFRelease(keys);
+                       }
+               }
+               /* Set the new model */
+               SCPreferencesSetValue(prefs, MODEL, new_model);
+       }
+
+       current = SCNetworkSetCopyCurrent(prefs);
+       if (current != NULL) {
+               set = current;
+       }
+
+       if (set == NULL) {
+               set = SCNetworkSetCreate(prefs);
+               if (set == NULL) {
+                       ok = FALSE;
+                       sc_status = SCError();
+                       goto done;
+               }
+
+               bundle = _SC_CFBundleGet();
+               if (bundle != NULL) {
+                       setName = CFBundleCopyLocalizedString(bundle,
+                                                             CFSTR("DEFAULT_SET_NAME"),
+                                                             CFSTR("Automatic"),
+                                                             NULL);
+               }
+
+               ok = SCNetworkSetSetName(set, (setName != NULL) ? setName : CFSTR("Automatic"));
+               if (!ok) {
+                       sc_status = SCError();
+                       goto done;
+               }
+
+               ok = SCNetworkSetSetCurrent(set);
+               if (!ok) {
+                       sc_status = SCError();
+                       goto done;
+               }
+       }
+
+       ok = SCNetworkSetEstablishDefaultConfiguration(set);
+       if (!ok) {
+               sc_status = SCError();
+               goto done;
+       }
+
+    done :
+
+       if (ok) {
+               ok = SCPreferencesCommitChanges(prefs);
+               if (ok) {
+                       SC_log(LOG_NOTICE, "New network configuration saved");
+                       updated = TRUE;
+               } else {
+                       sc_status = SCError();
+                       if (sc_status == EROFS) {
+                               /* a read-only fileysstem is OK */
+                               ok = TRUE;
+
+                               /* ... but we don't want to synchronize */
+                               rofs = TRUE;
+                       }
+               }
+
+               /* apply (committed or temporary/read-only) changes */
+               (void) SCPreferencesApplyChanges(prefs);
+       } else if ((current == NULL) && (set != NULL)) {
+               (void) SCNetworkSetRemove(set);
+       }
+
+       if (!ok) {
+               SC_log(LOG_NOTICE, "Could not establish network configuration: %s",
+                      SCErrorString(sc_status));
+       }
+
+       (void)SCPreferencesUnlock(prefs);
+       if (setName != NULL) CFRelease(setName);
+       if (set != NULL) CFRelease(set);
+       return updated;
+}
+
+
+static Boolean
+quiet(Boolean *timeout)
+{
+       CFDictionaryRef dict;
+       Boolean         _quiet          = FALSE;
+       Boolean         _timeout        = FALSE;
+
+       // check if quiet
+       dict = SCDynamicStoreCopyValue(store, initKey);
+       if (dict != NULL) {
+               if (isA_CFDictionary(dict)) {
+                       if (CFDictionaryContainsKey(dict, CFSTR("*QUIET*"))) {
+                               _quiet = TRUE;
+                       }
+                       if (CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*"))) {
+                               _timeout = TRUE;
+                       }
+               }
+               CFRelease(dict);
+       }
+
+       if (timeout != NULL) {
+               *timeout = _timeout;
+       }
+       return _quiet;
+}
+
+
+static void
+watchQuietDisable()
+{
+       if ((initKey == NULL) || (initRls == NULL)) {
+               return;
+       }
+
+       (void) SCDynamicStoreSetNotificationKeys(store, NULL, NULL);
+
+       CFRunLoopSourceInvalidate(initRls);
+       CFRelease(initRls);
+       initRls = NULL;
+
+       CFRelease(initKey);
+       initKey = NULL;
+
+       return;
+}
+
+
+static void
+watchQuietEnable()
+{
+       CFArrayRef      keys;
+       Boolean         ok;
+
+       initKey = SCDynamicStoreKeyCreate(NULL,
+                                         CFSTR("%@" "InterfaceNamer"),
+                                         kSCDynamicStoreDomainPlugin);
+
+       initRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), initRls, kCFRunLoopDefaultMode);
+
+       keys = CFArrayCreate(NULL, (const void **)&initKey, 1, &kCFTypeArrayCallBacks);
+       ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
+       CFRelease(keys);
+       if (!ok) {
+               SC_log(LOG_NOTICE, "SCDynamicStoreSetNotificationKeys() failed: %s", SCErrorString(SCError()));
+               watchQuietDisable();
+       }
+
+       return;
+}
+
+
+
+static Boolean
+previousConfigurationAvailable()
+{
+       CFStringRef             backupKey = NULL;
+       CFStringRef             currentModel = NULL;
+       CFPropertyListRef       properties = NULL;
+
+       currentModel = _SC_hw_model(FALSE);
+       if (currentModel == NULL) {
+               goto done;
+       }
+
+       /* Currently relying only if a backup of "Sets" is present */
+       backupKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:Sets"), currentModel);
+       properties = SCPreferencesGetValue(prefs, backupKey);
+       CFRelease(backupKey);
+done:
+       return (properties != NULL);
+}
+
+static void
+watchQuietCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
+{
+       Boolean _quiet;
+       Boolean _timeout        = FALSE;
+
+       _quiet = quiet(&_timeout);
+       if (_quiet
+#if    !TARGET_OS_IPHONE
+           || _timeout
+#endif /* !TARGET_OS_IPHONE */
+          ) {
+               watchQuietDisable();
+       }
+
+       if (_quiet || _timeout) {
+               static int      logged  = 0;
+
+               (void) establishNewPreferences();
+
+               if (restorePrefs == TRUE) {
+                       (void) restorePreferences();
+                       restorePrefs = FALSE;
+               }
+
+               if (_timeout && (logged++ == 0)) {
+                       SC_log(LOG_ERR, "Network configuration creation timed out waiting for IORegistry");
+               }
+       }
+
+       return;
+}
 
 
 static void
@@ -114,10 +514,9 @@ flatten(SCPreferencesRef   prefs,
                subset = SCPreferencesPathGetValue(prefs, link);
                if (!subset) {
                        /* if error with link */
-                       SCLog(TRUE, LOG_ERR,
-                             CFSTR("SCPreferencesPathGetValue(,%@,) failed: %s"),
-                             link,
-                             SCErrorString(SCError()));
+                       SC_log(LOG_NOTICE, "SCPreferencesPathGetValue(,%@,) failed: %s",
+                              link,
+                              SCErrorString(SCError()));
                        return;
                }
        }
@@ -185,9 +584,7 @@ flatten(SCPreferencesRef    prefs,
 
 
 static void
-updateConfiguration(SCPreferencesRef           prefs,
-                   SCPreferencesNotification   notificationType,
-                   void                        *info)
+updateSCDynamicStore(SCPreferencesRef prefs)
 {
        CFStringRef             current         = NULL;
        CFDateRef               date            = NULL;
@@ -200,13 +597,6 @@ updateConfiguration(SCPreferencesRef               prefs,
        CFMutableArrayRef       patterns;
        CFDictionaryRef         set             = NULL;
 
-
-       if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
-               return;
-       }
-
-       SCLog(_verbose, LOG_DEBUG, CFSTR("updating configuration"));
-
        /*
         * initialize old preferences, new preferences, an array
         * of keys which have not changed, and an array of keys
@@ -276,7 +666,7 @@ updateConfiguration(SCPreferencesRef                prefs,
         */
        keys = SCPreferencesCopyKeyList(prefs);
        if ((keys == NULL) || (CFArrayGetCount(keys) == 0)) {
-               SCLog(TRUE, LOG_NOTICE, CFSTR("updateConfiguration(): no preferences."));
+               SC_log(LOG_NOTICE, "updateConfiguration(): no preferences");
                goto done;
        }
 
@@ -290,9 +680,8 @@ updateConfiguration(SCPreferencesRef                prefs,
        }
 
        if (!isA_CFDictionary(global)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("updateConfiguration(): %@ is not a dictionary."),
-                     kSCPrefSystem);
+               SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
+                      kSCPrefSystem);
                goto done;
        }
 
@@ -311,9 +700,8 @@ updateConfiguration(SCPreferencesRef                prefs,
        }
 
        if (!isA_CFString(current)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("updateConfiguration(): %@ is not a string."),
-                     kSCPrefCurrentSet);
+               SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a string",
+                      kSCPrefCurrentSet);
                goto done;
        }
 
@@ -323,17 +711,15 @@ updateConfiguration(SCPreferencesRef              prefs,
        set = SCPreferencesPathGetValue(prefs, current);
        if (!set) {
                /* if error with path */
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("%@ value (%@) not valid"),
-                     kSCPrefCurrentSet,
-                     current);
+               SC_log(LOG_NOTICE, "%@ value (%@) not valid",
+                      kSCPrefCurrentSet,
+                      current);
                goto done;
        }
 
        if (!isA_CFDictionary(set)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("updateConfiguration(): %@ is not a dictionary."),
-                     current);
+               SC_log(LOG_NOTICE, "updateConfiguration(): %@ is not a dictionary",
+                      current);
                goto done;
        }
 
@@ -363,14 +749,15 @@ updateConfiguration(SCPreferencesRef              prefs,
        }
 
        /* Update the dynamic store */
+#ifndef MAIN
        if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCDynamicStoreSetMultiple() failed: %s", SCErrorString(SCError()));
        }
-
-       /* finished with current prefs, wait for changes */
-       SCPreferencesSynchronize(prefs);
+#else  // !MAIN
+       SC_log(LOG_DEBUG, "SCDynamicStore\nset: %@\nremove: %@",
+              newPrefs,
+              removedPrefsKeys);
+#endif // !MAIN
 
        CFRelease(currentPrefs);
        CFRelease(newPrefs);
@@ -383,30 +770,48 @@ updateConfiguration(SCPreferencesRef              prefs,
 }
 
 
-__private_extern__
-void
-stop_PreferencesMonitor(CFRunLoopSourceRef stopRls)
+static void
+updateConfiguration(SCPreferencesRef           prefs,
+                   SCPreferencesNotification   notificationType,
+                   void                        *info)
 {
-       // cleanup
+       os_activity_t           activity_id;
 
-       if (prefs != NULL) {
-               if (!SCPreferencesUnscheduleFromRunLoop(prefs,
-                                                       CFRunLoopGetCurrent(),
-                                                       kCFRunLoopDefaultMode)) {
-                       SCLog(TRUE, LOG_ERR,
-                             CFSTR("SCPreferencesUnscheduleFromRunLoop() failed: %s"),
-                             SCErrorString(SCError()));
+
+       activity_id = os_activity_start("processing [SC] preferences.plist changes",
+                                       OS_ACTIVITY_FLAG_DEFAULT);
+
+#if    !TARGET_OS_IPHONE
+       if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
+               SCNetworkSetRef current;
+
+               current = SCNetworkSetCopyCurrent(prefs);
+               if (current != NULL) {
+                       /* network configuration available, disable template creation */
+                       watchQuietDisable();
+                       CFRelease(current);
                }
-               CFRelease(prefs);
-               prefs = NULL;
        }
+#endif /* !TARGET_OS_IPHONE */
 
-       if (store != NULL) {
-               CFRelease(store);
-               store = NULL;
+       if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
+               goto done;
        }
 
-       CFRunLoopSourceSignal(stopRls);
+       SC_log(LOG_INFO, "updating configuration");
+
+       /* update SCDynamicStore (Setup:) */
+       updateSCDynamicStore(prefs);
+
+       /* finished with current prefs, wait for changes */
+       if (!rofs) {
+               SCPreferencesSynchronize(prefs);
+       }
+
+    done :
+
+       os_activity_end(activity_id);
+
        return;
 }
 
@@ -415,7 +820,7 @@ __private_extern__
 void
 prime_PreferencesMonitor()
 {
-       SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
+       SC_log(LOG_DEBUG, "prime() called");
 
        /* load the initial configuration from the database */
        updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
@@ -428,54 +833,89 @@ __private_extern__
 void
 load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
 {
-       if (bundleVerbose) {
-               _verbose = TRUE;
-       }
+       Boolean initPrefs       = TRUE;
 
-       SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
-       SCLog(_verbose, LOG_DEBUG, CFSTR("  bundle ID = %@"), CFBundleGetIdentifier(bundle));
+       SC_log(LOG_DEBUG, "load() called");
+       SC_log(LOG_DEBUG, "  bundle ID = %@", CFBundleGetIdentifier(bundle));
 
        /* open a SCDynamicStore session to allow cache updates */
-       store = SCDynamicStoreCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL, NULL);
+       store = SCDynamicStoreCreate(NULL,
+                                    CFSTR("PreferencesMonitor.bundle"),
+                                    watchQuietCallback,
+                                    NULL);
        if (store == NULL) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCDynamicStoreCreate() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
                goto error;
        }
 
        /* open a SCPreferences session */
+#ifndef        MAIN
        prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
-       if (prefs == NULL) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCPreferencesCreate() failed: %s"),
-                     SCErrorString(SCError()));
-               goto error;
-       }
+#else  // !MAIN
+       prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
+#endif // !MAIN
+       if (prefs != NULL) {
+               Boolean         need_update = FALSE;
+               CFStringRef     new_model;
 
-       if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCPreferencesSetCallBack() failed: %s"),
-                     SCErrorString(SCError()));
+               new_model = _SC_hw_model(FALSE);
+
+               /* Need to regenerate the new configuration for new model */
+               if (new_model != NULL) {
+                       CFStringRef     old_model;
+
+                       old_model = SCPreferencesGetValue(prefs, MODEL);
+                       if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) {
+                               // if new hardware
+                               need_update = TRUE;
+                               restorePrefs = previousConfigurationAvailable();
+                       }
+               }
+
+               if (need_update == FALSE) {
+                       SCNetworkSetRef current;
+
+                       current = SCNetworkSetCopyCurrent(prefs);
+                       if (current != NULL) {
+                               /* network configuration available, disable template creation */
+                               initPrefs = FALSE;
+                               CFRelease(current);
+                       }
+               }
+       } else {
+               SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError()));
                goto error;
        }
 
        /*
         * register for change notifications.
         */
+       if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
+               SC_log(LOG_NOTICE, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError()));
+               goto error;
+       }
+
        if (!SCPreferencesScheduleWithRunLoop(prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
-               SCLog(TRUE, LOG_ERR,
-                     CFSTR("SCPreferencesScheduleWithRunLoop() failed: %s"),
-                     SCErrorString(SCError()));
+               SC_log(LOG_NOTICE, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError()));
                goto error;
        }
 
+       /*
+        * if no preferences, initialize with a template (now or
+        * when IOKit has quiesced).
+        */
+       if (initPrefs) {
+               watchQuietEnable();
+               watchQuietCallback(store, NULL, NULL);
+       }
+
        return;
 
     error :
 
-       if (store)      CFRelease(store);
-       if (prefs)      CFRelease(prefs);
+       watchQuietDisable();
+       if (store != NULL)      CFRelease(store);
+       if (prefs != NULL)      CFRelease(prefs);
 
        return;
 }