e03cfff0bc05f2fd6a724eafee101e394cdbeb2f
[apple/configd.git] / SystemConfiguration.fproj / SCDOpen.c
1 /*
2 * Copyright (c) 2000-2006, 2008-2014 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 SCLog(_sc_verbose, LOG_DEBUG,
276 CFSTR("SCDynamicStoreCreate[WithOptions] bootstrap_look_up() failed: status=%s"),
277 bootstrap_strerror(*status));
278 #endif /* DEBUG */
279 break;
280 }
281
282 return MACH_PORT_NULL;
283 }
284
285
286 SCDynamicStorePrivateRef
287 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator,
288 const CFStringRef name,
289 SCDynamicStoreCallBack callout,
290 SCDynamicStoreContext *context)
291 {
292 uint32_t size;
293 SCDynamicStorePrivateRef storePrivate;
294
295 /* initialize runtime */
296 pthread_once(&initialized, __SCDynamicStoreInitialize);
297
298
299 /* allocate session */
300 size = sizeof(SCDynamicStorePrivate) - sizeof(CFRuntimeBase);
301 storePrivate = (SCDynamicStorePrivateRef)_CFRuntimeCreateInstance(allocator,
302 __kSCDynamicStoreTypeID,
303 size,
304 NULL);
305 if (storePrivate == NULL) {
306 _SCErrorSet(kSCStatusFailed);
307 return NULL;
308 }
309
310 /* client side of the "configd" session */
311 storePrivate->name = (name != NULL) ? CFRetain(name) : NULL;
312 storePrivate->options = NULL;
313
314 /* server side of the "configd" session */
315 storePrivate->server = MACH_PORT_NULL;
316 storePrivate->serverNullSession = FALSE;
317
318 /* flags */
319 storePrivate->useSessionKeys = FALSE;
320
321 /* Notification status */
322 storePrivate->notifyStatus = NotifierNotRegistered;
323
324 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
325 storePrivate->rlList = NULL;
326 storePrivate->rls = NULL;
327 storePrivate->rlsFunction = callout;
328 storePrivate->rlsContext.info = NULL;
329 storePrivate->rlsContext.retain = NULL;
330 storePrivate->rlsContext.release = NULL;
331 storePrivate->rlsContext.copyDescription = NULL;
332 if (context) {
333 bcopy(context, &storePrivate->rlsContext, sizeof(SCDynamicStoreContext));
334 if (context->retain != NULL) {
335 storePrivate->rlsContext.info = (void *)(*context->retain)(context->info);
336 }
337 }
338 storePrivate->rlsNotifyPort = NULL;
339 storePrivate->rlsNotifyRLS = NULL;
340
341 /* "client" information associated with SCDynamicStoreSetDispatchQueue() */
342 storePrivate->dispatchGroup = NULL;
343 storePrivate->dispatchQueue = NULL;
344 storePrivate->dispatchSource = NULL;
345
346 /* "client" information associated with SCDynamicStoreSetDisconnectCallBack() */
347 storePrivate->disconnectFunction = NULL;
348 storePrivate->disconnectForceCallBack = FALSE;
349
350 /* "server" information associated with SCDynamicStoreSetNotificationKeys() */
351 storePrivate->keys = NULL;
352 storePrivate->patterns = NULL;
353
354 /* "server" information associated with SCDynamicStoreNotifyMachPort(); */
355 storePrivate->notifyPort = MACH_PORT_NULL;
356 storePrivate->notifyPortIdentifier = 0;
357
358 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
359 storePrivate->notifyFile = -1;
360 storePrivate->notifyFileIdentifier = 0;
361
362 /* "server" information associated with SCDynamicStoreNotifySignal(); */
363 storePrivate->notifySignal = 0;
364 storePrivate->notifySignalTask = TASK_NULL;
365
366 return storePrivate;
367 }
368
369
370 static void
371 updateServerPort(SCDynamicStorePrivateRef storePrivate, mach_port_t *server, int *sc_status_p)
372 {
373 pthread_mutex_lock(&_sc_lock);
374 if (_sc_server != MACH_PORT_NULL) {
375 if (*server == _sc_server) {
376 mach_port_t old_port;
377
378 // if the server we tried returned the error, save the old port,
379 // [re-]lookup the name to the server, and deallocate the original
380 // send [or dead name] right
381
382 old_port = _sc_server;
383 _sc_server = __SCDynamicStoreServerPort(storePrivate, sc_status_p);
384 (void)mach_port_deallocate(mach_task_self(), old_port);
385 } else {
386 // another thread has refreshed the [main] SCDynamicStore server port
387 }
388 } else {
389 _sc_server = __SCDynamicStoreServerPort(storePrivate, sc_status_p);
390 }
391 *server = _sc_server;
392 pthread_mutex_unlock(&_sc_lock);
393
394 return;
395 }
396
397
398 static Boolean
399 __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate)
400 {
401 kern_return_t kr = KERN_SUCCESS;
402 CFDataRef myName; /* serialized name */
403 xmlData_t myNameRef;
404 CFIndex myNameLen;
405 CFDataRef myOptions = NULL; /* serialized options */
406 xmlData_t myOptionsRef = NULL;
407 CFIndex myOptionsLen = 0;
408 int sc_status = kSCStatusFailed;
409 mach_port_t server;
410
411 if (!_SCSerializeString(storePrivate->name, &myName, (void **)&myNameRef, &myNameLen)) {
412 goto done;
413 }
414
415 /* serialize the options */
416 if (storePrivate->options != NULL) {
417 if (!_SCSerialize(storePrivate->options, &myOptions, (void **)&myOptionsRef, &myOptionsLen)) {
418 CFRelease(myName);
419 goto done;
420 }
421 }
422
423 /* open a new session with the server */
424 server = MACH_PORT_NULL;
425
426
427 updateServerPort(storePrivate, &server, &sc_status);
428
429
430 while (server != MACH_PORT_NULL) {
431 // if SCDynamicStore server available
432
433 if (!storePrivate->serverNullSession) {
434 // if SCDynamicStore session
435 kr = configopen(server,
436 myNameRef,
437 (mach_msg_type_number_t)myNameLen,
438 myOptionsRef,
439 (mach_msg_type_number_t)myOptionsLen,
440 &storePrivate->server,
441 (int *)&sc_status);
442 } else {
443 // if NULL session
444 if (storePrivate->server == MACH_PORT_NULL) {
445 // use the [main] SCDynamicStore server port
446 kr = mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_SEND, +1);
447 if (kr == KERN_SUCCESS) {
448 storePrivate->server = server;
449 sc_status = kSCStatusOK;
450 } else {
451 storePrivate->server = MACH_PORT_NULL;
452 }
453 } else {
454 // if the server port we used returned an error
455 storePrivate->server = MACH_PORT_NULL;
456 kr = MACH_SEND_INVALID_DEST;
457 }
458 }
459
460 if (kr == KERN_SUCCESS) {
461 break;
462 }
463
464 // our [cached] server port is not valid
465 if ((kr != MACH_SEND_INVALID_DEST) && (kr != MIG_SERVER_DIED)) {
466 // if we got an unexpected error, don't retry
467 sc_status = kr;
468 break;
469 }
470
471
472 updateServerPort(storePrivate, &server, &sc_status);
473 }
474 __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreAddSession", storePrivate->server);
475
476 // clean up
477 CFRelease(myName);
478 if (myOptions != NULL) CFRelease(myOptions);
479
480 done :
481
482 switch (sc_status) {
483 case kSCStatusOK :
484 return TRUE;
485 case BOOTSTRAP_UNKNOWN_SERVICE :
486 SCLog(TRUE,
487 (kr == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR,
488 CFSTR("SCDynamicStore server not available"));
489 sc_status = kSCStatusNoStoreServer;
490 break;
491 default :
492 SCLog(TRUE,
493 (kr == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR,
494 CFSTR("SCDynamicStoreAddSession configopen(): %s"),
495 SCErrorString(sc_status));
496 break;
497 }
498
499 _SCErrorSet(sc_status);
500 return FALSE;
501 }
502
503
504 __private_extern__
505 SCDynamicStoreRef
506 __SCDynamicStoreNullSession(void)
507 {
508 SCDynamicStorePrivateRef storePrivate;
509 Boolean ok = TRUE;
510 __SCThreadSpecificDataRef tsd;
511
512 tsd = __SCGetThreadSpecificData();
513 if (tsd->_sc_store == NULL) {
514 storePrivate = __SCDynamicStoreCreatePrivate(NULL,
515 CFSTR("NULL session"),
516 NULL,
517 NULL);
518 assert(storePrivate != NULL);
519 storePrivate->serverNullSession = TRUE;
520 tsd->_sc_store = (SCDynamicStoreRef)storePrivate;
521 }
522
523 storePrivate = (SCDynamicStorePrivateRef)tsd->_sc_store;
524 if (storePrivate->server == MACH_PORT_NULL) {
525 ok = __SCDynamicStoreAddSession(storePrivate);
526 }
527
528 return ok ? tsd->_sc_store : NULL;
529 }
530
531
532 static Boolean
533 __SCDynamicStoreReconnect(SCDynamicStoreRef store)
534 {
535 Boolean ok;
536 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
537
538 ok = __SCDynamicStoreAddSession(storePrivate);
539 return ok;
540 }
541
542
543 __private_extern__
544 Boolean
545 __SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef store,
546 kern_return_t status,
547 int *sc_status,
548 const char *log_str)
549 {
550 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
551
552 if (status == KERN_SUCCESS) {
553 /* no error */
554 return FALSE;
555 }
556
557 if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) {
558 /* the server's gone, remove the session's dead name right */
559 (void) mach_port_deallocate(mach_task_self(), storePrivate->server);
560 storePrivate->server = MACH_PORT_NULL;
561
562 /* reconnect */
563 if (__SCDynamicStoreReconnect(store)) {
564 /* retry needed */
565 return TRUE;
566 }
567 } else {
568 /* an unexpected error, leave the [session] port alone */
569 SCLog(TRUE, LOG_ERR, CFSTR("%s: %s"), log_str, mach_error_string(status));
570 storePrivate->server = MACH_PORT_NULL;
571 }
572
573 *sc_status = status;
574 return FALSE;
575 }
576
577
578 static void
579 pushDisconnect(SCDynamicStoreRef store)
580 {
581 void *context_info;
582 void (*context_release)(const void *);
583 SCDynamicStoreDisconnectCallBack disconnectFunction;
584 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
585
586 disconnectFunction = storePrivate->disconnectFunction;
587 if (disconnectFunction == NULL) {
588 // if no reconnect callout, push empty notification
589 storePrivate->disconnectForceCallBack = TRUE;
590 return;
591 }
592
593 if (storePrivate->rlsContext.retain != NULL) {
594 context_info = (void *)storePrivate->rlsContext.retain(storePrivate->rlsContext.info);
595 context_release = storePrivate->rlsContext.release;
596 } else {
597 context_info = storePrivate->rlsContext.info;
598 context_release = NULL;
599 }
600 (*disconnectFunction)(store, context_info);
601 if (context_release) {
602 context_release(context_info);
603 }
604
605 return;
606 }
607
608
609 __private_extern__
610 Boolean
611 __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store)
612 {
613 dispatch_queue_t dispatchQueue = NULL;
614 __SCDynamicStoreNotificationStatus notifyStatus;
615 Boolean ok = TRUE;
616 CFArrayRef rlList = NULL;
617 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
618
619 // save old SCDynamicStore [notification] state
620 notifyStatus = storePrivate->notifyStatus;
621
622 // before tearing down our [old] notifications, make sure we've
623 // retained any information that will be lost when we cancel the
624 // current no-longer-valid handler
625 switch (notifyStatus) {
626 case Using_NotifierInformViaRunLoop :
627 if (storePrivate->rlList != NULL) {
628 rlList = CFArrayCreateCopy(NULL, storePrivate->rlList);
629 }
630 case Using_NotifierInformViaDispatch :
631 dispatchQueue = storePrivate->dispatchQueue;
632 if (dispatchQueue != NULL) dispatch_retain(dispatchQueue);
633 break;
634 default :
635 break;
636 }
637
638 // cancel [old] notifications
639 if (!SCDynamicStoreNotifyCancel(store)) {
640 // if we could not cancel / reconnect
641 SCLog(TRUE, LOG_DEBUG,
642 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreNotifyCancel() failed: %s"),
643 SCErrorString(SCError()));
644 }
645
646 // set notification keys & patterns
647 if ((storePrivate->keys != NULL) || (storePrivate->patterns)) {
648 ok = SCDynamicStoreSetNotificationKeys(store,
649 storePrivate->keys,
650 storePrivate->patterns);
651 if (!ok) {
652 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE),
653 LOG_ERR,
654 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetNotificationKeys() failed"));
655 goto done;
656 }
657 }
658
659 switch (notifyStatus) {
660 case Using_NotifierInformViaRunLoop : {
661 CFIndex i;
662 CFIndex n;
663 CFRunLoopSourceRef rls;
664
665 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
666 if (rls == NULL) {
667 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE),
668 LOG_ERR,
669 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreCreateRunLoopSource() failed"));
670 ok = FALSE;
671 break;
672 }
673
674 n = (rlList != NULL) ? CFArrayGetCount(rlList) : 0;
675 for (i = 0; i < n; i += 3) {
676 CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
677 CFStringRef rlMode = (CFStringRef) CFArrayGetValueAtIndex(rlList, i+2);
678
679 CFRunLoopAddSource(rl, rls, rlMode);
680 }
681
682 CFRelease(rls);
683 break;
684 }
685 case Using_NotifierInformViaDispatch :
686 ok = SCDynamicStoreSetDispatchQueue(store, dispatchQueue);
687 if (!ok) {
688 SCLog((SCError() != BOOTSTRAP_UNKNOWN_SERVICE),
689 LOG_ERR,
690 CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreSetDispatchQueue() failed"));
691 goto done;
692 }
693 break;
694
695 default :
696 _SCErrorSet(kSCStatusFailed);
697 ok = FALSE;
698 break;
699 }
700
701 done :
702
703 // cleanup
704 switch (notifyStatus) {
705 case Using_NotifierInformViaRunLoop :
706 if (rlList != NULL) CFRelease(rlList);
707 break;
708 case Using_NotifierInformViaDispatch :
709 if (dispatchQueue != NULL) dispatch_release(dispatchQueue);
710 break;
711 default :
712 break;
713 }
714
715 if (!ok) {
716 SCLog(TRUE, LOG_ERR,
717 CFSTR("SCDynamicStore server %s, notification (%s) not restored"),
718 (SCError() == BOOTSTRAP_UNKNOWN_SERVICE) ? "shutdown" : "failed",
719 notifyType[notifyStatus]);
720 }
721
722 // inform the client
723 pushDisconnect(store);
724
725 return ok;
726 }
727
728
729 const CFStringRef kSCDynamicStoreUseSessionKeys = CFSTR("UseSessionKeys"); /* CFBoolean */
730
731
732
733 SCDynamicStoreRef
734 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator,
735 CFStringRef name,
736 CFDictionaryRef storeOptions,
737 SCDynamicStoreCallBack callout,
738 SCDynamicStoreContext *context)
739 {
740 Boolean ok;
741 SCDynamicStorePrivateRef storePrivate;
742
743 // allocate and initialize a new session
744 storePrivate = __SCDynamicStoreCreatePrivate(allocator, NULL, callout, context);
745 if (storePrivate == NULL) {
746 return NULL;
747 }
748
749 // set "name"
750 if (_sc_bundleID != NULL) {
751 storePrivate->name = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"), _sc_bundleID, name);
752 } else {
753 storePrivate->name = CFRetain(name);
754 }
755
756 // set "options"
757
758 if (storeOptions != NULL) {
759 storePrivate->options = CFRetain(storeOptions);
760 }
761
762 // establish SCDynamicStore session
763 ok = __SCDynamicStoreAddSession(storePrivate);
764 if (!ok) {
765 CFRelease(storePrivate);
766 storePrivate = NULL;
767 }
768
769 return (SCDynamicStoreRef)storePrivate;
770 }
771
772
773 SCDynamicStoreRef
774 SCDynamicStoreCreate(CFAllocatorRef allocator,
775 CFStringRef name,
776 SCDynamicStoreCallBack callout,
777 SCDynamicStoreContext *context)
778 {
779 return SCDynamicStoreCreateWithOptions(allocator, name, NULL, callout, context);
780 }
781
782
783 CFTypeID
784 SCDynamicStoreGetTypeID(void) {
785 pthread_once(&initialized, __SCDynamicStoreInitialize); /* initialize runtime */
786 return __kSCDynamicStoreTypeID;
787 }
788
789 Boolean
790 SCDynamicStoreSetDisconnectCallBack(SCDynamicStoreRef store,
791 SCDynamicStoreDisconnectCallBack callout)
792 {
793 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
794
795 if (store == NULL) {
796 /* sorry, you must provide a session */
797 _SCErrorSet(kSCStatusNoStoreSession);
798 return FALSE;
799 }
800
801 storePrivate->disconnectFunction = callout;
802 return TRUE;
803 }