2 * Copyright (c) 2000-2006, 2008-2019 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
;
50 static unsigned int _sc_store_cnt
= 0;
51 static unsigned int _sc_store_max
= 50; /* complain if SCDynamicStore objects exceeds this [soft-]limit */
54 static const char *notifyType
[] = {
66 _SCDynamicStoreSetSessionWatchLimit(unsigned int limit
)
68 _sc_store_max
= limit
;
73 __private_extern__ os_log_t
74 __log_SCDynamicStore(void)
76 static os_log_t log
= NULL
;
79 log
= os_log_create("com.apple.SystemConfiguration", "SCDynamicStore");
87 __SCDynamicStoreCopyDescription(CFTypeRef cf
) {
88 CFAllocatorRef allocator
= CFGetAllocator(cf
);
89 CFMutableStringRef result
;
90 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)cf
;
92 result
= CFStringCreateMutable(allocator
, 0);
93 CFStringAppendFormat(result
, NULL
, CFSTR("<SCDynamicStore %p [%p]> {"), cf
, allocator
);
94 if (storePrivate
->server
!= MACH_PORT_NULL
) {
95 CFStringAppendFormat(result
, NULL
, CFSTR("server port = 0x%x"), storePrivate
->server
);
97 CFStringAppendFormat(result
, NULL
, CFSTR("server not (no longer) available"));
99 if (storePrivate
->disconnectFunction
!= NULL
) {
100 CFStringAppendFormat(result
, NULL
, CFSTR(", disconnect = %p"), storePrivate
->disconnectFunction
);
102 switch (storePrivate
->notifyStatus
) {
103 case Using_NotifierWait
:
104 CFStringAppendFormat(result
, NULL
, CFSTR(", waiting for a notification"));
106 case Using_NotifierInformViaMachPort
:
107 CFStringAppendFormat(result
, NULL
, CFSTR(", mach port notifications"));
109 case Using_NotifierInformViaFD
:
110 CFStringAppendFormat(result
, NULL
, CFSTR(", FD notifications"));
112 case Using_NotifierInformViaRunLoop
:
113 case Using_NotifierInformViaDispatch
:
114 if (storePrivate
->notifyStatus
== Using_NotifierInformViaRunLoop
) {
115 CFStringAppendFormat(result
, NULL
, CFSTR(", runloop notifications"));
116 CFStringAppendFormat(result
, NULL
, CFSTR(" {callout = %p"), storePrivate
->rlsFunction
);
117 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->rlsContext
.info
);
118 CFStringAppendFormat(result
, NULL
, CFSTR(", rls = %p"), storePrivate
->rls
);
119 CFStringAppendFormat(result
, NULL
, CFSTR(", notify rls = %@" ), storePrivate
->rlsNotifyRLS
);
120 } else if (storePrivate
->notifyStatus
== Using_NotifierInformViaDispatch
) {
121 CFStringAppendFormat(result
, NULL
, CFSTR(", dispatch notifications"));
122 CFStringAppendFormat(result
, NULL
, CFSTR(" {callout = %p"), storePrivate
->rlsFunction
);
123 CFStringAppendFormat(result
, NULL
, CFSTR(", info = %p"), storePrivate
->rlsContext
.info
);
124 CFStringAppendFormat(result
, NULL
, CFSTR(", queue = %p"), storePrivate
->dispatchQueue
);
125 CFStringAppendFormat(result
, NULL
, CFSTR(", source = %p"), storePrivate
->dispatchSource
);
127 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
130 CFStringAppendFormat(result
, NULL
, CFSTR(", notification delivery not requested%s"),
131 storePrivate
->rlsFunction
? " (yet)" : "");
134 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
141 __SCDynamicStoreDeallocate(CFTypeRef cf
)
144 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
145 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
147 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED
, &oldThreadState
);
149 /* Remove/cancel any outstanding notification requests. */
150 (void) SCDynamicStoreNotifyCancel(store
);
152 if (storePrivate
->server
!= MACH_PORT_NULL
) {
154 * Remove our send right to the SCDynamicStore server.
156 * In the case of a "real" session this will result in our
157 * session being closed.
159 * In the case of a "NULL" session, we just remove the
160 * the send right reference we are holding.
162 __MACH_PORT_DEBUG(TRUE
, "*** __SCDynamicStoreDeallocate", storePrivate
->server
);
163 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
164 storePrivate
->server
= MACH_PORT_NULL
;
167 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, &oldThreadState
);
168 pthread_testcancel();
170 /* release any callback context info */
171 if (storePrivate
->rlsContext
.release
!= NULL
) {
172 (*storePrivate
->rlsContext
.release
)(storePrivate
->rlsContext
.info
);
175 /* release any keys being watched */
176 if (storePrivate
->keys
!= NULL
) CFRelease(storePrivate
->keys
);
177 if (storePrivate
->patterns
!= NULL
) CFRelease(storePrivate
->patterns
);
179 /* release any client info */
180 if (storePrivate
->name
!= NULL
) CFRelease(storePrivate
->name
);
181 if (storePrivate
->options
!= NULL
) CFRelease(storePrivate
->options
);
183 /* release any cached content */
184 if (storePrivate
->cache_active
) {
185 _SCDynamicStoreCacheClose(store
);
188 _SC_ATOMIC_DEC(&_sc_store_cnt
);
194 static CFTypeID __kSCDynamicStoreTypeID
= _kCFRuntimeNotATypeID
;
197 static const CFRuntimeClass __SCDynamicStoreClass
= {
199 "SCDynamicStore", // className
202 __SCDynamicStoreDeallocate
, // dealloc
205 NULL
, // copyFormattingDesc
206 __SCDynamicStoreCopyDescription
// copyDebugDesc
213 /* the process has forked (and we are the child process) */
215 _sc_server
= MACH_PORT_NULL
;
220 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
223 __SCDynamicStoreInitialize(void)
227 /* register with CoreFoundation */
228 __kSCDynamicStoreTypeID
= _CFRuntimeRegisterClass(&__SCDynamicStoreClass
);
230 /* add handler to cleanup after fork() */
231 (void) pthread_atfork(NULL
, NULL
, childForkHandler
);
233 /* get the application/executable/bundle name */
234 bundle
= CFBundleGetMainBundle();
235 if (bundle
!= NULL
) {
236 _sc_bundleID
= CFBundleGetIdentifier(bundle
);
237 if (_sc_bundleID
!= NULL
) {
238 CFRetain(_sc_bundleID
);
242 url
= CFBundleCopyExecutableURL(bundle
);
244 _sc_bundleID
= CFURLCopyPath(url
);
249 if (_sc_bundleID
!= NULL
) {
250 if (CFEqual(_sc_bundleID
, CFSTR("/"))) {
251 CFRelease(_sc_bundleID
);
252 _sc_bundleID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("(%d)"), getpid());
262 __SCDynamicStoreServerPort(SCDynamicStorePrivateRef storePrivate
, kern_return_t
*status
)
264 #pragma unused(storePrivate)
265 mach_port_t server
= MACH_PORT_NULL
;
268 server_name
= getenv("SCD_SERVER");
272 * only allow the SCDynamicStore server bootstrap name to be changed with
273 * DEBUG builds. For RELEASE builds, assume that no server is available.
275 if (server_name
!= NULL
) {
276 *status
= BOOTSTRAP_UNKNOWN_SERVICE
;
277 return MACH_PORT_NULL
;
282 if (server_name
== NULL
) {
283 server_name
= SCD_SERVER
;
286 #if defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR
287 *status
= bootstrap_look_up2(bootstrap_port
,
291 BOOTSTRAP_PRIVILEGED_SERVER
);
292 #else // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR
293 *status
= bootstrap_look_up(bootstrap_port
, server_name
, &server
);
294 #endif // defined(BOOTSTRAP_PRIVILEGED_SERVER) && !TARGET_OS_SIMULATOR
297 case BOOTSTRAP_SUCCESS
:
298 /* service currently registered, "a good thing" (tm) */
300 case BOOTSTRAP_NOT_PRIVILEGED
:
301 /* the service is not privileged */
303 case BOOTSTRAP_UNKNOWN_SERVICE
:
304 /* service not currently registered, try again later */
308 SC_log(LOG_INFO
, "bootstrap_look_up() failed: status=%s (%d)",
309 bootstrap_strerror(*status
),
315 return MACH_PORT_NULL
;
319 SCDynamicStorePrivateRef
320 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator
,
321 const CFStringRef name
,
322 SCDynamicStoreCallBack callout
,
323 SCDynamicStoreContext
*context
)
327 SCDynamicStorePrivateRef storePrivate
;
329 /* initialize runtime */
330 pthread_once(&initialized
, __SCDynamicStoreInitialize
);
332 /* allocate session */
333 size
= sizeof(SCDynamicStorePrivate
) - sizeof(CFRuntimeBase
);
334 storePrivate
= (SCDynamicStorePrivateRef
)_CFRuntimeCreateInstance(allocator
,
335 __kSCDynamicStoreTypeID
,
338 if (storePrivate
== NULL
) {
339 _SCErrorSet(kSCStatusFailed
);
343 /* initialize non-zero/NULL members */
345 /* client side of the "configd" session */
346 storePrivate
->name
= (name
!= NULL
) ? CFRetain(name
) : NULL
;
348 /* Notification status */
349 storePrivate
->notifyStatus
= NotifierNotRegistered
;
351 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
352 storePrivate
->rlsFunction
= callout
;
353 if (context
!= NULL
) {
354 memcpy(&storePrivate
->rlsContext
, context
, sizeof(SCDynamicStoreContext
));
355 if (context
->retain
!= NULL
) {
356 storePrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
360 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
361 storePrivate
->notifyFile
= -1;
363 /* watch for excessive SCDynamicStore usage */
364 n
= _SC_ATOMIC_INC(&_sc_store_cnt
);
365 if (n
> _sc_store_max
) {
366 if (_sc_store_max
> 0) {
367 SC_log(LOG_ERR
, "SCDynamicStoreCreate(): number of SCDynamicStore objects now exceeds %u", n
- 1);
368 _sc_store_max
= (_sc_store_max
< 5000) ? (_sc_store_max
* 2) : 0;
369 _SC_crash_once("Excessive number of SCDynamicStore objects", NULL
, NULL
);
378 updateServerPort(SCDynamicStorePrivateRef storePrivate
, mach_port_t
*server
, int *sc_status_p
)
380 mach_port_t old_port
;
382 pthread_mutex_lock(&_sc_lock
);
383 old_port
= _sc_server
;
384 if (_sc_server
!= MACH_PORT_NULL
) {
385 if (*server
== _sc_server
) {
386 // if the server we tried returned the error, save the old port,
387 // [re-]lookup the name to the server, and deallocate the original
388 // send [or dead name] right
389 _sc_server
= __SCDynamicStoreServerPort(storePrivate
, sc_status_p
);
390 (void)mach_port_deallocate(mach_task_self(), old_port
);
392 // another thread has refreshed the [main] SCDynamicStore server port
395 _sc_server
= __SCDynamicStoreServerPort(storePrivate
, sc_status_p
);
398 *server
= _sc_server
;
399 pthread_mutex_unlock(&_sc_lock
);
402 SC_log(LOG_DEBUG
, "updateServerPort (%@): 0x%x (%d) --> 0x%x (%d)",
403 (storePrivate
->name
!= NULL
) ? storePrivate
->name
: CFSTR("?"),
413 __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate
)
415 kern_return_t kr
= KERN_SUCCESS
;
416 CFDataRef myName
; /* serialized name */
419 CFDataRef myOptions
= NULL
; /* serialized options */
420 xmlData_t myOptionsRef
= NULL
;
421 CFIndex myOptionsLen
= 0;
422 int sc_status
= kSCStatusFailed
;
425 if (!_SCSerializeString(storePrivate
->name
, &myName
, (void **)&myNameRef
, &myNameLen
)) {
429 /* serialize the options */
430 if (storePrivate
->options
!= NULL
) {
431 if (!_SCSerialize(storePrivate
->options
, &myOptions
, (void **)&myOptionsRef
, &myOptionsLen
)) {
437 /* open a new session with the server */
438 server
= MACH_PORT_NULL
;
441 updateServerPort(storePrivate
, &server
, &sc_status
);
444 while (server
!= MACH_PORT_NULL
) {
445 // if SCDynamicStore server available
447 if (!storePrivate
->serverNullSession
) {
448 // if SCDynamicStore session
449 kr
= configopen(server
,
451 (mach_msg_type_number_t
)myNameLen
,
453 (mach_msg_type_number_t
)myOptionsLen
,
454 &storePrivate
->server
,
458 if (storePrivate
->server
== MACH_PORT_NULL
) {
459 // use the [main] SCDynamicStore server port
460 kr
= mach_port_mod_refs(mach_task_self(), server
, MACH_PORT_RIGHT_SEND
, +1);
461 if (kr
== KERN_SUCCESS
) {
462 storePrivate
->server
= server
;
463 sc_status
= kSCStatusOK
;
465 if (kr
== KERN_INVALID_RIGHT
) {
466 // We can get KERN_INVALID_RIGHT if the server dies and we try to
467 // add a send right to a stale (now dead) port name
468 kr
= MACH_SEND_INVALID_DEST
;
470 storePrivate
->server
= MACH_PORT_NULL
;
473 // if the server port we used returned an error
474 storePrivate
->server
= MACH_PORT_NULL
;
475 kr
= MACH_SEND_INVALID_DEST
;
479 if (kr
== KERN_SUCCESS
) {
483 // our [cached] server port is not valid
484 if ((kr
!= MACH_SEND_INVALID_DEST
) && (kr
!= MIG_SERVER_DIED
)) {
485 // if we got an unexpected error, don't retry
491 updateServerPort(storePrivate
, &server
, &sc_status
);
493 __MACH_PORT_DEBUG(TRUE
, "*** SCDynamicStoreAddSession", storePrivate
->server
);
497 if (myOptions
!= NULL
) CFRelease(myOptions
);
504 case BOOTSTRAP_UNKNOWN_SERVICE
:
505 SC_log((kr
== KERN_SUCCESS
) ? LOG_INFO
: LOG_ERR
, "SCDynamicStore server not available");
506 sc_status
= kSCStatusNoStoreServer
;
509 SC_log((kr
== KERN_SUCCESS
) ? LOG_INFO
: LOG_ERR
, "configopen() failed: %d: %s",
511 SCErrorString(sc_status
));
515 _SCErrorSet(sc_status
);
522 __SCDynamicStoreNullSession(void)
524 SCDynamicStorePrivateRef storePrivate
;
526 __SCThreadSpecificDataRef tsd
;
528 tsd
= __SCGetThreadSpecificData();
529 if (tsd
->_sc_store
== NULL
) {
530 storePrivate
= __SCDynamicStoreCreatePrivate(NULL
,
531 CFSTR("NULL session"),
534 assert(storePrivate
!= NULL
);
535 storePrivate
->serverNullSession
= TRUE
;
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
) {
574 case MACH_SEND_INVALID_DEST
:
575 case MACH_SEND_INVALID_RIGHT
:
576 case MIG_SERVER_DIED
:
578 * the server's gone, remove the session's send (or dead name) right
581 SC_log(LOG_DEBUG
, "__SCDynamicStoreCheckRetryAndHandleError(%s): %@: 0x%x (%d) --> 0x%x (%d)",
583 (storePrivate
->name
!= NULL
) ? storePrivate
->name
: CFSTR("?"),
584 storePrivate
->server
, storePrivate
->server
,
585 MACH_PORT_NULL
, MACH_PORT_NULL
);
587 (void) mach_port_deallocate(mach_task_self(), storePrivate
->server
);
588 storePrivate
->server
= MACH_PORT_NULL
;
591 if (__SCDynamicStoreReconnect(store
)) {
601 * an unexpected error, leave the [session] port alone
604 SC_log(LOG_DEBUG
, "__SCDynamicStoreCheckRetryAndHandleError(%s): %@: unexpected status=%s (0x%x)",
606 (storePrivate
->name
!= NULL
) ? storePrivate
->name
: CFSTR("?"),
607 mach_error_string(status
),
611 SC_log(LOG_NOTICE
, "%s: %s", log_str
, mach_error_string(status
));
612 storePrivate
->server
= MACH_PORT_NULL
;
622 pushDisconnect(SCDynamicStoreRef store
)
625 void (*context_release
)(const void *);
626 SCDynamicStoreDisconnectCallBack disconnectFunction
;
627 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
629 disconnectFunction
= storePrivate
->disconnectFunction
;
630 if (disconnectFunction
== NULL
) {
631 // if no reconnect callout, push empty notification
632 storePrivate
->disconnectForceCallBack
= TRUE
;
636 if (storePrivate
->rlsContext
.retain
!= NULL
) {
637 context_info
= (void *)storePrivate
->rlsContext
.retain(storePrivate
->rlsContext
.info
);
638 context_release
= storePrivate
->rlsContext
.release
;
640 context_info
= storePrivate
->rlsContext
.info
;
641 context_release
= NULL
;
643 SC_log(LOG_DEBUG
, "exec SCDynamicStore disconnect callout");
644 (*disconnectFunction
)(store
, context_info
);
645 if (context_release
) {
646 context_release(context_info
);
655 __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store
)
657 dispatch_queue_t dispatchQueue
= NULL
;
658 __SCDynamicStoreNotificationStatus notifyStatus
;
660 CFArrayRef rlList
= NULL
;
661 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
664 SC_log(LOG_DEBUG
, "SCDynamicStore: reconnect notifications (%@)",
665 (storePrivate
->name
!= NULL
) ? storePrivate
->name
: CFSTR("?"));
668 // save old SCDynamicStore [notification] state
669 notifyStatus
= storePrivate
->notifyStatus
;
671 // before tearing down our [old] notifications, make sure we've
672 // retained any information that will be lost when we cancel the
673 // current no-longer-valid handler
674 switch (notifyStatus
) {
675 case Using_NotifierInformViaRunLoop
:
676 if (storePrivate
->rlList
!= NULL
) {
677 rlList
= CFArrayCreateCopy(NULL
, storePrivate
->rlList
);
680 case Using_NotifierInformViaDispatch
:
681 dispatchQueue
= storePrivate
->dispatchQueue
;
682 if (dispatchQueue
!= NULL
) dispatch_retain(dispatchQueue
);
688 // cancel [old] notifications
689 if (!SCDynamicStoreNotifyCancel(store
)) {
690 // if we could not cancel / reconnect
691 SC_log(LOG_NOTICE
, "SCDynamicStoreNotifyCancel() failed: %s", SCErrorString(SCError()));
694 // set notification keys & patterns
695 if ((storePrivate
->keys
!= NULL
) || (storePrivate
->patterns
)) {
696 ok
= SCDynamicStoreSetNotificationKeys(store
,
698 storePrivate
->patterns
);
700 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE
) {
701 SC_log(LOG_NOTICE
, "SCDynamicStoreSetNotificationKeys() failed");
707 switch (notifyStatus
) {
708 case Using_NotifierInformViaRunLoop
: {
711 CFRunLoopSourceRef rls
;
714 SC_log(LOG_DEBUG
, "SCDynamicStore: reconnecting w/CFRunLoop (%@)",
715 (storePrivate
->name
!= NULL
) ? storePrivate
->name
: CFSTR("?"));
718 rls
= SCDynamicStoreCreateRunLoopSource(NULL
, store
, 0);
720 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE
) {
721 SC_log(LOG_NOTICE
, "SCDynamicStoreCreateRunLoopSource() failed");
727 n
= (rlList
!= NULL
) ? CFArrayGetCount(rlList
) : 0;
728 for (i
= 0; i
< n
; i
+= 3) {
729 CFRunLoopRef rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
730 CFStringRef rlMode
= (CFStringRef
) CFArrayGetValueAtIndex(rlList
, i
+2);
732 CFRunLoopAddSource(rl
, rls
, rlMode
);
738 case Using_NotifierInformViaDispatch
:
741 SC_log(LOG_DEBUG
, "SCDynamicStore: reconnecting w/dispatch queue (%@)",
742 (storePrivate
->name
!= NULL
) ? storePrivate
->name
: CFSTR("?"));
745 ok
= SCDynamicStoreSetDispatchQueue(store
, dispatchQueue
);
747 if (SCError() != BOOTSTRAP_UNKNOWN_SERVICE
) {
748 SC_log(LOG_NOTICE
, "SCDynamicStoreSetDispatchQueue() failed");
755 _SCErrorSet(kSCStatusFailed
);
763 switch (notifyStatus
) {
764 case Using_NotifierInformViaRunLoop
:
765 if (rlList
!= NULL
) CFRelease(rlList
);
767 case Using_NotifierInformViaDispatch
:
768 if (dispatchQueue
!= NULL
) dispatch_release(dispatchQueue
);
775 SC_log(LOG_NOTICE
, "SCDynamicStore server %s, notification (%s) not restored",
776 (SCError() == BOOTSTRAP_UNKNOWN_SERVICE
) ? "shutdown" : "failed",
777 notifyType
[notifyStatus
]);
781 pushDisconnect(store
);
787 const CFStringRef kSCDynamicStoreUseSessionKeys
= CFSTR("UseSessionKeys"); /* CFBoolean */
792 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator
,
794 CFDictionaryRef storeOptions
,
795 SCDynamicStoreCallBack callout
,
796 SCDynamicStoreContext
*context
)
799 SCDynamicStorePrivateRef storePrivate
;
801 // allocate and initialize a new session
802 storePrivate
= __SCDynamicStoreCreatePrivate(allocator
, NULL
, callout
, context
);
803 if (storePrivate
== NULL
) {
808 if (_sc_bundleID
!= NULL
) {
809 storePrivate
->name
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:%@"), _sc_bundleID
, name
);
811 storePrivate
->name
= CFRetain(name
);
816 if (storeOptions
!= NULL
) {
817 storePrivate
->options
= CFRetain(storeOptions
);
820 // establish SCDynamicStore session
821 ok
= __SCDynamicStoreAddSession(storePrivate
);
823 CFRelease(storePrivate
);
827 return (SCDynamicStoreRef
)storePrivate
;
832 SCDynamicStoreCreate(CFAllocatorRef allocator
,
834 SCDynamicStoreCallBack callout
,
835 SCDynamicStoreContext
*context
)
837 return SCDynamicStoreCreateWithOptions(allocator
, name
, NULL
, callout
, context
);
842 SCDynamicStoreGetTypeID(void) {
843 pthread_once(&initialized
, __SCDynamicStoreInitialize
); /* initialize runtime */
844 return __kSCDynamicStoreTypeID
;
849 SCDynamicStoreSetDisconnectCallBack(SCDynamicStoreRef store
,
850 SCDynamicStoreDisconnectCallBack callout
)
852 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
855 /* sorry, you must provide a session */
856 _SCErrorSet(kSCStatusNoStoreSession
);
860 storePrivate
->disconnectFunction
= callout
;