2 * Copyright (c) 2000-2006, 2008-2018 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 "SCDynamicStoreInternal.h"
44 #include "config.h" /* MiG generated file */
47 static CFStringRef _sc_bundleID
= NULL
;
48 static pthread_mutex_t _sc_lock
= PTHREAD_MUTEX_INITIALIZER
;
49 static mach_port_t _sc_server
= MACH_PORT_NULL
;
52 static const char *notifyType
[] = {
64 __private_extern__ os_log_t
65 __log_SCDynamicStore(void)
67 static os_log_t log
= NULL
;
70 log
= os_log_create("com.apple.SystemConfiguration", "SCDynamicStore");
78 __SCDynamicStoreCopyDescription(CFTypeRef cf
) {
79 CFAllocatorRef allocator
= CFGetAllocator(cf
);
80 CFMutableStringRef result
;
81 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)cf
;
83 result
= CFStringCreateMutable(allocator
, 0);
84 CFStringAppendFormat(result
, NULL
, CFSTR("<SCDynamicStore %p [%p]> {"), cf
, allocator
);
85 if (storePrivate
->server
!= MACH_PORT_NULL
) {
86 CFStringAppendFormat(result
, NULL
, CFSTR("server port = 0x%x"), storePrivate
->server
);
88 CFStringAppendFormat(result
, NULL
, CFSTR("server not (no longer) available"));
90 if (storePrivate
->disconnectFunction
!= NULL
) {
91 CFStringAppendFormat(result
, NULL
, CFSTR(", disconnect = %p"), storePrivate
->disconnectFunction
);
93 switch (storePrivate
->notifyStatus
) {
94 case Using_NotifierWait
:
95 CFStringAppendFormat(result
, NULL
, CFSTR(", waiting for a notification"));
97 case Using_NotifierInformViaMachPort
:
98 CFStringAppendFormat(result
, NULL
, CFSTR(", mach port notifications"));
100 case Using_NotifierInformViaFD
:
101 CFStringAppendFormat(result
, NULL
, CFSTR(", FD notifications"));
103 case Using_NotifierInformViaSignal
:
104 CFStringAppendFormat(result
, NULL
, CFSTR(", BSD signal notifications"));
106 case Using_NotifierInformViaRunLoop
:
107 case Using_NotifierInformViaDispatch
:
108 if (storePrivate
->notifyStatus
== Using_NotifierInformViaRunLoop
) {
109 CFStringAppendFormat(result
, NULL
, CFSTR(", runloop notifications"));
110 CFStringAppendFormat(result
, NULL
, CFSTR(" {callout = %p"), storePrivate
->rlsFunction
);
111 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->rlsContext
.info
);
112 CFStringAppendFormat(result
, NULL
, CFSTR(", rls = %p"), storePrivate
->rls
);
113 } else if (storePrivate
->notifyStatus
== Using_NotifierInformViaDispatch
) {
114 CFStringAppendFormat(result
, NULL
, CFSTR(", dispatch notifications"));
115 CFStringAppendFormat(result
, NULL
, CFSTR(" {callout = %p"), storePrivate
->rlsFunction
);
116 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->rlsContext
.info
);
117 CFStringAppendFormat(result
, NULL
, CFSTR(", queue = %p"), storePrivate
->dispatchQueue
);
118 CFStringAppendFormat(result
, NULL
, CFSTR(", source = %p"), storePrivate
->dispatchSource
);
120 if (storePrivate
->rlsNotifyRLS
!= NULL
) {
121 CFStringAppendFormat(result
, NULL
, CFSTR(", notify rls = %@" ), storePrivate
->rlsNotifyRLS
);
123 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
126 CFStringAppendFormat(result
, NULL
, CFSTR(", notification delivery not requested%s"),
127 storePrivate
->rlsFunction
? " (yet)" : "");
130 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
137 __SCDynamicStoreDeallocate(CFTypeRef cf
)
140 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
141 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
143 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED
, &oldThreadState
);
145 /* Remove/cancel any outstanding notification requests. */
146 (void) SCDynamicStoreNotifyCancel(store
);
148 if (storePrivate
->server
!= MACH_PORT_NULL
) {
150 * Remove our send right to the SCDynamicStore server.
152 * In the case of a "real" session this will result in our
153 * session being closed.
155 * In the case of a "NULL" session, we just remove the
156 * the send right reference we are holding.
158 __MACH_PORT_DEBUG(TRUE
, "*** __SCDynamicStoreDeallocate", storePrivate
->server
);
159 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
160 storePrivate
->server
= MACH_PORT_NULL
;
163 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, &oldThreadState
);
164 pthread_testcancel();
166 /* release any callback context info */
167 if (storePrivate
->rlsContext
.release
!= NULL
) {
168 (*storePrivate
->rlsContext
.release
)(storePrivate
->rlsContext
.info
);
171 /* release any keys being watched */
172 if (storePrivate
->keys
!= NULL
) CFRelease(storePrivate
->keys
);
173 if (storePrivate
->patterns
!= NULL
) CFRelease(storePrivate
->patterns
);
175 /* release any client info */
176 if (storePrivate
->name
!= NULL
) CFRelease(storePrivate
->name
);
177 if (storePrivate
->options
!= NULL
) CFRelease(storePrivate
->options
);
179 #ifdef VERBOSE_ACTIVITY_LOGGING
180 /* release activity tracing */
181 if (storePrivate
->activity
!= NULL
) os_release(storePrivate
->activity
);
182 #endif // VERBOSE_ACTIVITY_LOGGING
188 static CFTypeID __kSCDynamicStoreTypeID
= _kCFRuntimeNotATypeID
;
191 static const CFRuntimeClass __SCDynamicStoreClass
= {
193 "SCDynamicStore", // className
196 __SCDynamicStoreDeallocate
, // dealloc
199 NULL
, // copyFormattingDesc
200 __SCDynamicStoreCopyDescription
// copyDebugDesc
207 /* the process has forked (and we are the child process) */
209 _sc_server
= MACH_PORT_NULL
;
214 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
217 __SCDynamicStoreInitialize(void)
221 /* register with CoreFoundation */
222 __kSCDynamicStoreTypeID
= _CFRuntimeRegisterClass(&__SCDynamicStoreClass
);
224 /* add handler to cleanup after fork() */
225 (void) pthread_atfork(NULL
, NULL
, childForkHandler
);
227 /* get the application/executable/bundle name */
228 bundle
= CFBundleGetMainBundle();
229 if (bundle
!= NULL
) {
230 _sc_bundleID
= CFBundleGetIdentifier(bundle
);
231 if (_sc_bundleID
!= NULL
) {
232 CFRetain(_sc_bundleID
);
236 url
= CFBundleCopyExecutableURL(bundle
);
238 _sc_bundleID
= CFURLCopyPath(url
);
243 if (_sc_bundleID
!= NULL
) {
244 if (CFEqual(_sc_bundleID
, CFSTR("/"))) {
245 CFRelease(_sc_bundleID
);
246 _sc_bundleID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("(%d)"), getpid());
256 __SCDynamicStoreServerPort(SCDynamicStorePrivateRef storePrivate
, kern_return_t
*status
)
258 #pragma unused(storePrivate)
259 mach_port_t server
= MACH_PORT_NULL
;
262 server_name
= getenv("SCD_SERVER");
266 * only allow the SCDynamicStore server bootstrap name to be changed with
267 * DEBUG builds. For RELEASE builds, assume that no server is available.
269 if (server_name
!= NULL
) {
270 *status
= BOOTSTRAP_UNKNOWN_SERVICE
;
271 return MACH_PORT_NULL
;
276 if (server_name
== NULL
) {
277 server_name
= SCD_SERVER
;
280 #if defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR
281 *status
= bootstrap_look_up2(bootstrap_port
,
285 BOOTSTRAP_PRIVILEGED_SERVER
);
286 #else // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR
287 *status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
288 #endif // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR
291 case BOOTSTRAP_SUCCESS
:
292 /* service currently registered, "a good thing" (tm) */
294 case BOOTSTRAP_NOT_PRIVILEGED
:
295 /* the service is not privileged */
297 case BOOTSTRAP_UNKNOWN_SERVICE
:
298 /* service not currently registered, try again later */
302 SC_log(LOG_INFO
, "bootstrap_look_up() failed: status=%s",
303 bootstrap_strerror(*status
));
308 return MACH_PORT_NULL
;
312 SCDynamicStorePrivateRef
313 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator
,
314 const CFStringRef name
,
315 SCDynamicStoreCallBack callout
,
316 SCDynamicStoreContext
*context
)
319 SCDynamicStorePrivateRef storePrivate
;
321 /* initialize runtime */
322 pthread_once(&initialized
, __SCDynamicStoreInitialize
);
324 /* allocate session */
325 size
= sizeof(SCDynamicStorePrivate
) - sizeof(CFRuntimeBase
);
326 storePrivate
= (SCDynamicStorePrivateRef
)_CFRuntimeCreateInstance(allocator
,
327 __kSCDynamicStoreTypeID
,
330 if (storePrivate
== NULL
) {
331 _SCErrorSet(kSCStatusFailed
);
335 /* initialize non-zero/NULL members */
337 /* client side of the "configd" session */
338 storePrivate
->name
= (name
!= NULL
) ? CFRetain(name
) : NULL
;
340 #ifdef VERBOSE_ACTIVITY_LOGGING
341 /* "client" activity tracing */
342 storePrivate
->activity
= os_activity_create("accessing SCDynamicStore",
344 OS_ACTIVITY_FLAG_DEFAULT
);
345 #endif // VERBOSE_ACTIVITY_LOGGING
347 /* Notification status */
348 storePrivate
->notifyStatus
= NotifierNotRegistered
;
350 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
351 storePrivate
->rlsFunction
= callout
;
352 if (context
!= NULL
) {
353 bcopy(context
, &storePrivate
->rlsContext
, sizeof(SCDynamicStoreContext
));
354 if (context
->retain
!= NULL
) {
355 storePrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
359 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
360 storePrivate
->notifyFile
= -1;
367 updateServerPort(SCDynamicStorePrivateRef storePrivate
, mach_port_t
*server
, int *sc_status_p
)
369 pthread_mutex_lock(&_sc_lock
);
370 if (_sc_server
!= MACH_PORT_NULL
) {
371 if (*server
== _sc_server
) {
372 mach_port_t old_port
;
374 // if the server we tried returned the error, save the old port,
375 // [re-]lookup the name to the server, and deallocate the original
376 // send [or dead name] right
378 old_port
= _sc_server
;
379 _sc_server
= __SCDynamicStoreServerPort(storePrivate
, sc_status_p
);
380 (void)mach_port_deallocate(mach_task_self(), old_port
);
382 // another thread has refreshed the [main] SCDynamicStore server port
385 _sc_server
= __SCDynamicStoreServerPort(storePrivate
, sc_status_p
);
387 *server
= _sc_server
;
388 pthread_mutex_unlock(&_sc_lock
);
395 __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate
)
397 #ifdef VERBOSE_ACTIVITY_LOGGING
398 struct os_activity_scope_state_s activity_state
;
399 #endif // VERBOSE_ACTIVITY_LOGGING
400 kern_return_t kr
= KERN_SUCCESS
;
401 CFDataRef myName
; /* serialized name */
404 CFDataRef myOptions
= NULL
; /* serialized options */
405 xmlData_t myOptionsRef
= NULL
;
406 CFIndex myOptionsLen
= 0;
407 int sc_status
= kSCStatusFailed
;
410 if (!_SCSerializeString(storePrivate
->name
, &myName
, (void **)&myNameRef
, &myNameLen
)) {
414 /* serialize the options */
415 if (storePrivate
->options
!= NULL
) {
416 if (!_SCSerialize(storePrivate
->options
, &myOptions
, (void **)&myOptionsRef
, &myOptionsLen
)) {
422 /* open a new session with the server */
423 server
= MACH_PORT_NULL
;
426 updateServerPort(storePrivate
, &server
, &sc_status
);
429 #ifdef VERBOSE_ACTIVITY_LOGGING
430 os_activity_scope_enter(storePrivate
->activity
, &activity_state
);
431 #endif // VERBOSE_ACTIVITY_LOGGING
433 while (server
!= MACH_PORT_NULL
) {
434 // if SCDynamicStore server available
436 if (!storePrivate
->serverNullSession
) {
437 // if SCDynamicStore session
438 kr
= configopen(server
,
440 (mach_msg_type_number_t
)myNameLen
,
442 (mach_msg_type_number_t
)myOptionsLen
,
443 &storePrivate
->server
,
447 if (storePrivate
->server
== MACH_PORT_NULL
) {
448 // use the [main] SCDynamicStore server port
449 kr
= mach_port_mod_refs(mach_task_self(), server
, MACH_PORT_RIGHT_SEND
, +1);
450 if (kr
== KERN_SUCCESS
) {
451 storePrivate
->server
= server
;
452 sc_status
= kSCStatusOK
;
454 if (kr
== KERN_INVALID_RIGHT
) {
455 // We can get KERN_INVALID_RIGHT if the server dies and we try to
456 // add a send right to a stale (now dead) port name
457 kr
= MACH_SEND_INVALID_DEST
;
459 storePrivate
->server
= MACH_PORT_NULL
;
462 // if the server port we used returned an error
463 storePrivate
->server
= MACH_PORT_NULL
;
464 kr
= MACH_SEND_INVALID_DEST
;
468 if (kr
== KERN_SUCCESS
) {
472 // our [cached] server port is not valid
473 if ((kr
!= MACH_SEND_INVALID_DEST
) && (kr
!= MIG_SERVER_DIED
)) {
474 // if we got an unexpected error, don't retry
480 updateServerPort(storePrivate
, &server
, &sc_status
);
482 __MACH_PORT_DEBUG(TRUE
, "*** SCDynamicStoreAddSession", storePrivate
->server
);
484 #ifdef VERBOSE_ACTIVITY_LOGGING
485 os_activity_scope_leave(&activity_state
);
486 #endif // VERBOSE_ACTIVITY_LOGGING
490 if (myOptions
!= NULL
) CFRelease(myOptions
);
497 case BOOTSTRAP_UNKNOWN_SERVICE
:
498 SC_log((kr
== KERN_SUCCESS
) ? LOG_INFO
: LOG_ERR
, "SCDynamicStore server not available");
499 sc_status
= kSCStatusNoStoreServer
;
502 SC_log((kr
== KERN_SUCCESS
) ? LOG_INFO
: LOG_ERR
, "configopen() failed: %d: %s",
504 SCErrorString(sc_status
));
508 _SCErrorSet(sc_status
);
515 __SCDynamicStoreNullSession(void)
517 SCDynamicStorePrivateRef storePrivate
;
519 __SCThreadSpecificDataRef tsd
;
521 tsd
= __SCGetThreadSpecificData();
522 if (tsd
->_sc_store
== NULL
) {
523 storePrivate
= __SCDynamicStoreCreatePrivate(NULL
,
524 CFSTR("NULL session"),
527 assert(storePrivate
!= NULL
);
528 storePrivate
->serverNullSession
= TRUE
;
529 tsd
->_sc_store
= (SCDynamicStoreRef
)storePrivate
;
532 storePrivate
= (SCDynamicStorePrivateRef
)tsd
->_sc_store
;
533 if (storePrivate
->server
== MACH_PORT_NULL
) {
534 ok
= __SCDynamicStoreAddSession(storePrivate
);
537 return ok
? tsd
->_sc_store
: NULL
;
542 __SCDynamicStoreReconnect(SCDynamicStoreRef store
)
545 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
547 ok
= __SCDynamicStoreAddSession(storePrivate
);
554 __SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef store
,
555 kern_return_t status
,
559 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
561 if (status
== KERN_SUCCESS
) {
566 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MIG_SERVER_DIED
)) {
567 /* the server's gone, remove the session's dead name right */
568 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
569 storePrivate
->server
= MACH_PORT_NULL
;
572 if (__SCDynamicStoreReconnect(store
)) {
579 /* an unexpected error, leave the [session] port alone */
580 SC_log(LOG_NOTICE
, "%s: %s", log_str
, mach_error_string(status
));
581 storePrivate
->server
= MACH_PORT_NULL
;
590 pushDisconnect(SCDynamicStoreRef store
)
593 void (*context_release
)(const void *);
594 SCDynamicStoreDisconnectCallBack disconnectFunction
;
595 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
597 disconnectFunction
= storePrivate
->disconnectFunction
;
598 if (disconnectFunction
== NULL
) {
599 // if no reconnect callout, push empty notification
600 storePrivate
->disconnectForceCallBack
= TRUE
;
604 if (storePrivate
->rlsContext
.retain
!= NULL
) {
605 context_info
= (void *)storePrivate
->rlsContext
.retain(storePrivate
->rlsContext
.info
);
606 context_release
= storePrivate
->rlsContext
.release
;
608 context_info
= storePrivate
->rlsContext
.info
;
609 context_release
= NULL
;
611 SC_log(LOG_DEBUG
, "exec SCDynamicStore disconnect callout");
612 (*disconnectFunction
)(store
, context_info
);
613 if (context_release
) {
614 context_release(context_info
);
623 __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store
)
625 dispatch_queue_t dispatchQueue
= NULL
;
626 __SCDynamicStoreNotificationStatus notifyStatus
;
628 CFArrayRef rlList
= NULL
;
629 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
631 // save old SCDynamicStore [notification] state
632 notifyStatus
= storePrivate
->notifyStatus
;
634 // before tearing down our [old] notifications, make sure we've
635 // retained any information that will be lost when we cancel the
636 // current no-longer-valid handler
637 switch (notifyStatus
) {
638 case Using_NotifierInformViaRunLoop
:
639 if (storePrivate
->rlList
!= NULL
) {
640 rlList
= CFArrayCreateCopy(NULL
, storePrivate
->rlList
);
643 case Using_NotifierInformViaDispatch
:
644 dispatchQueue
= storePrivate
->dispatchQueue
;
645 if (dispatchQueue
!= NULL
) dispatch_retain(dispatchQueue
);
651 // cancel [old] notifications
652 if (!SCDynamicStoreNotifyCancel(store
)) {
653 // if we could not cancel / reconnect
654 SC_log(LOG_NOTICE
, "SCDynamicStoreNotifyCancel() failed: %s", SCErrorString(SCError()));
657 // set notification keys & patterns
658 if ((storePrivate
->keys
!= NULL
) || (storePrivate
->patterns
)) {
659 ok
= SCDynamicStoreSetNotificationKeys(store
,
661 storePrivate
->patterns
);
663 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE
) {
664 SC_log(LOG_NOTICE
, "SCDynamicStoreSetNotificationKeys() failed");
670 switch (notifyStatus
) {
671 case Using_NotifierInformViaRunLoop
: {
674 CFRunLoopSourceRef rls
;
676 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
678 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE
) {
679 SC_log(LOG_NOTICE
, "SCDynamicStoreCreateRunLoopSource() failed");
685 n
= (rlList
!= NULL
) ? CFArrayGetCount(rlList
) : 0;
686 for (i
= 0; i
< n
; i
+= 3) {
687 CFRunLoopRef rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
688 CFStringRef rlMode
= (CFStringRef
) CFArrayGetValueAtIndex(rlList
, i
+2);
690 CFRunLoopAddSource(rl
, rls
, rlMode
);
696 case Using_NotifierInformViaDispatch
:
697 ok
= SCDynamicStoreSetDispatchQueue(store
, dispatchQueue
);
699 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE
) {
700 SC_log(LOG_NOTICE
, "SCDynamicStoreSetDispatchQueue() failed");
707 _SCErrorSet(kSCStatusFailed
);
715 switch (notifyStatus
) {
716 case Using_NotifierInformViaRunLoop
:
717 if (rlList
!= NULL
) CFRelease(rlList
);
719 case Using_NotifierInformViaDispatch
:
720 if (dispatchQueue
!= NULL
) dispatch_release(dispatchQueue
);
727 SC_log(LOG_NOTICE
, "SCDynamicStore server %s, notification (%s) not restored",
728 (SCError() == BOOTSTRAP_UNKNOWN_SERVICE
) ? "shutdown" : "failed",
729 notifyType
[notifyStatus
]);
733 pushDisconnect(store
);
739 const CFStringRef kSCDynamicStoreUseSessionKeys
= CFSTR("UseSessionKeys"); /* CFBoolean */
744 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator
,
746 CFDictionaryRef storeOptions
,
747 SCDynamicStoreCallBack callout
,
748 SCDynamicStoreContext
*context
)
751 SCDynamicStorePrivateRef storePrivate
;
753 // allocate and initialize a new session
754 storePrivate
= __SCDynamicStoreCreatePrivate(allocator
, NULL
, callout
, context
);
755 if (storePrivate
== NULL
) {
760 if (_sc_bundleID
!= NULL
) {
761 storePrivate
->name
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:%@"), _sc_bundleID
, name
);
763 storePrivate
->name
= CFRetain(name
);
768 if (storeOptions
!= NULL
) {
769 storePrivate
->options
= CFRetain(storeOptions
);
772 // establish SCDynamicStore session
773 ok
= __SCDynamicStoreAddSession(storePrivate
);
775 CFRelease(storePrivate
);
779 return (SCDynamicStoreRef
)storePrivate
;
784 SCDynamicStoreCreate(CFAllocatorRef allocator
,
786 SCDynamicStoreCallBack callout
,
787 SCDynamicStoreContext
*context
)
789 return SCDynamicStoreCreateWithOptions(allocator
, name
, NULL
, callout
, context
);
794 SCDynamicStoreGetTypeID(void) {
795 pthread_once(&initialized
, __SCDynamicStoreInitialize
); /* initialize runtime */
796 return __kSCDynamicStoreTypeID
;
801 SCDynamicStoreSetDisconnectCallBack(SCDynamicStoreRef store
,
802 SCDynamicStoreDisconnectCallBack callout
)
804 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
807 /* sorry, you must provide a session */
808 _SCErrorSet(kSCStatusNoStoreSession
);
812 storePrivate
->disconnectFunction
= callout
;