#include <unistd.h>
#include "configd.h"
#include "configd_server.h"
#include "session.h"
__private_extern__ CFMutableDictionaryRef sessionData = NULL;
__private_extern__ CFMutableDictionaryRef storeData = NULL;
__private_extern__ CFMutableDictionaryRef storeData_s = NULL;
__private_extern__ CFMutableDictionaryRef patternData = NULL;
__private_extern__ CFMutableDictionaryRef patternData_s = NULL;
__private_extern__ CFMutableSetRef changedKeys = NULL;
__private_extern__ CFMutableSetRef changedKeys_s = NULL;
__private_extern__ CFMutableSetRef deferredRemovals = NULL;
__private_extern__ CFMutableSetRef deferredRemovals_s = NULL;
__private_extern__ CFMutableSetRef removedSessionKeys = NULL;
__private_extern__ CFMutableSetRef removedSessionKeys_s = NULL;
__private_extern__ CFMutableSetRef needsNotification = NULL;
__private_extern__ int storeLocked = 0;
__private_extern__
void
_swapLockedStoreData()
{
void *temp;
temp = storeData;
storeData = storeData_s;
storeData_s = temp;
temp = patternData;
patternData = patternData_s;
patternData_s = temp;
temp = changedKeys;
changedKeys = changedKeys_s;
changedKeys_s = temp;
temp = deferredRemovals;
deferredRemovals = deferredRemovals_s;
deferredRemovals_s = temp;
temp = removedSessionKeys;
removedSessionKeys = removedSessionKeys_s;
removedSessionKeys_s = temp;
return;
}
__private_extern__
void
_addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFArrayRef watchers;
CFMutableArrayRef newWatchers;
CFArrayRef watcherRefs;
CFMutableArrayRef newWatcherRefs;
CFIndex i;
int refCnt;
CFNumberRef refNum;
dict = CFDictionaryGetValue(storeData, watchedKey);
if (dict) {
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
} else {
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
if (watchers) {
newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
} else {
newWatchers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
newWatcherRefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
i = CFArrayGetFirstIndexOfValue(newWatchers,
CFRangeMake(0, CFArrayGetCount(newWatchers)),
sessionNum);
if (i == kCFNotFound) {
CFArrayAppendValue(newWatchers, sessionNum);
refCnt = 1;
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArrayAppendValue(newWatcherRefs, refNum);
CFRelease(refNum);
} else {
refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
refCnt++;
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
CFRelease(refNum);
}
CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
CFRelease(newWatchers);
CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
CFRelease(newWatcherRefs);
CFDictionarySetValue(storeData, watchedKey, newDict);
CFRelease(newDict);
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _addWatcher: %@, %@"), sessionNum, watchedKey);
#endif
return;
}
__private_extern__
void
_removeWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
{
CFDictionaryRef dict;
CFMutableDictionaryRef newDict;
CFArrayRef watchers;
CFMutableArrayRef newWatchers;
CFArrayRef watcherRefs;
CFMutableArrayRef newWatcherRefs;
CFIndex i;
int refCnt;
CFNumberRef refNum;
dict = CFDictionaryGetValue(storeData, watchedKey);
if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDWatchers) == FALSE)) {
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@, key not watched"), sessionNum, watchedKey);
#endif
return;
}
newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
i = CFArrayGetFirstIndexOfValue(newWatchers,
CFRangeMake(0, CFArrayGetCount(newWatchers)),
sessionNum);
if (i == kCFNotFound) {
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@, session not watching"), sessionNum, watchedKey);
#endif
CFRelease(newDict);
CFRelease(newWatchers);
CFRelease(newWatcherRefs);
return;
}
refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
if (--refCnt > 0) {
refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
CFRelease(refNum);
} else {
CFArrayRemoveValueAtIndex(newWatchers, i);
CFArrayRemoveValueAtIndex(newWatcherRefs, i);
}
if (CFArrayGetCount(newWatchers) > 0) {
CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
} else {
CFDictionaryRemoveValue(newDict, kSCDWatchers);
CFDictionaryRemoveValue(newDict, kSCDWatcherRefs);
}
CFRelease(newWatchers);
CFRelease(newWatcherRefs);
if (CFDictionaryGetCount(newDict) > 0) {
CFDictionarySetValue(storeData, watchedKey, newDict);
} else {
CFDictionaryRemoveValue(storeData, watchedKey);
}
CFRelease(newDict);
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@"), sessionNum, watchedKey);
#endif
return;
}
__private_extern__
void
pushNotifications()
{
const void **sessionsToNotify;
CFIndex notifyCnt;
int server;
serverSessionRef theSession;
SCDynamicStorePrivateRef storePrivate;
if (needsNotification == NULL)
return;
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;
if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
(storePrivate->notifyPort != MACH_PORT_NULL)) {
#ifdef DEBUG
if (_configd_verbose) {
SCLog(TRUE, LOG_DEBUG, CFSTR("sending mach message notification."));
SCLog(TRUE, LOG_DEBUG, CFSTR(" port = %d"), storePrivate->notifyPort);
SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyPortIdentifier);
}
#endif
_SC_sendMachMessage(storePrivate->notifyPort, storePrivate->notifyPortIdentifier);
}
if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
(storePrivate->notifyFile >= 0)) {
ssize_t written;
#ifdef DEBUG
if (_configd_verbose) {
SCLog(TRUE, LOG_DEBUG, CFSTR("sending (UNIX domain) socket notification"));
SCLog(TRUE, LOG_DEBUG, CFSTR(" fd = %d"), storePrivate->notifyFile);
SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyFileIdentifier);
}
#endif
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
} else {
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG,
CFSTR("could not send notification, write() failed: %s"),
strerror(errno));
#endif
storePrivate->notifyFile = -1;
}
} else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG,
CFSTR("could not send notification, incomplete write()"));
#endif
storePrivate->notifyFile = -1;
}
}
if ((storePrivate->notifyStatus == Using_NotifierInformViaSignal) &&
(storePrivate->notifySignal > 0)) {
kern_return_t status;
pid_t pid;
status = pid_for_task(storePrivate->notifySignalTask, &pid);
if (status == KERN_SUCCESS) {
#ifdef DEBUG
if (_configd_verbose) {
SCLog(TRUE, LOG_DEBUG, CFSTR("sending signal notification"));
SCLog(TRUE, LOG_DEBUG, CFSTR(" pid = %d"), pid);
SCLog(TRUE, LOG_DEBUG, CFSTR(" signal = %d"), storePrivate->notifySignal);
}
#endif
if (kill(pid, storePrivate->notifySignal) != 0) {
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), strerror(errno));
#endif
status = KERN_FAILURE;
}
} else {
mach_port_type_t pt;
if ((mach_port_type(mach_task_self(), storePrivate->notifySignalTask, &pt) == KERN_SUCCESS) &&
(pt & MACH_PORT_TYPE_DEAD_NAME)) {
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal, process died"));
} else {
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), mach_error_string(status));
}
}
if (status != KERN_SUCCESS) {
(void) mach_port_destroy(mach_task_self(), storePrivate->notifySignalTask);
storePrivate->notifySignal = 0;
storePrivate->notifySignalTask = TASK_NULL;
}
}
}
free(sessionsToNotify);
CFRelease(needsNotification);
needsNotification = NULL;
return;
}