#include <stdlib.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include "SCDynamicStoreInternal.h"
#include "config.h"
static CFStringRef
__SCDynamicStoreCopyDescription(CFTypeRef cf) {
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCDynamicStore %p [%p]> {\n"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__SCDynamicStoreDeallocate(CFTypeRef cf)
{
int oldThreadState;
int sc_status;
kern_return_t status;
SCDynamicStoreRef store = (SCDynamicStoreRef)cf;
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCDynamicStoreDeallocate:"));
(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldThreadState);
(void) SCDynamicStoreNotifyCancel(store);
if (storePrivate->server && storePrivate->locked) {
(void) SCDynamicStoreUnlock(store);
}
if (storePrivate->server != MACH_PORT_NULL) {
status = configclose(storePrivate->server, (int *)&sc_status);
if (status != KERN_SUCCESS) {
if (status != MACH_SEND_INVALID_DEST)
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("configclose(): %s"), mach_error_string(status));
}
(void) mach_port_destroy(mach_task_self(), storePrivate->server);
storePrivate->server = MACH_PORT_NULL;
}
(void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldThreadState);
pthread_testcancel();
if (storePrivate->rlsContext.release) {
storePrivate->rlsContext.release(storePrivate->rlsContext.info);
}
CFRelease(storePrivate->keys);
CFRelease(storePrivate->patterns);
return;
}
static CFTypeID __kSCDynamicStoreTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCDynamicStoreClass = {
0, "SCDynamicStore", NULL, NULL, __SCDynamicStoreDeallocate, NULL, NULL, NULL, __SCDynamicStoreCopyDescription };
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static void
__SCDynamicStoreInitialize(void) {
__kSCDynamicStoreTypeID = _CFRuntimeRegisterClass(&__SCDynamicStoreClass);
return;
}
SCDynamicStorePrivateRef
__SCDynamicStoreCreatePrivate(CFAllocatorRef allocator,
const CFStringRef name,
SCDynamicStoreCallBack callout,
SCDynamicStoreContext *context)
{
uint32_t size;
SCDynamicStorePrivateRef storePrivate;
pthread_once(&initialized, __SCDynamicStoreInitialize);
size = sizeof(SCDynamicStorePrivate) - sizeof(CFRuntimeBase);
storePrivate = (SCDynamicStorePrivateRef)_CFRuntimeCreateInstance(allocator,
__kSCDynamicStoreTypeID,
size,
NULL);
if (!storePrivate) {
return NULL;
}
storePrivate->server = MACH_PORT_NULL;
storePrivate->locked = FALSE;
storePrivate->notifyStatus = NotifierNotRegistered;
storePrivate->rlsRefs = 0;
storePrivate->rls = NULL;
storePrivate->rlsFunction = callout;
storePrivate->rlsContext.info = NULL;
storePrivate->rlsContext.retain = NULL;
storePrivate->rlsContext.release = NULL;
storePrivate->rlsContext.copyDescription = NULL;
if (context) {
bcopy(context, &storePrivate->rlsContext, sizeof(SCDynamicStoreContext));
if (context->retain) {
storePrivate->rlsContext.info = (void *)context->retain(context->info);
}
}
storePrivate->callbackFunction = NULL;
storePrivate->callbackArgument = NULL;
storePrivate->callbackPort = NULL;
storePrivate->callbackRunLoop = NULL;
storePrivate->callbackRunLoopSource = NULL;
storePrivate->keys = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
storePrivate->patterns = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
storePrivate->notifyPort = MACH_PORT_NULL;
storePrivate->notifyPortIdentifier = 0;
storePrivate->notifyFile = -1;
storePrivate->notifyFileIdentifier = 0;
storePrivate->notifySignal = 0;
storePrivate->notifySignalTask = TASK_NULL;
return storePrivate;
}
SCDynamicStoreRef
SCDynamicStoreCreate(CFAllocatorRef allocator,
CFStringRef name,
SCDynamicStoreCallBack callout,
SCDynamicStoreContext *context)
{
SCDynamicStorePrivateRef storePrivate;
kern_return_t status;
mach_port_t bootstrap_port;
CFBundleRef bundle;
CFStringRef bundleID = NULL;
mach_port_t server;
char *server_name;
CFDataRef utfName;
xmlData_t myNameRef;
CFIndex myNameLen;
int sc_status;
if (_sc_verbose) {
SCLog(TRUE, LOG_DEBUG, CFSTR("SCDynamicStoreCreate:"));
SCLog(TRUE, LOG_DEBUG, CFSTR(" name = %@"), name);
}
storePrivate = __SCDynamicStoreCreatePrivate(allocator, name, callout, context);
status = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
if (status != KERN_SUCCESS) {
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("task_get_bootstrap_port(): %s"), mach_error_string(status));
CFRelease(storePrivate);
_SCErrorSet(status);
return NULL;
}
server_name = getenv("SCD_SERVER");
if (!server_name) {
server_name = SCD_SERVER;
}
status = bootstrap_look_up(bootstrap_port, server_name, &server);
switch (status) {
case BOOTSTRAP_SUCCESS :
break;
case BOOTSTRAP_UNKNOWN_SERVICE :
CFRelease(storePrivate);
_SCErrorSet(status);
return NULL;
break;
default :
#ifdef DEBUG
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("bootstrap_look_up() failed: status=%d"), status);
#endif
CFRelease(storePrivate);
_SCErrorSet(status);
return NULL;
}
bundle = CFBundleGetMainBundle();
if (bundle) {
bundleID = CFBundleGetIdentifier(bundle);
if (bundleID) {
CFRetain(bundleID);
} else {
CFURLRef url;
url = CFBundleCopyExecutableURL(bundle);
if (url) {
bundleID = CFURLCopyPath(url);
CFRelease(url);
}
}
}
if (bundleID) {
CFStringRef fullName;
if (CFEqual(bundleID, CFSTR("/"))) {
CFRelease(bundleID);
bundleID = CFStringCreateWithFormat(NULL, NULL, CFSTR("(%d)"), getpid());
}
fullName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"), bundleID, name);
name = fullName;
CFRelease(bundleID);
} else {
CFRetain(name);
}
if (!_SCSerializeString(name, &utfName, (void **)&myNameRef, &myNameLen)) {
CFRelease(name);
_SCErrorSet(kSCStatusFailed);
return NULL;
}
CFRelease(name);
status = configopen(server, myNameRef, myNameLen, &storePrivate->server, (int *)&sc_status);
CFRelease(utfName);
if (status != KERN_SUCCESS) {
if (status != MACH_SEND_INVALID_DEST)
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("configopen(): %s"), mach_error_string(status));
CFRelease(storePrivate);
_SCErrorSet(status);
return NULL;
}
if (sc_status != kSCStatusOK) {
CFRelease(storePrivate);
_SCErrorSet(sc_status);
return NULL;
}
SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" server port = %d"), storePrivate->server);
return (SCDynamicStoreRef)storePrivate;
}
CFTypeID
SCDynamicStoreGetTypeID(void) {
pthread_once(&initialized, __SCDynamicStoreInitialize);
return __kSCDynamicStoreTypeID;
}