2 * Copyright (c) 2000-2004 Apple Computer, 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>
36 #include <sys/types.h>
37 #include <mach/mach.h>
38 #include <mach/mach_error.h>
39 #include <servers/bootstrap.h>
41 #include <SystemConfiguration/SystemConfiguration.h>
42 #include <SystemConfiguration/SCPrivate.h>
43 #include "SCDynamicStoreInternal.h"
44 #include "config.h" /* MiG generated file */
47 static int _sc_active
= 0;
48 static CFStringRef _sc_bundleID
= NULL
;
49 static pthread_mutex_t _sc_lock
= PTHREAD_MUTEX_INITIALIZER
;
50 static mach_port_t _sc_server
= MACH_PORT_NULL
;
54 __SCDynamicStoreCopyDescription(CFTypeRef cf
) {
55 CFAllocatorRef allocator
= CFGetAllocator(cf
);
56 CFMutableStringRef result
;
57 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)cf
;
59 result
= CFStringCreateMutable(allocator
, 0);
60 CFStringAppendFormat(result
, NULL
, CFSTR("<SCDynamicStore %p [%p]> { "), cf
, allocator
);
61 if (storePrivate
->server
!= MACH_PORT_NULL
) {
62 CFStringAppendFormat(result
, NULL
, CFSTR("server port=%d"), storePrivate
->server
);
64 CFStringAppendFormat(result
, NULL
, CFSTR("server not (no longer) available"));
66 if (storePrivate
->locked
) {
67 CFStringAppendFormat(result
, NULL
, CFSTR(", locked"));
69 switch (storePrivate
->notifyStatus
) {
70 case Using_NotifierWait
:
71 CFStringAppendFormat(result
, NULL
, CFSTR(", waiting for a notification"));
73 case Using_NotifierInformViaMachPort
:
74 CFStringAppendFormat(result
, NULL
, CFSTR(", mach port notifications"));
76 case Using_NotifierInformViaFD
:
77 CFStringAppendFormat(result
, NULL
, CFSTR(", FD notifications"));
79 case Using_NotifierInformViaSignal
:
80 CFStringAppendFormat(result
, NULL
, CFSTR(", BSD signal notifications"));
82 case Using_NotifierInformViaRunLoop
:
83 case Using_NotifierInformViaCallback
:
84 if (storePrivate
->notifyStatus
== Using_NotifierInformViaRunLoop
) {
85 CFStringAppendFormat(result
, NULL
, CFSTR(", runloop notifications"));
86 CFStringAppendFormat(result
, NULL
, CFSTR(" (func=0x%8.8x"), storePrivate
->rlsFunction
);
87 CFStringAppendFormat(result
, NULL
, CFSTR(", info=0x%8.8x"), storePrivate
->rlsContext
.info
);
88 CFStringAppendFormat(result
, NULL
, CFSTR(", rls=0x%8.8x" ), storePrivate
->rls
);
89 CFStringAppendFormat(result
, NULL
, CFSTR(", refs=%d" ), storePrivate
->rlsRefs
);
91 CFStringAppendFormat(result
, NULL
, CFSTR(", mach port/callback notifications"));
92 CFStringAppendFormat(result
, NULL
, CFSTR(" (func=0x%8.8x"), storePrivate
->callbackFunction
);
93 CFStringAppendFormat(result
, NULL
, CFSTR(", info=0x%8.8x"), storePrivate
->callbackArgument
);
95 if (storePrivate
->callbackRLS
!= NULL
) {
96 CFStringAppendFormat(result
, NULL
, CFSTR(", notify rls=%@" ), storePrivate
->callbackRLS
);
98 CFStringAppendFormat(result
, NULL
, CFSTR(")"));
101 CFStringAppendFormat(result
, NULL
, CFSTR(", notification delivery not requested%s"),
102 storePrivate
->rlsFunction
? " (yet)" : "");
105 CFStringAppendFormat(result
, NULL
, CFSTR(" }"));
112 __SCDynamicStoreDeallocate(CFTypeRef cf
)
116 kern_return_t status
;
117 SCDynamicStoreRef store
= (SCDynamicStoreRef
)cf
;
118 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
120 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED
, &oldThreadState
);
122 /* Remove/cancel any outstanding notification requests. */
123 (void) SCDynamicStoreNotifyCancel(store
);
125 if ((storePrivate
->server
!= MACH_PORT_NULL
) && storePrivate
->locked
) {
126 (void) SCDynamicStoreUnlock(store
); /* release the lock */
129 if (storePrivate
->server
!= MACH_PORT_NULL
) {
130 status
= configclose(storePrivate
->server
, (int *)&sc_status
);
132 if (status
!= KERN_SUCCESS
) {
133 if (status
!= MACH_SEND_INVALID_DEST
)
134 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCDynamicStoreDeallocate configclose(): %s"), mach_error_string(status
));
138 (void) mach_port_destroy(mach_task_self(), storePrivate
->server
);
139 storePrivate
->server
= MACH_PORT_NULL
;
142 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, &oldThreadState
);
143 pthread_testcancel();
145 /* release any callback context info */
146 if (storePrivate
->rlsContext
.release
!= NULL
) {
147 (*storePrivate
->rlsContext
.release
)(storePrivate
->rlsContext
.info
);
150 /* release any keys being watched */
151 CFRelease(storePrivate
->keys
);
152 CFRelease(storePrivate
->patterns
);
155 pthread_mutex_lock(&_sc_lock
);
156 _sc_active
--; /* drop the number of active dynamic store sessions */
157 if ((_sc_active
== 0) && (_sc_server
!= MACH_PORT_NULL
)) {
158 /* release the [last] reference to the server */
159 (void)mach_port_deallocate(mach_task_self(), _sc_server
);
160 _sc_server
= MACH_PORT_NULL
;
162 pthread_mutex_unlock(&_sc_lock
);
168 static CFTypeID __kSCDynamicStoreTypeID
= _kCFRuntimeNotATypeID
;
171 static const CFRuntimeClass __SCDynamicStoreClass
= {
173 "SCDynamicStore", // className
176 __SCDynamicStoreDeallocate
, // dealloc
179 NULL
, // copyFormattingDesc
180 __SCDynamicStoreCopyDescription
// copyDebugDesc
187 /* the process has forked (and we are the child process) */
190 _sc_server
= MACH_PORT_NULL
;
196 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
199 __SCDynamicStoreInitialize(void) {
202 /* register with CoreFoundation */
203 __kSCDynamicStoreTypeID
= _CFRuntimeRegisterClass(&__SCDynamicStoreClass
);
205 /* add handler to cleanup after fork() */
206 (void) pthread_atfork(NULL
, NULL
, childForkHandler
);
208 /* get the application/executable/bundle name */
209 bundle
= CFBundleGetMainBundle();
210 if (bundle
!= NULL
) {
211 _sc_bundleID
= CFBundleGetIdentifier(bundle
);
212 if (_sc_bundleID
!= NULL
) {
213 CFRetain(_sc_bundleID
);
217 url
= CFBundleCopyExecutableURL(bundle
);
219 _sc_bundleID
= CFURLCopyPath(url
);
224 if (_sc_bundleID
!= NULL
) {
225 if (CFEqual(_sc_bundleID
, CFSTR("/"))) {
226 CFRelease(_sc_bundleID
);
227 _sc_bundleID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("(%d)"), getpid());
236 SCDynamicStorePrivateRef
237 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator
,
238 const CFStringRef name
,
239 SCDynamicStoreCallBack callout
,
240 SCDynamicStoreContext
*context
)
242 int sc_status
= kSCStatusOK
;
244 SCDynamicStorePrivateRef storePrivate
;
246 /* initialize runtime */
247 pthread_once(&initialized
, __SCDynamicStoreInitialize
);
250 /* allocate session */
251 size
= sizeof(SCDynamicStorePrivate
) - sizeof(CFRuntimeBase
);
252 storePrivate
= (SCDynamicStorePrivateRef
)_CFRuntimeCreateInstance(allocator
,
253 __kSCDynamicStoreTypeID
,
256 if (storePrivate
== NULL
) {
257 _SCErrorSet(kSCStatusFailed
);
261 /* server side of the "configd" session */
262 storePrivate
->server
= MACH_PORT_NULL
;
265 storePrivate
->locked
= FALSE
;
266 storePrivate
->useSessionKeys
= FALSE
;
268 /* Notification status */
269 storePrivate
->notifyStatus
= NotifierNotRegistered
;
271 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
272 storePrivate
->rlsRefs
= 0;
273 storePrivate
->rls
= NULL
;
274 storePrivate
->rlsFunction
= callout
;
275 storePrivate
->rlsContext
.info
= NULL
;
276 storePrivate
->rlsContext
.retain
= NULL
;
277 storePrivate
->rlsContext
.release
= NULL
;
278 storePrivate
->rlsContext
.copyDescription
= NULL
;
280 bcopy(context
, &storePrivate
->rlsContext
, sizeof(SCDynamicStoreContext
));
281 if (context
->retain
!= NULL
) {
282 storePrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
286 /* "client" information associated with SCDynamicStoreNotifyCallback() */
287 storePrivate
->callbackFunction
= NULL
;
288 storePrivate
->callbackArgument
= NULL
;
289 storePrivate
->callbackPort
= NULL
;
290 storePrivate
->callbackRLS
= NULL
;
292 /* "server" information associated with SCDynamicStoreSetNotificationKeys() */
293 storePrivate
->keys
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
294 storePrivate
->patterns
= CFSetCreateMutable(NULL
, 0, &kCFTypeSetCallBacks
);
296 /* "server" information associated with SCDynamicStoreNotifyMachPort(); */
297 storePrivate
->notifyPort
= MACH_PORT_NULL
;
298 storePrivate
->notifyPortIdentifier
= 0;
300 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
301 storePrivate
->notifyFile
= -1;
302 storePrivate
->notifyFileIdentifier
= 0;
304 /* "server" information associated with SCDynamicStoreNotifySignal(); */
305 storePrivate
->notifySignal
= 0;
306 storePrivate
->notifySignalTask
= TASK_NULL
;
308 /* initialize global state */
310 pthread_mutex_lock(&_sc_lock
);
312 /* get the server port */
313 if (_sc_server
== MACH_PORT_NULL
) {
315 kern_return_t status
;
317 server_name
= getenv("SCD_SERVER");
319 server_name
= SCD_SERVER
;
322 status
= bootstrap_look_up(bootstrap_port
, server_name
, &_sc_server
);
324 case BOOTSTRAP_SUCCESS
:
325 /* service currently registered, "a good thing" (tm) */
327 case BOOTSTRAP_UNKNOWN_SERVICE
:
328 /* service not currently registered, try again later */
333 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCDynamicStoreCreate[WithOptions] bootstrap_look_up() failed: status=%d"), status
);
340 /* bump the number of active dynamic store sessions */
345 pthread_mutex_unlock(&_sc_lock
);
347 if (sc_status
!= kSCStatusOK
) {
348 _SCErrorSet(sc_status
);
349 CFRelease(storePrivate
);
357 const CFStringRef kSCDynamicStoreUseSessionKeys
= CFSTR("UseSessionKeys"); /* CFBoolean */
361 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator
,
363 CFDictionaryRef storeOptions
,
364 SCDynamicStoreCallBack callout
,
365 SCDynamicStoreContext
*context
)
367 SCDynamicStorePrivateRef storePrivate
;
368 kern_return_t status
;
369 CFDataRef utfName
; /* serialized name */
372 CFDataRef xmlOptions
= NULL
; /* serialized options */
373 xmlData_t myOptionsRef
= NULL
;
374 CFIndex myOptionsLen
= 0;
375 int sc_status
= kSCStatusFailed
;
378 * allocate and initialize a new session
380 storePrivate
= __SCDynamicStoreCreatePrivate(allocator
, name
, callout
, context
);
381 if (storePrivate
== NULL
) {
385 if (_sc_bundleID
!= NULL
) {
386 CFStringRef fullName
;
388 fullName
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@:%@"), _sc_bundleID
, name
);
394 if (!_SCSerializeString(name
, &utfName
, (void **)&myNameRef
, &myNameLen
)) {
400 /* serialize the options */
402 if (!_SCSerialize(storeOptions
, &xmlOptions
, (void **)&myOptionsRef
, &myOptionsLen
)) {
408 /* open a new session with the server */
409 status
= configopen(_sc_server
,
414 &storePrivate
->server
,
419 if (xmlOptions
) CFRelease(xmlOptions
);
421 if (status
!= KERN_SUCCESS
) {
423 if (status
!= MACH_SEND_INVALID_DEST
)
424 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("SCDynamicStoreCreate[WithOptions] configopen(): %s"), mach_error_string(status
));
432 if (sc_status
!= kSCStatusOK
) {
433 _SCErrorSet(sc_status
);
434 CFRelease(storePrivate
);
438 return (SCDynamicStoreRef
)storePrivate
;
443 SCDynamicStoreCreate(CFAllocatorRef allocator
,
445 SCDynamicStoreCallBack callout
,
446 SCDynamicStoreContext
*context
)
448 return SCDynamicStoreCreateWithOptions(allocator
, name
, NULL
, callout
, context
);
453 SCDynamicStoreGetTypeID(void) {
454 pthread_once(&initialized
, __SCDynamicStoreInitialize
); /* initialize runtime */
455 return __kSCDynamicStoreTypeID
;