#include <unistd.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <SystemConfiguration/SCD.h>
#include "config.h"
#include "SCDPrivate.h"
SCDStatus
SCDClose(SCDSessionRef *session)
{
SCDSessionPrivateRef sessionPrivate;
int oldThreadState;
kern_return_t status;
SCDStatus scd_status;
CFIndex keyCnt;
SCDLog(LOG_DEBUG, CFSTR("SCDClose:"));
if ((session == NULL) || (*session == NULL)) {
return SCD_NOSESSION;
}
sessionPrivate = (SCDSessionPrivateRef)*session;
(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldThreadState);
scd_status = (sessionPrivate->server == MACH_PORT_NULL) ? SCD_NOSESSION : SCD_OK;
if ((keyCnt = CFSetGetCount(sessionPrivate->keys)) > 0) {
void **watchedKeys;
CFArrayRef keysToRemove;
CFIndex i;
watchedKeys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
CFSetGetValues(sessionPrivate->keys, watchedKeys);
keysToRemove = CFArrayCreate(NULL, watchedKeys, keyCnt, &kCFTypeArrayCallBacks);
CFAllocatorDeallocate(NULL, watchedKeys);
for (i=0; i<keyCnt; i++) {
if (scd_status == SCD_OK) {
scd_status = SCDNotifierRemove(*session,
CFArrayGetValueAtIndex(keysToRemove, i),
0);
}
}
CFRelease(keysToRemove);
}
if ((keyCnt = CFSetGetCount(sessionPrivate->reKeys)) > 0) {
void **watchedKeys;
CFArrayRef keysToRemove;
CFIndex i;
watchedKeys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
CFSetGetValues(sessionPrivate->reKeys, watchedKeys);
keysToRemove = CFArrayCreate(NULL, watchedKeys, keyCnt, &kCFTypeArrayCallBacks);
CFAllocatorDeallocate(NULL, watchedKeys);
for (i=0; i<keyCnt; i++) {
if (scd_status == SCD_OK) {
scd_status = SCDNotifierRemove(*session,
CFArrayGetValueAtIndex(keysToRemove, i),
kSCDRegexKey);
}
}
CFRelease(keysToRemove);
}
(void) SCDNotifierCancel(*session);
if (SCDOptionGet(*session, kSCDOptionIsLocked) && (scd_status == SCD_OK)) {
scd_status = SCDUnlock(*session);
}
if (scd_status == SCD_OK) {
status = configclose(sessionPrivate->server, (int *)&scd_status);
if (status != KERN_SUCCESS) {
if (status != MACH_SEND_INVALID_DEST)
SCDLog(LOG_DEBUG, CFSTR("configclose(): %s"), mach_error_string(status));
scd_status = SCD_NOSERVER;
}
(void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
sessionPrivate->server = MACH_PORT_NULL;
}
CFAllocatorDeallocate(NULL, sessionPrivate);
*session = NULL;
(void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldThreadState);
pthread_testcancel();
return scd_status;
}