2 * Copyright (c) 2000-2006, 2008-2013 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
34 #include <TargetConditionals.h>
37 #include <sys/types.h>
38 #include <mach/mach.h>
39 #include <mach/mach_error.h>
40 #include <servers/bootstrap.h>
41 #include <bootstrap_priv.h>
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h>
46 #include "SCDynamicStoreInternal.h"
47 #include "config.h" /* MiG generated file */
50 static CFStringRef _sc_bundleID
= NULL
;
51 static pthread_mutex_t _sc_lock
= PTHREAD_MUTEX_INITIALIZER
;
52 static mach_port_t _sc_server
= MACH_PORT_NULL
;
55 static const char *notifyType
[] = {
68 __SCDynamicStoreCopyDescription(CFTypeRef cf
) {
69 CFAllocatorRef allocator
= CFGetAllocator(cf
);
70 CFMutableStringRef result
;
71 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)cf
;
73 result
= CFStringCreateMutable(allocator
, 0);
74 CFStringAppendFormat(result
, NULL
, CFSTR("<SCDynamicStore %p [%p]> {"), cf
, allocator
);
75 if (storePrivate
->server
!= MACH_PORT_NULL
) {
76 CFStringAppendFormat(result
, NULL
, CFSTR("server port = 0x%x"), storePrivate
->server
);
78 CFStringAppendFormat(result
, NULL
, CFSTR("server not (no longer) available"));
80 if (storePrivate
->disconnectFunction
!= NULL
) {
81 CFStringAppendFormat(result
, NULL
, CFSTR(", disconnect = %p"), storePrivate
->disconnectFunction
);
83 switch (storePrivate
->notifyStatus
) {
84 case Using_NotifierWait
:
85 CFStringAppendFormat(result
, NULL
, CFSTR(", waiting for a notification"));
87 case Using_NotifierInformViaMachPort
:
88 CFStringAppendFormat(result
, NULL
, CFSTR(", mach port notifications"));
90 case Using_NotifierInformViaFD
:
91 CFStringAppendFormat(result
, NULL
, CFSTR(", FD notifications"));
93 case Using_NotifierInformViaSignal
:
94 CFStringAppendFormat(result
, NULL
, CFSTR(", BSD signal notifications"));
96 case Using_NotifierInformViaRunLoop
:
97 case Using_NotifierInformViaDispatch
:
98 if (storePrivate
->notifyStatus
== Using_NotifierInformViaRunLoop
) {
99 CFStringAppendFormat(result
, NULL
, CFSTR(", runloop notifications"));
100 CFStringAppendFormat(result
, NULL
, CFSTR(" {callout = %p"), storePrivate
->rlsFunction
);
101 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->rlsContext
.info
);
102 CFStringAppendFormat(result
, NULL
, CFSTR(", rls = %p"), storePrivate
->rls
);
103 } else if (storePrivate
->notifyStatus
== Using_NotifierInformViaDispatch
) {
104 CFStringAppendFormat(result
, NULL
, CFSTR(", dispatch notifications"));
105 CFStringAppendFormat(result
, NULL
, CFSTR(" {callout = %p"), storePrivate
->rlsFunction
);
106 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->rlsContext
.info
);
107 CFStringAppendFormat(result
, NULL
, CFSTR(", queue = %p"), storePrivate
->dispatchQueue
);
108 CFStringAppendFormat(result
, NULL
, CFSTR(", source = %p"), storePrivate
->dispatchSource
);
110 if (storePrivate
->rlsNotifyRLS
!= NULL
) {
111 CFStringAppendFormat(result
, NULL
, CFSTR(", notify rls = %@" ), storePrivate
->rlsNotifyRLS
);
113 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
116 CFStringAppendFormat(result
, NULL
, CFSTR(", notification delivery not requested%s"),
117 storePrivate
->rlsFunction
? " (yet)" : "");
120 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
127 __SCDynamicStoreDeallocate(CFTypeRef cf
)
130 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
131 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
133 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED
, &oldThreadState
);
135 /* Remove/cancel any outstanding notification requests. */
136 (void) SCDynamicStoreNotifyCancel(store
);
138 if (storePrivate
->server
!= MACH_PORT_NULL
) {
139 if (!storePrivate
->serverNullSession
) {
141 * Remove our send right to the SCDynamicStore server (and that will
142 * result in our session being closed).
144 __MACH_PORT_DEBUG(TRUE
, "*** __SCDynamicStoreDeallocate", storePrivate
->server
);
145 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
148 storePrivate
->server
= MACH_PORT_NULL
;
151 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, &oldThreadState
);
152 pthread_testcancel();
154 /* release any callback context info */
155 if (storePrivate
->rlsContext
.release
!= NULL
) {
156 (*storePrivate
->rlsContext
.release
)(storePrivate
->rlsContext
.info
);
159 /* release any keys being watched */
160 if (storePrivate
->keys
!= NULL
) CFRelease(storePrivate
->keys
);
161 if (storePrivate
->patterns
!= NULL
) CFRelease(storePrivate
->patterns
);
163 /* release any client info */
164 if (storePrivate
->name
!= NULL
) CFRelease(storePrivate
->name
);
165 if (storePrivate
->options
!= NULL
) CFRelease(storePrivate
->options
);
171 static CFTypeID __kSCDynamicStoreTypeID
= _kCFRuntimeNotATypeID
;
174 static const CFRuntimeClass __SCDynamicStoreClass
= {
176 "SCDynamicStore", // className
179 __SCDynamicStoreDeallocate
, // dealloc
182 NULL
, // copyFormattingDesc
183 __SCDynamicStoreCopyDescription
// copyDebugDesc
190 /* the process has forked (and we are the child process) */
192 _sc_server
= MACH_PORT_NULL
;
197 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
200 __SCDynamicStoreInitialize(void)
204 /* register with CoreFoundation */
205 __kSCDynamicStoreTypeID
= _CFRuntimeRegisterClass(&__SCDynamicStoreClass
);
207 /* add handler to cleanup after fork() */
208 (void) pthread_atfork(NULL
, NULL
, childForkHandler
);
210 /* get the application/executable/bundle name */
211 bundle
= CFBundleGetMainBundle();
212 if (bundle
!= NULL
) {
213 _sc_bundleID
= CFBundleGetIdentifier(bundle
);
214 if (_sc_bundleID
!= NULL
) {
215 CFRetain(_sc_bundleID
);
219 url
= CFBundleCopyExecutableURL(bundle
);
221 _sc_bundleID
= CFURLCopyPath(url
);
226 if (_sc_bundleID
!= NULL
) {
227 if (CFEqual(_sc_bundleID
, CFSTR("/"))) {
228 CFRelease(_sc_bundleID
);
229 _sc_bundleID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("(%d)"), getpid());
239 __SCDynamicStoreServerPort(SCDynamicStorePrivateRef storePrivate
, kern_return_t
*status
)
241 mach_port_t server
= MACH_PORT_NULL
;
244 server_name
= getenv("SCD_SERVER");
247 if (server_name
== NULL
) {
248 server_name
= SCD_SERVER
;
251 #if defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_IPHONE_SIMULATOR
252 *status
= bootstrap_look_up2(bootstrap_port
,
256 BOOTSTRAP_PRIVILEGED_SERVER
);
257 #else // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_IPHONE_SIMULATOR
258 *status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
259 #endif // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_IPHONE_SIMULATOR
262 case BOOTSTRAP_SUCCESS
:
263 /* service currently registered, "a good thing" (tm) */
265 case BOOTSTRAP_NOT_PRIVILEGED
:
266 /* the service is not privileged */
268 case BOOTSTRAP_UNKNOWN_SERVICE
:
269 /* service not currently registered, try again later */
273 SCLog(_sc_verbose
, LOG_DEBUG
,
274 CFSTR("SCDynamicStoreCreate[WithOptions] bootstrap_look_up() failed: status=%s"),
275 bootstrap_strerror(*status
));
280 return MACH_PORT_NULL
;
284 SCDynamicStorePrivateRef
285 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator
,
286 const CFStringRef name
,
287 SCDynamicStoreCallBack callout
,
288 SCDynamicStoreContext
*context
)
291 SCDynamicStorePrivateRef storePrivate
;
293 /* initialize runtime */
294 pthread_once(&initialized
, __SCDynamicStoreInitialize
);
297 /* allocate session */
298 size
= sizeof(SCDynamicStorePrivate
) - sizeof(CFRuntimeBase
);
299 storePrivate
= (SCDynamicStorePrivateRef
)_CFRuntimeCreateInstance(allocator
,
300 __kSCDynamicStoreTypeID
,
303 if (storePrivate
== NULL
) {
304 _SCErrorSet(kSCStatusFailed
);
308 /* client side of the "configd" session */
309 storePrivate
->name
= (name
!= NULL
) ? CFRetain(name
) : NULL
;
310 storePrivate
->options
= NULL
;
312 /* server side of the "configd" session */
313 storePrivate
->server
= MACH_PORT_NULL
;
314 storePrivate
->serverNullSession
= FALSE
;
317 storePrivate
->useSessionKeys
= FALSE
;
319 /* Notification status */
320 storePrivate
->notifyStatus
= NotifierNotRegistered
;
322 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
323 storePrivate
->rlList
= NULL
;
324 storePrivate
->rls
= NULL
;
325 storePrivate
->rlsFunction
= callout
;
326 storePrivate
->rlsContext
.info
= NULL
;
327 storePrivate
->rlsContext
.retain
= NULL
;
328 storePrivate
->rlsContext
.release
= NULL
;
329 storePrivate
->rlsContext
.copyDescription
= NULL
;
331 bcopy(context
, &storePrivate
->rlsContext
, sizeof(SCDynamicStoreContext
));
332 if (context
->retain
!= NULL
) {
333 storePrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
336 storePrivate
->rlsNotifyPort
= NULL
;
337 storePrivate
->rlsNotifyRLS
= NULL
;
339 /* "client" information associated with SCDynamicStoreSetDispatchQueue() */
340 storePrivate
->dispatchGroup
= NULL
;
341 storePrivate
->dispatchQueue
= NULL
;
342 storePrivate
->dispatchSource
= NULL
;
344 /* "client" information associated with SCDynamicStoreSetDisconnectCallBack() */
345 storePrivate
->disconnectFunction
= NULL
;
346 storePrivate
->disconnectForceCallBack
= FALSE
;
348 /* "server" information associated with SCDynamicStoreSetNotificationKeys() */
349 storePrivate
->keys
= NULL
;
350 storePrivate
->patterns
= NULL
;
352 /* "server" information associated with SCDynamicStoreNotifyMachPort(); */
353 storePrivate
->notifyPort
= MACH_PORT_NULL
;
354 storePrivate
->notifyPortIdentifier
= 0;
356 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
357 storePrivate
->notifyFile
= -1;
358 storePrivate
->notifyFileIdentifier
= 0;
360 /* "server" information associated with SCDynamicStoreNotifySignal(); */
361 storePrivate
->notifySignal
= 0;
362 storePrivate
->notifySignalTask
= TASK_NULL
;
369 updateServerPort(SCDynamicStorePrivateRef storePrivate
, mach_port_t
*server
, int *sc_status_p
)
371 pthread_mutex_lock(&_sc_lock
);
372 if (_sc_server
!= MACH_PORT_NULL
) {
373 if (*server
== _sc_server
) {
374 // if the server we tried returned the error, deallocate
375 // our send [or dead name] right
376 (void)mach_port_deallocate(mach_task_self(), _sc_server
);
378 // and [re-]lookup the name to the server
379 _sc_server
= __SCDynamicStoreServerPort(storePrivate
, sc_status_p
);
381 // another thread has refreshed the SCDynamicStore server port
384 _sc_server
= __SCDynamicStoreServerPort(storePrivate
, sc_status_p
);
386 *server
= _sc_server
;
387 pthread_mutex_unlock(&_sc_lock
);
394 __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate
)
396 CFDataRef myName
; /* serialized name */
399 CFDataRef myOptions
= NULL
; /* serialized options */
400 xmlData_t myOptionsRef
= NULL
;
401 CFIndex myOptionsLen
= 0;
402 int sc_status
= kSCStatusFailed
;
404 kern_return_t status
= KERN_SUCCESS
;
406 if (!_SCSerializeString(storePrivate
->name
, &myName
, (void **)&myNameRef
, &myNameLen
)) {
410 /* serialize the options */
411 if (storePrivate
->options
!= NULL
) {
412 if (!_SCSerialize(storePrivate
->options
, &myOptions
, (void **)&myOptionsRef
, &myOptionsLen
)) {
418 /* open a new session with the server */
422 updateServerPort(storePrivate
, &server
, &sc_status
);
426 if (server
!= MACH_PORT_NULL
) {
427 if (!storePrivate
->serverNullSession
) {
428 // if SCDynamicStore session
429 status
= configopen(server
,
434 &storePrivate
->server
,
438 if (storePrivate
->server
== MACH_PORT_NULL
) {
439 // use the [main] SCDynamicStore server port
440 storePrivate
->server
= server
;
441 sc_status
= kSCStatusOK
;
442 status
= KERN_SUCCESS
;
444 // if the server port we used returned an error
445 storePrivate
->server
= MACH_PORT_NULL
;
446 status
= MACH_SEND_INVALID_DEST
;
450 if (status
== KERN_SUCCESS
) {
454 // our [cached] server port is not valid
455 if ((status
!= MACH_SEND_INVALID_DEST
) && (status
!= MIG_SERVER_DIED
)) {
456 // if we got an unexpected error, don't retry
463 updateServerPort(storePrivate
, &server
, &sc_status
);
465 if (server
== MACH_PORT_NULL
) {
466 // if SCDynamicStore server not available
470 __MACH_PORT_DEBUG(TRUE
, "*** SCDynamicStoreAddSession", storePrivate
->server
);
474 if (myOptions
!= NULL
) CFRelease(myOptions
);
481 case BOOTSTRAP_UNKNOWN_SERVICE
:
483 (status
== KERN_SUCCESS
) ? LOG_DEBUG
: LOG_ERR
,
484 CFSTR("SCDynamicStore server not available"));
485 sc_status
= kSCStatusNoStoreServer
;
489 (status
== KERN_SUCCESS
) ? LOG_DEBUG
: LOG_ERR
,
490 CFSTR("SCDynamicStoreAddSession configopen(): %s"),
491 SCErrorString(sc_status
));
495 _SCErrorSet(sc_status
);
502 __SCDynamicStoreNullSession(void)
504 SCDynamicStorePrivateRef storePrivate
;
506 __SCThreadSpecificDataRef tsd
;
508 tsd
= __SCGetThreadSpecificData();
509 if (tsd
->_sc_store
== NULL
) {
510 #if !TARGET_IPHONE_SIMULATOR
511 storePrivate
= __SCDynamicStoreCreatePrivate(NULL
,
512 CFSTR("NULL session"),
515 assert(storePrivate
!= NULL
);
516 storePrivate
->server
= _sc_server
;
517 storePrivate
->serverNullSession
= TRUE
;
520 * In the simulator, this code may be talking to an older version of
521 * configd that still requires a valid session. Instead of using a
522 * "NULL" session that uses the server mach port, set up a "normal"
523 * session in thread-local storage.
525 storePrivate
= __SCDynamicStoreCreatePrivate(NULL
,
526 CFSTR("Thread local session"),
529 assert(storePrivate
!= NULL
);
531 * Use MACH_PORT_NULL here to trigger the call to
532 * __SCDynamicStoreAddSession below.
534 storePrivate
->server
= MACH_PORT_NULL
;
535 #endif /* TARGET_IPHONE_SIMULATOR */
536 tsd
->_sc_store
= (SCDynamicStoreRef
)storePrivate
;
539 storePrivate
= (SCDynamicStorePrivateRef
)tsd
->_sc_store
;
540 if (storePrivate
->server
== MACH_PORT_NULL
) {
541 ok
= __SCDynamicStoreAddSession(storePrivate
);
544 return ok
? tsd
->_sc_store
: NULL
;
549 __SCDynamicStoreReconnect(SCDynamicStoreRef store
)
552 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
554 ok
= __SCDynamicStoreAddSession(storePrivate
);
561 __SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef store
,
562 kern_return_t status
,
566 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
568 if (status
== KERN_SUCCESS
) {
573 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
574 /* the server's gone */
575 if (!storePrivate
->serverNullSession
) {
577 * remove the session's dead name right (and not the
578 * not the "server" port)
580 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
582 storePrivate
->server
= MACH_PORT_NULL
;
585 if (__SCDynamicStoreReconnect(store
)) {
590 /* an unexpected error, leave the [session] port alone */
591 SCLog(TRUE
, LOG_ERR
, CFSTR("%s: %s"), log_str
, mach_error_string(status
));
592 storePrivate
->server
= MACH_PORT_NULL
;
601 pushDisconnect(SCDynamicStoreRef store
)
604 void (*context_release
)(const void *);
605 SCDynamicStoreDisconnectCallBack disconnectFunction
;
606 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
608 disconnectFunction
= storePrivate
->disconnectFunction
;
609 if (disconnectFunction
== NULL
) {
610 // if no reconnect callout, push empty notification
611 storePrivate
->disconnectForceCallBack
= TRUE
;
615 if (storePrivate
->rlsContext
.retain
!= NULL
) {
616 context_info
= (void *)storePrivate
->rlsContext
.retain(storePrivate
->rlsContext
.info
);
617 context_release
= storePrivate
->rlsContext
.release
;
619 context_info
= storePrivate
->rlsContext
.info
;
620 context_release
= NULL
;
622 (*disconnectFunction
)(store
, context_info
);
623 if (context_release
) {
624 context_release(context_info
);
633 __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store
)
635 dispatch_queue_t dispatchQueue
= NULL
;
636 __SCDynamicStoreNotificationStatus notifyStatus
;
638 CFArrayRef rlList
= NULL
;
639 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
641 // save old SCDynamicStore [notification] state
642 notifyStatus
= storePrivate
->notifyStatus
;
644 // before tearing down our [old] notifications, make sure we've
645 // retained any information that will be lost when we cancel the
646 // current no-longer-valid handler
647 switch (notifyStatus
) {
648 case Using_NotifierInformViaRunLoop
:
649 if (storePrivate
->rlList
!= NULL
) {
650 rlList
= CFArrayCreateCopy(NULL
, storePrivate
->rlList
);
652 case Using_NotifierInformViaDispatch
:
653 dispatchQueue
= storePrivate
->dispatchQueue
;
654 if (dispatchQueue
!= NULL
) dispatch_retain(dispatchQueue
);
660 // cancel [old] notifications
661 if (!SCDynamicStoreNotifyCancel(store
)) {
662 // if we could not cancel / reconnect
663 SCLog(TRUE
, LOG_DEBUG
,
664 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreNotifyCancel() failed: %s"),
665 SCErrorString(SCError()));
668 // set notification keys & patterns
669 if ((storePrivate
->keys
!= NULL
) || (storePrivate
->patterns
)) {
670 ok
= SCDynamicStoreSetNotificationKeys(store
,
672 storePrivate
->patterns
);
674 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE
),
676 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetNotificationKeys() failed"));
681 switch (notifyStatus
) {
682 case Using_NotifierInformViaRunLoop
: {
685 CFRunLoopSourceRef rls
;
687 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
689 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE
),
691 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreCreateRunLoopSource() failed"));
696 n
= (rlList
!= NULL
) ? CFArrayGetCount(rlList
) : 0;
697 for (i
= 0; i
< n
; i
+= 3) {
698 CFRunLoopRef rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
699 CFStringRef rlMode
= (CFStringRef
) CFArrayGetValueAtIndex(rlList
, i
+2);
701 CFRunLoopAddSource(rl
, rls
, rlMode
);
707 case Using_NotifierInformViaDispatch
:
708 ok
= SCDynamicStoreSetDispatchQueue(store
, dispatchQueue
);
710 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE
),
712 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetDispatchQueue() failed"));
718 _SCErrorSet(kSCStatusFailed
);
726 switch (notifyStatus
) {
727 case Using_NotifierInformViaRunLoop
:
728 if (rlList
!= NULL
) CFRelease(rlList
);
730 case Using_NotifierInformViaDispatch
:
731 if (dispatchQueue
!= NULL
) dispatch_release(dispatchQueue
);
739 CFSTR("SCDynamicStore server %s, notification (%s) not restored"),
740 (SCError() == BOOTSTRAP_UNKNOWN_SERVICE
) ? "shutdown" : "failed",
741 notifyType
[notifyStatus
]);
745 pushDisconnect(store
);
751 const CFStringRef kSCDynamicStoreUseSessionKeys
= CFSTR("UseSessionKeys"); /* CFBoolean */
756 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator
,
758 CFDictionaryRef storeOptions
,
759 SCDynamicStoreCallBack callout
,
760 SCDynamicStoreContext
*context
)
763 SCDynamicStorePrivateRef storePrivate
;
765 // allocate and initialize a new session
766 storePrivate
= __SCDynamicStoreCreatePrivate(allocator
, NULL
, callout
, context
);
767 if (storePrivate
== NULL
) {
772 if (_sc_bundleID
!= NULL
) {
773 storePrivate
->name
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:%@"), _sc_bundleID
, name
);
775 storePrivate
->name
= CFRetain(name
);
780 if (storeOptions
!= NULL
) {
781 storePrivate
->options
= CFRetain(storeOptions
);
784 // establish SCDynamicStore session
785 ok
= __SCDynamicStoreAddSession(storePrivate
);
787 CFRelease(storePrivate
);
791 return (SCDynamicStoreRef
)storePrivate
;
796 SCDynamicStoreCreate(CFAllocatorRef allocator
,
798 SCDynamicStoreCallBack callout
,
799 SCDynamicStoreContext
*context
)
801 return SCDynamicStoreCreateWithOptions(allocator
, name
, NULL
, callout
, context
);
806 SCDynamicStoreGetTypeID(void) {
807 pthread_once(&initialized
, __SCDynamicStoreInitialize
); /* initialize runtime */
808 return __kSCDynamicStoreTypeID
;
812 SCDynamicStoreSetDisconnectCallBack(SCDynamicStoreRef store
,
813 SCDynamicStoreDisconnectCallBack callout
)
815 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
818 /* sorry, you must provide a session */
819 _SCErrorSet(kSCStatusNoStoreSession
);
823 storePrivate
->disconnectFunction
= callout
;