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