#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(FILE *_configd_trace)
{
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)) {
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);
}
if ((storePrivate->notifyStatus == 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
} 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) {
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));
}
(void) mach_port_deallocate(mach_task_self(), storePrivate->notifySignalTask);
storePrivate->notifySignal = 0;
storePrivate->notifySignalTask = TASK_NULL;
}
}
}
free(sessionsToNotify);
CFRelease(needsNotification);
needsNotification = NULL;
return;
}