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