#include <unistd.h>
#include "configd.h"
#include "session.h"
#define N_QUICK 16
static Boolean
isMySessionKey(CFStringRef sessionKey, CFStringRef key)
{
CFDictionaryRef dict;
CFStringRef storeSessionKey;
dict = CFDictionaryGetValue(storeData, key);
if (!dict) {
return FALSE;
}
storeSessionKey = CFDictionaryGetValue(dict, kSCDSession);
if (!storeSessionKey) {
return FALSE;
}
if (!CFEqual(sessionKey, storeSessionKey)) {
return FALSE;
}
return TRUE;
}
static void
removeAllKeys(SCDynamicStoreRef store, Boolean isRegex)
{
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
CFSetRef keys;
CFIndex n;
keys = isRegex ? storePrivate->patterns : storePrivate->keys;
n = CFSetGetCount(keys);
if (n > 0) {
CFIndex i;
CFArrayRef keysToRemove;
const void * watchedKeys_q[N_QUICK];
const void ** watchedKeys = watchedKeys_q;
if (n > (CFIndex)(sizeof(watchedKeys_q) / sizeof(CFStringRef)))
watchedKeys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
CFSetGetValues(keys, watchedKeys);
keysToRemove = CFArrayCreate(NULL, watchedKeys, n, &kCFTypeArrayCallBacks);
if (watchedKeys != watchedKeys_q) CFAllocatorDeallocate(NULL, watchedKeys);
for (i = 0; i < n; i++) {
(void) __SCDynamicStoreRemoveWatchedKey(store,
CFArrayGetValueAtIndex(keysToRemove, i),
isRegex,
TRUE);
}
CFRelease(keysToRemove);
}
return;
}
__private_extern__
int
__SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal)
{
CFDictionaryRef dict;
CFArrayRef keys;
CFIndex keyCnt;
serverSessionRef mySession;
CFStringRef sessionKey;
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)*store;
if ((*store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
return kSCStatusNoStoreSession;
}
if (_configd_trace) {
SCTrace(TRUE, _configd_trace,
CFSTR("%s : %5d\n"),
internal ? "*close " : "close ",
storePrivate->server);
}
removeAllKeys(*store, FALSE); removeAllKeys(*store, TRUE);
__MACH_PORT_DEBUG(storePrivate->notifyPort != MACH_PORT_NULL, "*** __SCDynamicStoreClose", storePrivate->notifyPort);
(void) __SCDynamicStoreNotifyCancel(*store);
sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
dict = CFDictionaryGetValue(sessionData, sessionKey);
keys = CFDictionaryGetValue(dict, kSCDSessionKeys);
if (keys && ((keyCnt = CFArrayGetCount(keys)) > 0)) {
Boolean wasLocked;
CFIndex i;
wasLocked = (storeLocked > 0);
if (!wasLocked) {
(void) __SCDynamicStoreLock(*store, FALSE);
}
for (i = 0; i < keyCnt; i++) {
if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i))) {
(void) __SCDynamicStoreRemoveValue(*store, CFArrayGetValueAtIndex(keys, i), TRUE);
}
}
if (wasLocked) {
_swapLockedStoreData();
for (i = 0; i < keyCnt; i++) {
if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i)))
(void) __SCDynamicStoreRemoveValue(*store, CFArrayGetValueAtIndex(keys, i), TRUE);
}
_swapLockedStoreData();
}
}
CFRelease(sessionKey);
if (storePrivate->locked) {
(void) __SCDynamicStoreUnlock(*store, FALSE);
}
mySession = getSession(storePrivate->server);
if (mySession->serverRunLoopSource) {
CFRunLoopSourceInvalidate(mySession->serverRunLoopSource);
CFRelease(mySession->serverRunLoopSource);
mySession->serverRunLoopSource = NULL;
}
if (mySession->serverPort != NULL) {
CFMachPortInvalidate(mySession->serverPort);
CFRelease(mySession->serverPort);
mySession->serverPort = NULL;
}
storePrivate->server = MACH_PORT_NULL;
CFRelease(*store);
*store = NULL;
return kSCStatusOK;
}
__private_extern__
kern_return_t
_configclose(mach_port_t server, int *sc_status)
{
serverSessionRef mySession = getSession(server);
if (mySession == NULL) {
*sc_status = kSCStatusNoStoreSession;
return KERN_SUCCESS;
}
__MACH_PORT_DEBUG(TRUE, "*** _configclose", server);
*sc_status = __SCDynamicStoreClose(&mySession->store, FALSE);
if (*sc_status != kSCStatusOK) {
SCLog(TRUE, LOG_ERR,
CFSTR("_configclose __SCDynamicStoreClose() failed, status = %s"),
SCErrorString(*sc_status));
return KERN_SUCCESS;
}
__MACH_PORT_DEBUG(TRUE, "*** _configclose (after __SCDynamicStoreClose)", server);
(void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1);
removeSession(server);
return KERN_SUCCESS;
}