X-Git-Url: https://git.saurik.com/apple/configd.git/blobdiff_plain/5958d7c06f2795b9ec773eb750b8259460acf8cb..1e2cbe6aa7461cd7abf510b7c26db26974657962:/configd.tproj/_SCD.c?ds=sidebyside diff --git a/configd.tproj/_SCD.c b/configd.tproj/_SCD.c index c89dd8c..bb64497 100644 --- a/configd.tproj/_SCD.c +++ b/configd.tproj/_SCD.c @@ -1,71 +1,60 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * + * 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * + * 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@ */ +/* + * Modification History + * + * June 1, 2001 Allan Nathanson + * - public API conversion + * + * June 2, 2000 Allan Nathanson + * - initial revision + */ -#include "configd.h" - - -CFMutableDictionaryRef sessionData = NULL; - -CFMutableDictionaryRef cacheData = NULL; -CFMutableDictionaryRef cacheData_s = NULL; - -CFMutableSetRef changedKeys = NULL; -CFMutableSetRef changedKeys_s = NULL; -CFMutableSetRef deferredRemovals = NULL; -CFMutableSetRef deferredRemovals_s = NULL; +#include -CFMutableSetRef removedSessionKeys = NULL; -CFMutableSetRef removedSessionKeys_s = NULL; +#include "configd.h" +#include "configd_server.h" +#include "session.h" -CFMutableSetRef needsNotification = NULL; +__private_extern__ CFMutableDictionaryRef sessionData = NULL; -void -_swapLockedCacheData() -{ - void *temp; +__private_extern__ CFMutableDictionaryRef storeData = NULL; - temp = cacheData; - cacheData = cacheData_s; - cacheData_s = temp; +__private_extern__ CFMutableDictionaryRef patternData = NULL; - temp = changedKeys; - changedKeys = changedKeys_s; - changedKeys_s = temp; +__private_extern__ CFMutableSetRef changedKeys = NULL; - temp = deferredRemovals; - deferredRemovals = deferredRemovals_s; - deferredRemovals_s = temp; +__private_extern__ CFMutableSetRef deferredRemovals = NULL; - temp = removedSessionKeys; - removedSessionKeys = removedSessionKeys_s; - removedSessionKeys_s = temp; +__private_extern__ CFMutableSetRef removedSessionKeys = NULL; - return; -} +__private_extern__ CFMutableSetRef needsNotification = NULL; +__private_extern__ void _addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey) { @@ -80,9 +69,9 @@ _addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey) CFNumberRef refNum; /* - * Get the dictionary associated with this key out of the cache + * Get the dictionary associated with this key out of the store */ - dict = CFDictionaryGetValue(cacheData, watchedKey); + dict = CFDictionaryGetValue(storeData, watchedKey); if (dict) { newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); } else { @@ -111,7 +100,7 @@ _addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey) i = CFArrayGetFirstIndexOfValue(newWatchers, CFRangeMake(0, CFArrayGetCount(newWatchers)), sessionNum); - if (i == -1) { + if (i == kCFNotFound) { /* if this is the first instance of this session watching this key */ CFArrayAppendValue(newWatchers, sessionNum); refCnt = 1; @@ -137,160 +126,20 @@ _addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey) CFRelease(newWatcherRefs); /* - * Update the cache for this key + * Update the store for this key */ - CFDictionarySetValue(cacheData, watchedKey, newDict); + CFDictionarySetValue(storeData, watchedKey, newDict); CFRelease(newDict); - SCDLog(LOG_DEBUG, CFSTR(" _addWatcher: %@, %@"), sessionNum, watchedKey); - - return; -} - - -/* - * _addRegexWatcherByKey() - * - * This is a CFDictionaryApplierFunction which will iterate over each key - * defined in the "cacheData" dictionary. The arguments are the dictionary - * key, it's associated cache dictionary, and a context structure which - * includes the following: - * - * 1. the session which has just added a regex notification request - * 2. the compiled regular expression associated with the above key. - * - * If a (real) dictionary key is found which matches the provided regular - * expression then we mark that key as being watched by the session. - */ -void -_addRegexWatcherByKey(const void *key, void *val, void *context) -{ - CFStringRef cacheStr = key; - CFDictionaryRef info = val; - mach_port_t sessionID = ((addContextRef)context)->session->server; - regex_t *preg = ((addContextRef)context)->preg; - int cacheKeyLen; - char *cacheKey; - CFNumberRef sessionNum; - int reError; - char reErrBuf[256]; - int reErrStrLen; - - if (CFDictionaryContainsKey(info, kSCDData) == FALSE) { - /* if no data (yet) */ - return; - } - - /* convert cache key to C string */ - cacheKeyLen = CFStringGetLength(cacheStr) + 1; - cacheKey = CFAllocatorAllocate(NULL, cacheKeyLen, 0); - if (!CFStringGetCString(cacheStr, cacheKey, cacheKeyLen, kCFStringEncodingMacRoman)) { - SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert cache key to C string")); - CFAllocatorDeallocate(NULL, cacheKey); - return; - } - - /* compare cache key to new notification keys regular expression pattern */ - reError = regexec(preg, cacheKey, 0, NULL, 0); - switch (reError) { - case 0 : - /* we've got a match */ - sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionID); - _addWatcher(sessionNum, cacheStr); - CFRelease(sessionNum); - break; - case REG_NOMATCH : - /* no match */ - break; - default : - reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf)); - SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf); - break; - } - CFAllocatorDeallocate(NULL, cacheKey); -} - - -/* - * _addRegexWatchersBySession() - * - * This is a CFDictionaryApplierFunction which will iterate over each session - * defined in the "sessionData" dictionary. The arguments are the session - * key, it's associated session dictionary, , and the cache key being added. - * - * If an active session includes any regular expression keys which match the - * key being added to the "cacheData" dictionary then we mark this key as being - * watched by the session. - */ -void -_addRegexWatchersBySession(const void *key, void *val, void *context) -{ - CFStringRef sessionKey = key; - CFDictionaryRef info = val; - CFStringRef addedKey = context; - CFIndex newKeyLen; - char *newKeyStr; - CFArrayRef rKeys; - CFArrayRef rData; - CFIndex i; - - if (info == NULL) { - /* if no dictionary for this session */ - return; - } - - rKeys = CFDictionaryGetValue(info, kSCDRegexKeys); - if (rKeys == NULL) { - /* if no regex keys for this session */ - return; - } - rData = CFDictionaryGetValue(info, kSCDRegexData); - - /* convert new key to C string */ - newKeyLen = CFStringGetLength(addedKey) + 1; - newKeyStr = CFAllocatorAllocate(NULL, newKeyLen, 0); - if (!CFStringGetCString(addedKey, newKeyStr, newKeyLen, kCFStringEncodingMacRoman)) { - SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert new key to C string")); - CFAllocatorDeallocate(NULL, newKeyStr); - return; - } - - /* iterate over the regex keys looking for an pattern which matches the new key */ - for (i=0; i 0) { /* if this key is still active */ - CFDictionarySetValue(cacheData, watchedKey, newDict); + CFDictionarySetValue(storeData, watchedKey, newDict); } else { /* no information left, remove the empty dictionary */ - CFDictionaryRemoveValue(cacheData, watchedKey); + CFDictionaryRemoveValue(storeData, watchedKey); } CFRelease(newDict); - SCDLog(LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@"), sessionNum, watchedKey); +#ifdef DEBUG + SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@"), sessionNum, watchedKey); +#endif /* DEBUG */ return; } -/* - * _removeRegexWatcherByKey() - * - * This is a CFDictionaryApplierFunction which will iterate over each key - * defined in the "cacheData" dictionary. The arguments are the dictionary - * key, it's associated cache dictionary, and a context structure which - * includes the following: - * - * 1. the session which has just removed a regex notification request - * 2. the compiled regular expression associated with the above key. - * - * If a key is found and it matches the provided regular expression then - * it will its "being watched" status will be cleared. - */ -void -_removeRegexWatcherByKey(const void *key, void *val, void *context) -{ - CFStringRef cacheStr = key; - CFDictionaryRef info = val; - mach_port_t sessionID = ((removeContextRef)context)->session->server; - regex_t *preg = ((removeContextRef)context)->preg; - CFNumberRef sessionNum; - CFArrayRef watchers; - int cacheKeyLen; - char *cacheKey; - int reError; - char reErrBuf[256]; - int reErrStrLen; - - if ((info == NULL) || (CFDictionaryContainsKey(info, kSCDWatchers) == FALSE)) { - /* no dictionary or no watchers */ - return; - } - - sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionID); - - watchers = CFDictionaryGetValue(info, kSCDWatchers); - if (CFArrayContainsValue(watchers, - CFRangeMake(0, CFArrayGetCount(watchers)), - sessionNum) == FALSE) { - /* this session is not watching this key */ - CFRelease(sessionNum); - return; - } - - /* convert key to C string */ - cacheKeyLen = CFStringGetLength(cacheStr) + 1; - cacheKey = CFAllocatorAllocate(NULL, cacheKeyLen, 0); - if (!CFStringGetCString(cacheStr, cacheKey, cacheKeyLen, kCFStringEncodingMacRoman)) { - SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert key to C string")); - CFAllocatorDeallocate(NULL, cacheKey); - CFRelease(sessionNum); - return; - } - - /* check if this key matches the regular expression */ - reError = regexec(preg, cacheKey, 0, NULL, 0); - switch (reError) { - case 0 : - /* we've got a match */ - _removeWatcher(sessionNum, cacheStr); - break; - case REG_NOMATCH : - /* no match */ - break; - default : - reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf)); - SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf); - break; - } - CFAllocatorDeallocate(NULL, cacheKey); - CFRelease(sessionNum); -} - - -/* - * _removeRegexWatchersBySession() - * - * This is a CFDictionaryApplierFunction which will iterate over each session - * defined in the "sessionData" dictionary. The arguments are the session - * key, it's associated session dictionary, and the cache key being removed. - * - * If an active session includes any regular expression keys which match the - * key being removed from the "cacheData" dictionary then we clear this keys - * reference of being watched. - */ +__private_extern__ void -_removeRegexWatchersBySession(const void *key, void *val, void *context) +pushNotifications(FILE *_configd_trace) { - CFStringRef sessionKey = key; - CFDictionaryRef info = val; - CFStringRef removedKey = context; - CFIndex oldKeyLen; - char *oldKeyStr; - CFArrayRef rKeys; - CFArrayRef rData; - CFIndex i; - - if (info == NULL) { - /* if no dictionary for this session */ - return; - } - - rKeys = CFDictionaryGetValue(info, kSCDRegexKeys); - if (rKeys == NULL) { - /* if no regex keys for this session */ - return; - } - rData = CFDictionaryGetValue(info, kSCDRegexData); - - /* convert new key to C string */ - oldKeyLen = CFStringGetLength(removedKey) + 1; - oldKeyStr = CFAllocatorAllocate(NULL, oldKeyLen, 0); - if (!CFStringGetCString(removedKey, oldKeyStr, oldKeyLen, kCFStringEncodingMacRoman)) { - SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert old key to C string")); - CFAllocatorDeallocate(NULL, oldKeyStr); - return; - } + const void **sessionsToNotify; + CFIndex notifyCnt; + int server; + serverSessionRef theSession; + SCDynamicStorePrivateRef storePrivate; + + if (needsNotification == NULL) + return; /* if no sessions need to be kicked */ + + notifyCnt = CFSetGetCount(needsNotification); + sessionsToNotify = malloc(notifyCnt * sizeof(CFNumberRef)); + CFSetGetValues(needsNotification, sessionsToNotify); + while (--notifyCnt >= 0) { + (void) CFNumberGetValue(sessionsToNotify[notifyCnt], + kCFNumberIntType, + &server); + theSession = getSession(server); + storePrivate = (SCDynamicStorePrivateRef)theSession->store; + + /* + * deliver notifications to client sessions + */ + if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) && + (storePrivate->notifyPort != MACH_PORT_NULL)) { + /* + * Post notification as mach message + */ + if (_configd_trace != NULL) { + SCTrace(TRUE, _configd_trace, + CFSTR("%s : %5d : port = %d, msgid = %d\n"), + "-->port", + storePrivate->server, + storePrivate->notifyPort, + storePrivate->notifyPortIdentifier); + } + + _SC_sendMachMessage(storePrivate->notifyPort, storePrivate->notifyPortIdentifier); + } - /* iterate over the regex keys looking for an pattern which matches the old key */ - for (i=0; inotifyStatus == Using_NotifierInformViaFD) && + (storePrivate->notifyFile >= 0)) { + ssize_t written; + + if (_configd_trace != NULL) { + SCTrace(TRUE, _configd_trace, + CFSTR("%s : %5d : fd = %d, msgid = %d\n"), + "-->fd ", + storePrivate->server, + storePrivate->notifyFile, + storePrivate->notifyFileIdentifier); + } + + written = write(storePrivate->notifyFile, + &storePrivate->notifyFileIdentifier, + sizeof(storePrivate->notifyFileIdentifier)); + if (written == -1) { + if (errno == EWOULDBLOCK) { +#ifdef DEBUG + SCLog(_configd_verbose, LOG_DEBUG, + CFSTR("sorry, only one outstanding notification per session.")); +#endif /* DEBUG */ + } else { +#ifdef DEBUG + SCLog(_configd_verbose, LOG_DEBUG, + CFSTR("could not send notification, write() failed: %s"), + strerror(errno)); +#endif /* DEBUG */ + storePrivate->notifyFile = -1; + } + } else if (written != sizeof(storePrivate->notifyFileIdentifier)) { +#ifdef DEBUG + SCLog(_configd_verbose, LOG_DEBUG, + CFSTR("could not send notification, incomplete write()")); +#endif /* DEBUG */ + storePrivate->notifyFile = -1; + } } + if ((storePrivate->notifyStatus == Using_NotifierInformViaSignal) && + (storePrivate->notifySignal > 0)) { + kern_return_t status; + pid_t pid; + /* + * Post notification as signal + */ + status = pid_for_task(storePrivate->notifySignalTask, &pid); + if (status == KERN_SUCCESS) { + if (_configd_trace != NULL) { + SCTrace(TRUE, _configd_trace, + CFSTR("%s : %5d : pid = %d, signal = sig%s (%d)\n"), + "-->sig ", + storePrivate->server, + pid, + sys_signame[storePrivate->notifySignal], + storePrivate->notifySignal); + } + + if (kill(pid, storePrivate->notifySignal) != 0) { + if (errno != ESRCH) { + SCLog(TRUE, LOG_ERR, + CFSTR("could not send sig%s to PID %d: %s"), + sys_signame[storePrivate->notifySignal], + pid, + strerror(errno)); + } + } + } else { + mach_port_type_t pt; + + __MACH_PORT_DEBUG(TRUE, "*** pushNotifications pid_for_task failed: releasing task", storePrivate->notifySignalTask); + if (mach_port_type(mach_task_self(), storePrivate->notifySignalTask, &pt) == KERN_SUCCESS) { + if ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) { + SCLog(TRUE, LOG_ERR, CFSTR("pushNotifications pid_for_task() failed: %s"), mach_error_string(status)); + } + } else { + SCLog(TRUE, LOG_ERR, CFSTR("pushNotifications mach_port_type() failed: %s"), mach_error_string(status)); + } + + /* don't bother with any more attempts */ + (void) mach_port_deallocate(mach_task_self(), storePrivate->notifySignalTask); + storePrivate->notifySignal = 0; + storePrivate->notifySignalTask = TASK_NULL; + } + } } - CFAllocatorDeallocate(NULL, oldKeyStr); + free(sessionsToNotify); + + /* + * this list of notifications have been posted, wait for some more. + */ + CFRelease(needsNotification); + needsNotification = NULL; return; }