]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDOpen.c
configd-395.10.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDOpen.c
1 /*
2 * Copyright (c) 2000-2006, 2008-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <TargetConditionals.h>
35 #include <stdlib.h>
36 #include <unistd.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>
42
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h>
45 #include "SCDynamicStoreInternal.h"
46 #include "config.h" /* MiG generated file */
47
48
49 static CFStringRef _sc_bundleID = NULL;
50 static pthread_mutex_t _sc_lock = PTHREAD_MUTEX_INITIALIZER;
51 static mach_port_t _sc_server = MACH_PORT_NULL;
52
53
54 static const char *notifyType[] = {
55 "",
56 "wait",
57 "inform w/callback",
58 "inform w/mach port",
59 "inform w/fd",
60 "inform w/signal",
61 "inform w/runLoop",
62 "inform w/dispatch"
63 };
64
65
66 static CFStringRef
67 __SCDynamicStoreCopyDescription(CFTypeRef cf) {
68 CFAllocatorRef allocator = CFGetAllocator(cf);
69 CFMutableStringRef result;
70 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)cf;
71
72 result = CFStringCreateMutable(allocator, 0);
73 CFStringAppendFormat(result, NULL, CFSTR("<SCDynamicStore %p [%p]> {"), cf, allocator);
74 if (storePrivate->server != MACH_PORT_NULL) {
75 CFStringAppendFormat(result, NULL, CFSTR("server port = %p"), storePrivate->server);
76 } else {
77 CFStringAppendFormat(result, NULL, CFSTR("server not (no longer) available"));
78 }
79 if (storePrivate->locked) {
80 CFStringAppendFormat(result, NULL, CFSTR(", locked"));
81 }
82 if (storePrivate->disconnectFunction != NULL) {
83 CFStringAppendFormat(result, NULL, CFSTR(", disconnect = %p"), storePrivate->disconnectFunction);
84 }
85 switch (storePrivate->notifyStatus) {
86 case Using_NotifierWait :
87 CFStringAppendFormat(result, NULL, CFSTR(", waiting for a notification"));
88 break;
89 case Using_NotifierInformViaMachPort :
90 CFStringAppendFormat(result, NULL, CFSTR(", mach port notifications"));
91 break;
92 case Using_NotifierInformViaFD :
93 CFStringAppendFormat(result, NULL, CFSTR(", FD notifications"));
94 break;
95 case Using_NotifierInformViaSignal :
96 CFStringAppendFormat(result, NULL, CFSTR(", BSD signal notifications"));
97 break;
98 case Using_NotifierInformViaRunLoop :
99 case Using_NotifierInformViaCallback :
100 if (storePrivate->notifyStatus == Using_NotifierInformViaRunLoop) {
101 CFStringAppendFormat(result, NULL, CFSTR(", runloop notifications"));
102 CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->rlsFunction);
103 CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->rlsContext.info);
104 CFStringAppendFormat(result, NULL, CFSTR(", rls = %p"), storePrivate->rls);
105 } else {
106 CFStringAppendFormat(result, NULL, CFSTR(", mach port/callback notifications"));
107 CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->callbackFunction);
108 CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->callbackArgument);
109 }
110 if (storePrivate->callbackRLS != NULL) {
111 CFStringAppendFormat(result, NULL, CFSTR(", notify rls = %@" ), storePrivate->callbackRLS);
112 }
113 CFStringAppendFormat(result, NULL, CFSTR("}"));
114 break;
115 default :
116 CFStringAppendFormat(result, NULL, CFSTR(", notification delivery not requested%s"),
117 storePrivate->rlsFunction ? " (yet)" : "");
118 break;
119 }
120 CFStringAppendFormat(result, NULL, CFSTR("}"));
121
122 return result;
123 }
124
125
126 static void
127 __SCDynamicStoreDeallocate(CFTypeRef cf)
128 {
129 int oldThreadState;
130 int sc_status;
131 SCDynamicStoreRef store = (SCDynamicStoreRef)cf;
132 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
133
134 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldThreadState);
135
136 /* Remove/cancel any outstanding notification requests. */
137 (void) SCDynamicStoreNotifyCancel(store);
138
139 if ((storePrivate->server != MACH_PORT_NULL) && storePrivate->locked) {
140 (void) SCDynamicStoreUnlock(store); /* release the lock */
141 }
142
143 if (storePrivate->server != MACH_PORT_NULL) {
144 __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate", storePrivate->server);
145 (void) configclose(storePrivate->server, (int *)&sc_status);
146 __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate (after configclose)", storePrivate->server);
147
148 /*
149 * the above call to configclose() should result in the SCDynamicStore
150 * server code deallocating it's receive right. That, in turn, should
151 * result in our send becoming a dead name. We could explicitly remove
152 * the dead name right with a call to mach_port_mod_refs() but, to be
153 * sure, we use mach_port_deallocate() since that will get rid of a
154 * send, send_once, or dead name right.
155 */
156 (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
157 storePrivate->server = MACH_PORT_NULL;
158 }
159
160 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldThreadState);
161 pthread_testcancel();
162
163 /* release any callback context info */
164 if (storePrivate->rlsContext.release != NULL) {
165 (*storePrivate->rlsContext.release)(storePrivate->rlsContext.info);
166 }
167
168 /* release any keys being watched */
169 if (storePrivate->keys != NULL) CFRelease(storePrivate->keys);
170 if (storePrivate->patterns != NULL) CFRelease(storePrivate->patterns);
171
172 /* release any client info */
173 if (storePrivate->name != NULL) CFRelease(storePrivate->name);
174 if (storePrivate->options != NULL) CFRelease(storePrivate->options);
175
176 return;
177 }
178
179
180 static CFTypeID __kSCDynamicStoreTypeID = _kCFRuntimeNotATypeID;
181
182
183 static const CFRuntimeClass __SCDynamicStoreClass = {
184 0, // version
185 "SCDynamicStore", // className
186 NULL, // init
187 NULL, // copy
188 __SCDynamicStoreDeallocate, // dealloc
189 NULL, // equal
190 NULL, // hash
191 NULL, // copyFormattingDesc
192 __SCDynamicStoreCopyDescription // copyDebugDesc
193 };
194
195
196 static void
197 childForkHandler()
198 {
199 /* the process has forked (and we are the child process) */
200
201 _sc_server = MACH_PORT_NULL;
202 return;
203 }
204
205
206 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
207
208 static void
209 __SCDynamicStoreInitialize(void)
210 {
211 CFBundleRef bundle;
212
213 /* register with CoreFoundation */
214 __kSCDynamicStoreTypeID = _CFRuntimeRegisterClass(&__SCDynamicStoreClass);
215
216 /* add handler to cleanup after fork() */
217 (void) pthread_atfork(NULL, NULL, childForkHandler);
218
219 /* get the application/executable/bundle name */
220 bundle = CFBundleGetMainBundle();
221 if (bundle != NULL) {
222 _sc_bundleID = CFBundleGetIdentifier(bundle);
223 if (_sc_bundleID != NULL) {
224 CFRetain(_sc_bundleID);
225 } else {
226 CFURLRef url;
227
228 url = CFBundleCopyExecutableURL(bundle);
229 if (url != NULL) {
230 _sc_bundleID = CFURLCopyPath(url);
231 CFRelease(url);
232 }
233 }
234
235 if (_sc_bundleID != NULL) {
236 if (CFEqual(_sc_bundleID, CFSTR("/"))) {
237 CFRelease(_sc_bundleID);
238 _sc_bundleID = CFStringCreateWithFormat(NULL, NULL, CFSTR("(%d)"), getpid());
239 }
240 }
241 }
242
243 return;
244 }
245
246
247 static mach_port_t
248 __SCDynamicStoreServerPort(kern_return_t *status)
249 {
250 mach_port_t server = MACH_PORT_NULL;
251 char *server_name;
252
253 server_name = getenv("SCD_SERVER");
254 if (!server_name) {
255 server_name = SCD_SERVER;
256 }
257
258 #ifdef BOOTSTRAP_PRIVILEGED_SERVER
259 *status = bootstrap_look_up2(bootstrap_port,
260 server_name,
261 &server,
262 0,
263 BOOTSTRAP_PRIVILEGED_SERVER);
264 #else // BOOTSTRAP_PRIVILEGED_SERVER
265 *status = bootstrap_look_up(bootstrap_port, server_name, &server);
266 #endif // BOOTSTRAP_PRIVILEGED_SERVER
267
268 switch (*status) {
269 case BOOTSTRAP_SUCCESS :
270 /* service currently registered, "a good thing" (tm) */
271 return server;
272 case BOOTSTRAP_NOT_PRIVILEGED :
273 /* the service is not privileged */
274 break;
275 case BOOTSTRAP_UNKNOWN_SERVICE :
276 /* service not currently registered, try again later */
277 break;
278 default :
279 #ifdef DEBUG
280 SCLog(_sc_verbose, LOG_DEBUG,
281 CFSTR("SCDynamicStoreCreate[WithOptions] bootstrap_look_up() failed: status=%s"),
282 bootstrap_strerror(*status));
283 #endif /* DEBUG */
284 break;
285 }
286
287 return MACH_PORT_NULL;
288 }
289
290
291 SCDynamicStorePrivateRef
292 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator,
293 const CFStringRef name,
294 SCDynamicStoreCallBack callout,
295 SCDynamicStoreContext *context)
296 {
297 uint32_t size;
298 SCDynamicStorePrivateRef storePrivate;
299
300 /* initialize runtime */
301 pthread_once(&initialized, __SCDynamicStoreInitialize);
302
303
304 /* allocate session */
305 size = sizeof(SCDynamicStorePrivate) - sizeof(CFRuntimeBase);
306 storePrivate = (SCDynamicStorePrivateRef)_CFRuntimeCreateInstance(allocator,
307 __kSCDynamicStoreTypeID,
308 size,
309 NULL);
310 if (storePrivate == NULL) {
311 _SCErrorSet(kSCStatusFailed);
312 return NULL;
313 }
314
315 /* client side of the "configd" session */
316 storePrivate->name = NULL;
317 storePrivate->options = NULL;
318
319 /* server side of the "configd" session */
320 storePrivate->server = MACH_PORT_NULL;
321
322 /* flags */
323 storePrivate->locked = FALSE;
324 storePrivate->useSessionKeys = FALSE;
325
326 /* Notification status */
327 storePrivate->notifyStatus = NotifierNotRegistered;
328
329 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
330 storePrivate->rlList = NULL;
331 storePrivate->rls = NULL;
332 storePrivate->rlsFunction = callout;
333 storePrivate->rlsContext.info = NULL;
334 storePrivate->rlsContext.retain = NULL;
335 storePrivate->rlsContext.release = NULL;
336 storePrivate->rlsContext.copyDescription = NULL;
337 if (context) {
338 bcopy(context, &storePrivate->rlsContext, sizeof(SCDynamicStoreContext));
339 if (context->retain != NULL) {
340 storePrivate->rlsContext.info = (void *)(*context->retain)(context->info);
341 }
342 }
343
344 /* "client" information associated with SCDynamicStoreNotifyCallback() */
345 storePrivate->callbackFunction = NULL;
346 storePrivate->callbackArgument = NULL;
347 storePrivate->callbackPort = NULL;
348 storePrivate->callbackRLS = NULL;
349
350 /* "client" information associated with SCDynamicStoreSetDispatchQueue() */
351 storePrivate->dispatchQueue = NULL;
352 storePrivate->callbackSource = NULL;
353 storePrivate->callbackQueue = NULL;
354
355 /* "client" information associated with SCDynamicStoreSetDisconnectCallBack() */
356 storePrivate->disconnectFunction = NULL;
357 storePrivate->disconnectForceCallBack = FALSE;
358
359 /* "server" information associated with SCDynamicStoreSetNotificationKeys() */
360 storePrivate->keys = NULL;
361 storePrivate->patterns = NULL;
362
363 /* "server" information associated with SCDynamicStoreNotifyMachPort(); */
364 storePrivate->notifyPort = MACH_PORT_NULL;
365 storePrivate->notifyPortIdentifier = 0;
366
367 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
368 storePrivate->notifyFile = -1;
369 storePrivate->notifyFileIdentifier = 0;
370
371 /* "server" information associated with SCDynamicStoreNotifySignal(); */
372 storePrivate->notifySignal = 0;
373 storePrivate->notifySignalTask = TASK_NULL;
374
375 return storePrivate;
376 }
377
378
379 static Boolean
380 __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate)
381 {
382 CFDataRef myName; /* serialized name */
383 xmlData_t myNameRef;
384 CFIndex myNameLen;
385 CFDataRef myOptions = NULL; /* serialized options */
386 xmlData_t myOptionsRef = NULL;
387 CFIndex myOptionsLen = 0;
388 int sc_status = kSCStatusFailed;
389 mach_port_t server;
390 kern_return_t status = KERN_SUCCESS;
391
392 if (!_SCSerializeString(storePrivate->name, &myName, (void **)&myNameRef, &myNameLen)) {
393 goto done;
394 }
395
396 /* serialize the options */
397 if (storePrivate->options != NULL) {
398 if (!_SCSerialize(storePrivate->options, &myOptions, (void **)&myOptionsRef, &myOptionsLen)) {
399 CFRelease(myName);
400 goto done;
401 }
402 }
403
404 /* open a new session with the server */
405 server = _sc_server;
406 while (TRUE) {
407 if (server != MACH_PORT_NULL) {
408 status = configopen(server,
409 myNameRef,
410 myNameLen,
411 myOptionsRef,
412 myOptionsLen,
413 &storePrivate->server,
414 (int *)&sc_status);
415 if (status == KERN_SUCCESS) {
416 break;
417 }
418
419 // our [cached] server port is not valid
420 if ((status != MACH_SEND_INVALID_DEST) && (status != MIG_SERVER_DIED)) {
421 // if we got an unexpected error, don't retry
422 sc_status = status;
423 break;
424 }
425 }
426
427 pthread_mutex_lock(&_sc_lock);
428 if (_sc_server != MACH_PORT_NULL) {
429 if (server == _sc_server) {
430 // if the server we tried returned the error
431 (void)mach_port_deallocate(mach_task_self(), _sc_server);
432 _sc_server = __SCDynamicStoreServerPort(&sc_status);
433 } else {
434 // another thread has refreshed the SCDynamicStore server port
435 }
436 } else {
437 _sc_server = __SCDynamicStoreServerPort(&sc_status);
438 }
439 server = _sc_server;
440 pthread_mutex_unlock(&_sc_lock);
441
442 if (server == MACH_PORT_NULL) {
443 // if SCDynamicStore server not available
444 break;
445 }
446 }
447 __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreAddSession", storePrivate->server);
448
449 // clean up
450 CFRelease(myName);
451 if (myOptions != NULL) CFRelease(myOptions);
452
453 done :
454
455 switch (sc_status) {
456 case kSCStatusOK :
457 return TRUE;
458 case BOOTSTRAP_UNKNOWN_SERVICE :
459 SCLog(TRUE,
460 (status == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR,
461 CFSTR("SCDynamicStore server not available"));
462 break;
463 default :
464 SCLog(TRUE,
465 (status == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR,
466 CFSTR("SCDynamicStoreCreateAddSession configopen(): %s"),
467 SCErrorString(sc_status));
468 break;
469 }
470
471 _SCErrorSet(sc_status);
472 return FALSE;
473 }
474
475
476 __private_extern__
477 Boolean
478 __SCDynamicStoreReconnect(SCDynamicStoreRef store)
479 {
480 Boolean ok;
481 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
482
483 ok = __SCDynamicStoreAddSession(storePrivate);
484 return ok;
485 }
486
487
488 static void
489 pushDisconnect(SCDynamicStoreRef store)
490 {
491 void *context_info;
492 void (*context_release)(const void *);
493 SCDynamicStoreDisconnectCallBack disconnectFunction;
494 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
495
496 disconnectFunction = storePrivate->disconnectFunction;
497 if (disconnectFunction == NULL) {
498 // if no reconnect callout, push empty notification
499 storePrivate->disconnectForceCallBack = TRUE;
500 return;
501 }
502
503 if (storePrivate->rlsContext.retain != NULL) {
504 context_info = (void *)storePrivate->rlsContext.retain(storePrivate->rlsContext.info);
505 context_release = storePrivate->rlsContext.release;
506 } else {
507 context_info = storePrivate->rlsContext.info;
508 context_release = NULL;
509 }
510 (*disconnectFunction)(store, context_info);
511 if (context_release) {
512 context_release(context_info);
513 }
514
515 return;
516 }
517
518
519 __private_extern__
520 Boolean
521 __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store)
522 {
523 dispatch_queue_t dispatchQueue = NULL;
524 __SCDynamicStoreNotificationStatus notifyStatus;
525 Boolean ok = TRUE;
526 CFArrayRef rlList = NULL;
527 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
528
529 // save old SCDynamicStore [notification] state
530 notifyStatus = storePrivate->notifyStatus;
531
532 // before tearing down our [old] notifications, make sure we've
533 // retained any information that will be lost when we cancel the
534 // current no-longer-valid handler
535 switch (notifyStatus) {
536 case Using_NotifierInformViaRunLoop :
537 if (storePrivate->rlList != NULL) {
538 rlList = CFArrayCreateCopy(NULL, storePrivate->rlList);
539 }
540 case Using_NotifierInformViaDispatch :
541 dispatchQueue = storePrivate->dispatchQueue;
542 if (dispatchQueue != NULL) dispatch_retain(dispatchQueue);
543 break;
544 default :
545 break;
546 }
547
548 #ifdef NOTNOW
549 // invalidate the run loop source(s)
550 if (storePrivate->callbackRLS != NULL) {
551 CFRunLoopSourceInvalidate(storePrivate->callbackRLS);
552 CFRelease(storePrivate->callbackRLS);
553 storePrivate->callbackRLS = NULL;
554 }
555
556 // invalidate port
557 if (storePrivate->callbackPort != NULL) {
558 __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreReconnectNotifications w/MACH_NOTIFY_NO_SENDERS", CFMachPortGetPort(storePrivate->callbackPort));
559 CFMachPortInvalidate(storePrivate->callbackPort);
560 CFRelease(storePrivate->callbackPort);
561 storePrivate->callbackPort = NULL;
562 }
563 #endif // NOTNOW
564
565 // cancel [old] notifications
566 SCDynamicStoreNotifyCancel(store);
567
568 // set notification keys & patterns
569 if ((storePrivate->keys != NULL) || (storePrivate->patterns)) {
570 ok = SCDynamicStoreSetNotificationKeys(store,
571 storePrivate->keys,
572 storePrivate->patterns);
573 if (!ok) {
574 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE),
575 LOG_ERR,
576 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetNotificationKeys() failed"));
577 goto done;
578 }
579 }
580
581 switch (notifyStatus) {
582 case Using_NotifierInformViaRunLoop : {
583 CFIndex i;
584 CFIndex n;
585 CFRunLoopSourceRef rls;
586
587 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
588 if (rls == NULL) {
589 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE),
590 LOG_ERR,
591 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreCreateRunLoopSource() failed"));
592 ok = FALSE;
593 break;
594 }
595
596 n = (rlList != NULL) ? CFArrayGetCount(rlList) : 0;
597 for (i = 0; i < n; i += 3) {
598 CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
599 CFStringRef rlMode = (CFStringRef) CFArrayGetValueAtIndex(rlList, i+2);
600
601 CFRunLoopAddSource(rl, rls, rlMode);
602 }
603
604 CFRelease(rls);
605 break;
606 }
607 case Using_NotifierInformViaDispatch :
608 ok = SCDynamicStoreSetDispatchQueue(store, dispatchQueue);
609 if (!ok) {
610 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE),
611 LOG_ERR,
612 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetDispatchQueue() failed"));
613 goto done;
614 }
615 break;
616
617 default :
618 _SCErrorSet(kSCStatusFailed);
619 ok = FALSE;
620 break;
621 }
622
623 done :
624
625 // cleanup
626 switch (notifyStatus) {
627 case Using_NotifierInformViaRunLoop :
628 if (rlList != NULL) CFRelease(rlList);
629 break;
630 case Using_NotifierInformViaDispatch :
631 if (dispatchQueue != NULL) dispatch_release(dispatchQueue);
632 break;
633 default :
634 break;
635 }
636
637 if (!ok) {
638 SCLog(TRUE, LOG_ERR,
639 CFSTR("SCDynamicStore server %s, notification (%s) not restored"),
640 (SCError() == BOOTSTRAP_UNKNOWN_SERVICE) ? "shutdown" : "failed",
641 notifyType[notifyStatus]);
642 }
643
644 // inform the client
645 pushDisconnect(store);
646
647 return ok;
648 }
649
650
651 const CFStringRef kSCDynamicStoreUseSessionKeys = CFSTR("UseSessionKeys"); /* CFBoolean */
652
653
654 SCDynamicStoreRef
655 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator,
656 CFStringRef name,
657 CFDictionaryRef storeOptions,
658 SCDynamicStoreCallBack callout,
659 SCDynamicStoreContext *context)
660 {
661 Boolean ok;
662 SCDynamicStorePrivateRef storePrivate;
663
664 // allocate and initialize a new session
665 storePrivate = __SCDynamicStoreCreatePrivate(allocator, name, callout, context);
666 if (storePrivate == NULL) {
667 return NULL;
668 }
669
670 // set "name"
671 if (_sc_bundleID != NULL) {
672 storePrivate->name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"), _sc_bundleID, name);
673 } else {
674 storePrivate->name = CFRetain(name);
675 }
676
677 // set "options"
678 storePrivate->options = (storeOptions != NULL) ? CFRetain(storeOptions) : NULL;
679
680 // establish SCDynamicStore session
681 ok = __SCDynamicStoreAddSession(storePrivate);
682 if (!ok) {
683 CFRelease(storePrivate);
684 storePrivate = NULL;
685 }
686
687 return (SCDynamicStoreRef)storePrivate;
688 }
689
690
691 SCDynamicStoreRef
692 SCDynamicStoreCreate(CFAllocatorRef allocator,
693 CFStringRef name,
694 SCDynamicStoreCallBack callout,
695 SCDynamicStoreContext *context)
696 {
697 return SCDynamicStoreCreateWithOptions(allocator, name, NULL, callout, context);
698 }
699
700
701 CFTypeID
702 SCDynamicStoreGetTypeID(void) {
703 pthread_once(&initialized, __SCDynamicStoreInitialize); /* initialize runtime */
704 return __kSCDynamicStoreTypeID;
705 }
706
707 Boolean
708 SCDynamicStoreSetDisconnectCallBack(SCDynamicStoreRef store,
709 SCDynamicStoreDisconnectCallBack callout)
710 {
711 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
712
713 if (store == NULL) {
714 /* sorry, you must provide a session */
715 _SCErrorSet(kSCStatusNoStoreSession);
716 return FALSE;
717 }
718
719 storePrivate->disconnectFunction = callout;
720 return TRUE;
721 }