X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/edebe297f772e4cdd76278ebb777820466d2917b..77a550b625b42f93d03018146bc3f0751ff2eed8:/Plugins/PreferencesMonitor/prefsmon.c diff --git a/Plugins/PreferencesMonitor/prefsmon.c b/Plugins/PreferencesMonitor/prefsmon.c index 5466f22..5727a67 100644 --- a/Plugins/PreferencesMonitor/prefsmon.c +++ b/Plugins/PreferencesMonitor/prefsmon.c @@ -1,15 +1,15 @@ /* - * Copyright (c) 2000-2007 Apple 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 #include #include #include @@ -62,17 +63,127 @@ 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 void +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); @@ -82,40 +193,100 @@ establishNewPreferences() sc_status = SCError(); if (sc_status == kSCStatusStale) { - (void) SCPreferencesSynchronize(prefs); + SCPreferencesSynchronize(prefs); } else { - SCLog(TRUE, LOG_ERR, - CFSTR("Could not acquire network configuration lock: %s"), - SCErrorString(sc_status)); - return; + SC_log(LOG_NOTICE, "Could not acquire network configuration lock: %s", + SCErrorString(sc_status)); + return FALSE; } } - set = SCNetworkSetCreate(prefs); - if (set == NULL) { - ok = FALSE; - sc_status = SCError(); - goto done; - } + /* 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); + } + } - bundle = _SC_CFBundleGet(); - if (bundle != NULL) { - setName = CFBundleCopyLocalizedString(bundle, - CFSTR("DEFAULT_SET_NAME"), - CFSTR("Automatic"), - NULL); + if (keys != NULL) { + CFRelease(keys); + } + } + /* Set the new model */ + SCPreferencesSetValue(prefs, MODEL, new_model); } - ok = SCNetworkSetSetName(set, (setName != NULL) ? setName : CFSTR("Automatic")); - if (!ok) { - sc_status = SCError(); - goto done; + current = SCNetworkSetCopyCurrent(prefs); + if (current != NULL) { + set = current; } - ok = SCNetworkSetSetCurrent(set); - if (!ok) { - sc_status = SCError(); - goto done; + 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); @@ -129,59 +300,69 @@ establishNewPreferences() if (ok) { ok = SCPreferencesCommitChanges(prefs); if (ok) { - SCLog(TRUE, LOG_NOTICE, CFSTR("New network configuration saved")); + 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 (set != NULL) { + } else if ((current == NULL) && (set != NULL)) { (void) SCNetworkSetRemove(set); } if (!ok) { - SCLog(TRUE, LOG_ERR, - CFSTR("Could not establish network configuration: %s"), - SCErrorString(sc_status)); + 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; + return updated; } static Boolean -quiet() +quiet(Boolean *timeout) { CFDictionaryRef dict; - Boolean quiet = FALSE; + Boolean _quiet = FALSE; + Boolean _timeout = FALSE; // check if quiet dict = SCDynamicStoreCopyValue(store, initKey); if (dict != NULL) { - if (isA_CFDictionary(dict) && - (CFDictionaryContainsKey(dict, CFSTR("*QUIET*")) || - CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*")))) { - quiet = TRUE; + if (isA_CFDictionary(dict)) { + if (CFDictionaryContainsKey(dict, CFSTR("*QUIET*"))) { + _quiet = TRUE; + } + if (CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*"))) { + _timeout = TRUE; + } } CFRelease(dict); } - return quiet; + if (timeout != NULL) { + *timeout = _timeout; + } + return _quiet; } static void watchQuietDisable() { - if ((initKey == NULL) && (initRls == NULL)) { + if ((initKey == NULL) || (initRls == NULL)) { return; } @@ -215,20 +396,63 @@ watchQuietEnable() ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL); CFRelease(keys); if (!ok) { - SCPrint(TRUE, stderr, - CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError())); + 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) { - if (quiet()) { + Boolean _quiet; + Boolean _timeout = FALSE; + + _quiet = quiet(&_timeout); + if (_quiet +#if !TARGET_OS_IPHONE + || _timeout +#endif /* !TARGET_OS_IPHONE */ + ) { watchQuietDisable(); - establishNewPreferences(); + } + + 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; @@ -290,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; } } @@ -443,7 +666,7 @@ updateSCDynamicStore(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; } @@ -457,9 +680,8 @@ updateSCDynamicStore(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; } @@ -478,9 +700,8 @@ updateSCDynamicStore(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; } @@ -490,17 +711,15 @@ updateSCDynamicStore(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; } @@ -530,11 +749,15 @@ updateSCDynamicStore(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())); } +#else // !MAIN + SC_log(LOG_DEBUG, "SCDynamicStore\nset: %@\nremove: %@", + newPrefs, + removedPrefsKeys); +#endif // !MAIN CFRelease(currentPrefs); CFRelease(newPrefs); @@ -552,8 +775,13 @@ updateConfiguration(SCPreferencesRef prefs, SCPreferencesNotification notificationType, void *info) { + os_activity_t activity_id; + + activity_id = os_activity_start("processing [SC] preferences.plist changes", + OS_ACTIVITY_FLAG_DEFAULT); +#if !TARGET_OS_IPHONE if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) { SCNetworkSetRef current; @@ -564,49 +792,26 @@ updateConfiguration(SCPreferencesRef prefs, CFRelease(current); } } +#endif /* !TARGET_OS_IPHONE */ if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) { - return; + goto done; } - SCLog(_verbose, LOG_DEBUG, CFSTR("updating configuration")); + SC_log(LOG_INFO, "updating configuration"); /* update SCDynamicStore (Setup:) */ updateSCDynamicStore(prefs); /* finished with current prefs, wait for changes */ - SCPreferencesSynchronize(prefs); - - return; -} - - -__private_extern__ -void -stop_PreferencesMonitor(CFRunLoopSourceRef stopRls) -{ - // cleanup - - watchQuietDisable(); - - if (prefs != NULL) { - if (!SCPreferencesUnscheduleFromRunLoop(prefs, - CFRunLoopGetCurrent(), - kCFRunLoopDefaultMode)) { - SCLog(TRUE, LOG_ERR, - CFSTR("SCPreferencesUnscheduleFromRunLoop() failed: %s"), - SCErrorString(SCError())); - } - CFRelease(prefs); - prefs = NULL; + if (!rofs) { + SCPreferencesSynchronize(prefs); } - if (store != NULL) { - CFRelease(store); - store = NULL; - } + done : + + os_activity_end(activity_id); - CFRunLoopSourceSignal(stopRls); return; } @@ -615,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); @@ -630,12 +835,8 @@ load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose) { Boolean initPrefs = TRUE; - if (bundleVerbose) { - _verbose = 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, @@ -643,27 +844,46 @@ load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose) 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); +#else // !MAIN + prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist")); +#endif // !MAIN if (prefs != NULL) { - SCNetworkSetRef current; + Boolean need_update = FALSE; + CFStringRef new_model; - current = SCNetworkSetCopyCurrent(prefs); - if (current != NULL) { - /* network configuration available, disable template creation */ - initPrefs = FALSE; - CFRelease(current); + 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 { - SCLog(TRUE, LOG_ERR, - CFSTR("SCPreferencesCreate() failed: %s"), - SCErrorString(SCError())); + SC_log(LOG_NOTICE, "SCPreferencesCreate() failed: %s", SCErrorString(SCError())); goto error; } @@ -671,16 +891,12 @@ load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose) * register for change notifications. */ if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) { - SCLog(TRUE, LOG_ERR, - CFSTR("SCPreferencesSetCallBack() failed: %s"), - SCErrorString(SCError())); + 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; }