2 * Copyright(c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * February 16, 2004 Allan Nathanson <ajn@apple.com>
28 * - add preference notification APIs
30 * June 1, 2001 Allan Nathanson <ajn@apple.com>
31 * - public API conversion
33 * November 9, 2000 Allan Nathanson <ajn@apple.com>
37 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCValidation.h>
39 #include <SystemConfiguration/SCPrivate.h>
40 #include "SCPreferencesInternal.h"
41 #include "SCHelper_client.h"
43 #include <Security/Security.h>
44 #include "dy_framework.h"
49 #include <sys/errno.h>
53 __SCPreferencesCopyDescription(CFTypeRef cf
) {
54 CFAllocatorRef allocator
= CFGetAllocator(cf
);
55 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)cf
;
56 CFMutableStringRef result
;
58 result
= CFStringCreateMutable(allocator
, 0);
59 CFStringAppendFormat(result
, NULL
, CFSTR("<SCPreferences %p [%p]> {"), cf
, allocator
);
60 CFStringAppendFormat(result
, NULL
, CFSTR("name = %@"), prefsPrivate
->name
);
61 CFStringAppendFormat(result
, NULL
, CFSTR(", id = %@"), prefsPrivate
->prefsID
);
62 CFStringAppendFormat(result
, NULL
, CFSTR(", path = %s"),
63 prefsPrivate
->newPath
? prefsPrivate
->newPath
: prefsPrivate
->path
);
64 if (prefsPrivate
->accessed
) {
65 CFStringAppendFormat(result
, NULL
, CFSTR(", accessed"));
67 if (prefsPrivate
->changed
) {
68 CFStringAppendFormat(result
, NULL
, CFSTR(", changed"));
70 if (prefsPrivate
->locked
) {
71 CFStringAppendFormat(result
, NULL
, CFSTR(", locked"));
73 if (prefsPrivate
->helper
!= -1) {
74 CFStringAppendFormat(result
, NULL
, CFSTR(", helper fd=%d"), prefsPrivate
->helper
);
76 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
83 __SCPreferencesDeallocate(CFTypeRef cf
)
85 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)cf
;
87 /* release resources */
89 pthread_mutex_destroy(&prefsPrivate
->lock
);
91 if (prefsPrivate
->name
) CFRelease(prefsPrivate
->name
);
92 if (prefsPrivate
->prefsID
) CFRelease(prefsPrivate
->prefsID
);
93 if (prefsPrivate
->path
) CFAllocatorDeallocate(NULL
, prefsPrivate
->path
);
94 if (prefsPrivate
->newPath
) CFAllocatorDeallocate(NULL
, prefsPrivate
->newPath
);
95 if (prefsPrivate
->lockFD
!= -1) {
96 if (prefsPrivate
->lockPath
!= NULL
) {
97 unlink(prefsPrivate
->lockPath
);
99 close(prefsPrivate
->lockFD
);
101 if (prefsPrivate
->lockPath
) CFAllocatorDeallocate(NULL
, prefsPrivate
->lockPath
);
102 if (prefsPrivate
->signature
) CFRelease(prefsPrivate
->signature
);
103 if (prefsPrivate
->session
) CFRelease(prefsPrivate
->session
);
104 if (prefsPrivate
->sessionKeyCommit
) CFRelease(prefsPrivate
->sessionKeyCommit
);
105 if (prefsPrivate
->sessionKeyApply
) CFRelease(prefsPrivate
->sessionKeyApply
);
106 if (prefsPrivate
->rlsContext
.release
!= NULL
) {
107 (*prefsPrivate
->rlsContext
.release
)(prefsPrivate
->rlsContext
.info
);
109 if (prefsPrivate
->prefs
) CFRelease(prefsPrivate
->prefs
);
110 if (prefsPrivate
->authorizationData
!= NULL
) CFRelease(prefsPrivate
->authorizationData
);
111 if (prefsPrivate
->helper
!= -1) {
112 (void) _SCHelperExec(prefsPrivate
->helper
, SCHELPER_MSG_PREFS_CLOSE
, NULL
, NULL
, NULL
);
113 _SCHelperClose(prefsPrivate
->helper
);
120 static CFTypeID __kSCPreferencesTypeID
= _kCFRuntimeNotATypeID
;
123 static const CFRuntimeClass __SCPreferencesClass
= {
125 "SCPreferences", // className
128 __SCPreferencesDeallocate
, // dealloc
131 NULL
, // copyFormattingDesc
132 __SCPreferencesCopyDescription
// copyDebugDesc
136 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
139 __SCPreferencesInitialize(void) {
140 __kSCPreferencesTypeID
= _CFRuntimeRegisterClass(&__SCPreferencesClass
);
145 static SCPreferencesPrivateRef
146 __SCPreferencesCreatePrivate(CFAllocatorRef allocator
)
148 SCPreferencesPrivateRef prefsPrivate
;
151 /* initialize runtime */
152 pthread_once(&initialized
, __SCPreferencesInitialize
);
154 /* allocate prefs session */
155 size
= sizeof(SCPreferencesPrivate
) - sizeof(CFRuntimeBase
);
156 prefsPrivate
= (SCPreferencesPrivateRef
)_CFRuntimeCreateInstance(allocator
,
157 __kSCPreferencesTypeID
,
160 if (prefsPrivate
== NULL
) {
164 pthread_mutex_init(&prefsPrivate
->lock
, NULL
);
166 prefsPrivate
->name
= NULL
;
167 prefsPrivate
->prefsID
= NULL
;
168 prefsPrivate
->path
= NULL
;
169 prefsPrivate
->newPath
= NULL
; // new prefs path
170 prefsPrivate
->locked
= FALSE
;
171 prefsPrivate
->lockFD
= -1;
172 prefsPrivate
->lockPath
= NULL
;
173 prefsPrivate
->signature
= NULL
;
174 prefsPrivate
->session
= NULL
;
175 prefsPrivate
->sessionKeyCommit
= NULL
;
176 prefsPrivate
->sessionKeyApply
= NULL
;
177 prefsPrivate
->rls
= NULL
;
178 prefsPrivate
->rlsFunction
= NULL
;
179 prefsPrivate
->rlsContext
.info
= NULL
;
180 prefsPrivate
->rlsContext
.retain
= NULL
;
181 prefsPrivate
->rlsContext
.release
= NULL
;
182 prefsPrivate
->rlsContext
.copyDescription
= NULL
;
183 prefsPrivate
->rlList
= NULL
;
184 prefsPrivate
->prefs
= NULL
;
185 prefsPrivate
->accessed
= FALSE
;
186 prefsPrivate
->changed
= FALSE
;
187 prefsPrivate
->isRoot
= (geteuid() == 0);
188 prefsPrivate
->authorizationData
= NULL
;
189 prefsPrivate
->helper
= -1;
195 __private_extern__ Boolean
196 __SCPreferencesCreate_helper(SCPreferencesRef prefs
)
198 CFDataRef data
= NULL
;
200 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
201 uint32_t status
= kSCStatusOK
;
204 prefsPrivate
->helper
= _SCHelperOpen(prefsPrivate
->authorizationData
);
205 if (prefsPrivate
->helper
== -1) {
209 // serialize the "prefsID"
210 if (prefsPrivate
->prefsID
!= NULL
) {
211 ok
= _SCSerializeString(prefsPrivate
->prefsID
, &data
, NULL
, NULL
);
217 // have the helper "open" the prefs
218 ok
= _SCHelperExec(prefsPrivate
->helper
,
219 SCHELPER_MSG_PREFS_OPEN
,
223 if (data
!= NULL
) CFRelease(data
);
228 if (status
!= kSCStatusOK
) {
237 if (prefsPrivate
->helper
!= -1) {
238 _SCHelperClose(prefsPrivate
->helper
);
239 prefsPrivate
->helper
= -1;
242 status
= kSCStatusAccessError
;
253 __SCPreferencesAccess_helper(SCPreferencesRef prefs
)
256 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
257 CFDictionaryRef serverDict
= NULL
;
258 CFDictionaryRef serverPrefs
= NULL
;
259 CFDictionaryRef serverSignature
= NULL
;
260 uint32_t status
= kSCStatusOK
;
261 CFDataRef reply
= NULL
;
263 if (prefsPrivate
->helper
== -1) {
264 ok
= __SCPreferencesCreate_helper(prefs
);
270 // have the helper "access" the prefs
271 ok
= _SCHelperExec(prefsPrivate
->helper
,
272 SCHELPER_MSG_PREFS_ACCESS
,
280 if (status
!= kSCStatusOK
) {
288 ok
= _SCUnserialize((CFPropertyListRef
*)&serverDict
, reply
, NULL
, 0);
294 if (isA_CFDictionary(serverDict
)) {
295 serverPrefs
= CFDictionaryGetValue(serverDict
, CFSTR("preferences"));
296 serverSignature
= CFDictionaryGetValue(serverDict
, CFSTR("signature"));
299 if (!isA_CFDictionary(serverPrefs
) || !isA_CFData(serverSignature
)) {
300 CFRelease(serverDict
);
304 prefsPrivate
->prefs
= CFDictionaryCreateMutableCopy(NULL
, 0, serverPrefs
);
305 prefsPrivate
->signature
= CFRetain(serverSignature
);
306 prefsPrivate
->accessed
= TRUE
;
307 CFRelease(serverDict
);
314 if (prefsPrivate
->helper
!= -1) {
315 _SCHelperClose(prefsPrivate
->helper
);
316 prefsPrivate
->helper
= -1;
319 status
= kSCStatusAccessError
;
329 static SCPreferencesPrivateRef
330 __SCPreferencesCreate(CFAllocatorRef allocator
,
333 CFDataRef authorizationData
)
336 SCPreferencesPrivateRef prefsPrivate
;
337 int sc_status
= kSCStatusOK
;
340 * allocate and initialize a new prefs session
342 prefsPrivate
= __SCPreferencesCreatePrivate(allocator
);
343 if (prefsPrivate
== NULL
) {
347 prefsPrivate
->name
= CFStringCreateCopy(allocator
, name
);
348 if (prefsID
!= NULL
) {
349 prefsPrivate
->prefsID
= CFStringCreateCopy(allocator
, prefsID
);
351 if (authorizationData
!= NULL
) {
352 prefsPrivate
->authorizationData
= CFRetain(authorizationData
);
358 * convert prefsID to path
360 prefsPrivate
->path
= __SCPreferencesPath(allocator
,
362 (prefsPrivate
->newPath
== NULL
));
363 if (prefsPrivate
->path
== NULL
) {
364 sc_status
= kSCStatusFailed
;
371 fd
= open(prefsPrivate
->path
, O_RDONLY
, 0644);
378 if ((prefsID
== NULL
) || !CFStringHasPrefix(prefsID
, CFSTR("/"))) {
379 /* if default preference ID or relative path */
380 if (prefsPrivate
->newPath
== NULL
) {
382 * we've looked in the "new" prefs directory
383 * without success. Save the "new" path and
384 * look in the "old" prefs directory.
386 prefsPrivate
->newPath
= prefsPrivate
->path
;
390 * we've looked in both the "new" and "old"
391 * prefs directories without success. Use
394 CFAllocatorDeallocate(NULL
, prefsPrivate
->path
);
395 prefsPrivate
->path
= prefsPrivate
->newPath
;
396 prefsPrivate
->newPath
= NULL
;
400 /* no preference data, start fresh */
401 sc_status
= kSCStatusNoConfigFile
;
404 if (prefsPrivate
->authorizationData
!= NULL
) {
405 /* no problem, we'll be using the helper */
409 sc_status
= kSCStatusAccessError
;
412 sc_status
= kSCStatusFailed
;
415 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCPreferencesCreate open() failed: %s"), strerror(errno
));
422 _SCErrorSet(sc_status
);
427 if (fd
!= -1) (void) close(fd
);
428 CFRelease(prefsPrivate
);
429 _SCErrorSet(sc_status
);
434 __private_extern__
void
435 __SCPreferencesAccess(SCPreferencesRef prefs
)
437 CFAllocatorRef allocator
= CFGetAllocator(prefs
);
439 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
442 if (prefsPrivate
->accessed
) {
443 // if preference data has already been accessed
447 fd
= open(prefsPrivate
->path
, O_RDONLY
, 0644);
450 if (fstat(fd
, &statBuf
) == -1) {
451 SCLog(TRUE
, LOG_ERR
, CFSTR("__SCPreferencesAccess fstat() failed: %s"), strerror(errno
));
452 bzero(&statBuf
, sizeof(statBuf
));
457 /* no preference data, start fresh */
460 if (prefsPrivate
->authorizationData
!= NULL
) {
461 if (__SCPreferencesAccess_helper(prefs
)) {
465 CFSTR("__SCPreferencesAccess_helper() failed: %s"),
466 SCErrorString(SCError()));
472 SCLog(TRUE
, LOG_ERR
, CFSTR("__SCPreferencesAccess open() failed: %s"), strerror(errno
));
475 bzero(&statBuf
, sizeof(statBuf
));
478 if (prefsPrivate
->signature
!= NULL
) CFRelease(prefsPrivate
->signature
);
479 prefsPrivate
->signature
= __SCPSignatureFromStatbuf(&statBuf
);
481 if (statBuf
.st_size
> 0) {
482 CFDictionaryRef dict
;
483 CFMutableDataRef xmlData
;
484 CFStringRef xmlError
;
487 * extract property list
489 xmlData
= CFDataCreateMutable(allocator
, statBuf
.st_size
);
490 CFDataSetLength(xmlData
, statBuf
.st_size
);
491 if (read(fd
, (void *)CFDataGetBytePtr(xmlData
), statBuf
.st_size
) != statBuf
.st_size
) {
492 /* corrupt prefs file, start fresh */
493 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCPreferencesAccess read(): could not load preference data."));
502 dict
= CFPropertyListCreateFromXMLData(allocator
,
504 kCFPropertyListImmutable
,
508 /* corrupt prefs file, start fresh */
509 if (xmlError
!= NULL
) {
511 CFSTR("__SCPreferencesAccess CFPropertyListCreateFromXMLData(): %@"),
519 * make sure that we've got a dictionary
521 if (!isA_CFDictionary(dict
)) {
522 /* corrupt prefs file, start fresh */
523 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCPreferencesAccess CFGetTypeID(): not a dictionary."));
528 prefsPrivate
->prefs
= CFDictionaryCreateMutableCopy(allocator
, 0, dict
);
539 if (prefsPrivate
->prefs
== NULL
) {
541 * new file, create empty preferences
543 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCPreferencesAccess(): creating new preferences file."));
544 prefsPrivate
->prefs
= CFDictionaryCreateMutable(allocator
,
546 &kCFTypeDictionaryKeyCallBacks
,
547 &kCFTypeDictionaryValueCallBacks
);
548 prefsPrivate
->changed
= TRUE
;
551 prefsPrivate
->accessed
= TRUE
;
557 SCPreferencesCreate(CFAllocatorRef allocator
,
561 SCPreferencesPrivateRef prefsPrivate
;
563 prefsPrivate
= __SCPreferencesCreate(allocator
, name
, prefsID
, NULL
);
564 return (SCPreferencesRef
)prefsPrivate
;
569 SCPreferencesCreateWithAuthorization(CFAllocatorRef allocator
,
572 AuthorizationRef authorization
)
574 CFDataRef authorizationData
;
575 AuthorizationExternalForm extForm
;
577 SCPreferencesPrivateRef prefsPrivate
;
579 os_status
= AuthorizationMakeExternalForm(authorization
, &extForm
);
580 if (os_status
!= errAuthorizationSuccess
) {
581 SCLog(TRUE
, LOG_INFO
, CFSTR("_SCHelperOpen AuthorizationMakeExternalForm() failed"));
582 _SCErrorSet(kSCStatusInvalidArgument
);
586 authorizationData
= CFDataCreate(NULL
, (const UInt8
*)extForm
.bytes
, sizeof(extForm
.bytes
));
587 prefsPrivate
= __SCPreferencesCreate(allocator
, name
, prefsID
, authorizationData
);
588 CFRelease(authorizationData
);
590 return (SCPreferencesRef
)prefsPrivate
;
595 SCPreferencesGetTypeID(void) {
596 pthread_once(&initialized
, __SCPreferencesInitialize
); /* initialize runtime */
597 return __kSCPreferencesTypeID
;
602 prefsNotify(SCDynamicStoreRef store
, CFArrayRef changedKeys
, void *info
)
605 void (*context_release
)(const void *);
608 SCPreferencesNotification notify
= 0;
609 SCPreferencesRef prefs
= (SCPreferencesRef
)info
;
610 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
611 SCPreferencesCallBack rlsFunction
;
613 n
= (changedKeys
!= NULL
) ? CFArrayGetCount(changedKeys
) : 0;
614 for (i
= 0; i
< n
; i
++) {
617 key
= CFArrayGetValueAtIndex(changedKeys
, i
);
618 if (CFEqual(key
, prefsPrivate
->sessionKeyCommit
)) {
619 // if preferences have been saved
620 notify
|= kSCPreferencesNotificationCommit
;
622 if (CFEqual(key
, prefsPrivate
->sessionKeyApply
)) {
623 // if stored preferences should be applied to current configuration
624 notify
|= kSCPreferencesNotificationApply
;
633 pthread_mutex_lock(&prefsPrivate
->lock
);
636 rlsFunction
= prefsPrivate
->rlsFunction
;
637 if (prefsPrivate
->rlsContext
.retain
!= NULL
) {
638 context_info
= (void *)prefsPrivate
->rlsContext
.retain(prefsPrivate
->rlsContext
.info
);
639 context_release
= prefsPrivate
->rlsContext
.release
;
641 context_info
= prefsPrivate
->rlsContext
.info
;
642 context_release
= NULL
;
645 pthread_mutex_unlock(&prefsPrivate
->lock
);
647 if (rlsFunction
!= NULL
) {
648 (*rlsFunction
)(prefs
, notify
, context_info
);
651 if (context_release
!= NULL
) {
652 (*context_release
)(context_info
);
659 __private_extern__ Boolean
660 __SCPreferencesAddSession(SCPreferencesRef prefs
)
662 CFAllocatorRef allocator
= CFGetAllocator(prefs
);
663 SCDynamicStoreContext context
= { 0
669 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
671 /* establish a dynamic store session */
672 prefsPrivate
->session
= SCDynamicStoreCreate(allocator
,
673 CFSTR("SCPreferences"),
676 if (prefsPrivate
->session
== NULL
) {
677 SCLog(_sc_verbose
, LOG_INFO
, CFSTR("__SCPreferencesAddSession SCDynamicStoreCreate() failed"));
681 /* create the session "commit" key */
682 prefsPrivate
->sessionKeyCommit
= _SCPNotificationKey(NULL
,
683 prefsPrivate
->prefsID
,
684 kSCPreferencesKeyCommit
);
686 /* create the session "apply" key */
687 prefsPrivate
->sessionKeyApply
= _SCPNotificationKey(NULL
,
688 prefsPrivate
->prefsID
,
689 kSCPreferencesKeyApply
);
696 SCPreferencesSetCallback(SCPreferencesRef prefs
,
697 SCPreferencesCallBack callout
,
698 SCPreferencesContext
*context
)
700 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
703 /* sorry, you must provide a session */
704 _SCErrorSet(kSCStatusNoPrefsSession
);
708 pthread_mutex_lock(&prefsPrivate
->lock
);
710 if (prefsPrivate
->rlsContext
.release
!= NULL
) {
711 /* let go of the current context */
712 (*prefsPrivate
->rlsContext
.release
)(prefsPrivate
->rlsContext
.info
);
715 prefsPrivate
->rlsFunction
= callout
;
716 prefsPrivate
->rlsContext
.info
= NULL
;
717 prefsPrivate
->rlsContext
.retain
= NULL
;
718 prefsPrivate
->rlsContext
.release
= NULL
;
719 prefsPrivate
->rlsContext
.copyDescription
= NULL
;
720 if (context
!= NULL
) {
721 bcopy(context
, &prefsPrivate
->rlsContext
, sizeof(SCPreferencesContext
));
722 if (context
->retain
!= NULL
) {
723 prefsPrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
727 pthread_mutex_unlock(&prefsPrivate
->lock
);
734 SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs
,
735 CFRunLoopRef runLoop
,
736 CFStringRef runLoopMode
)
738 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
741 /* sorry, you must provide a session */
742 _SCErrorSet(kSCStatusNoPrefsSession
);
746 pthread_mutex_lock(&prefsPrivate
->lock
);
748 if (prefsPrivate
->rls
== NULL
) {
749 CFMutableArrayRef keys
;
751 if (prefsPrivate
->session
== NULL
) {
752 __SCPreferencesAddSession(prefs
);
755 CFRetain(prefs
); // hold a reference to the prefs
757 keys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
758 CFArrayAppendValue(keys
, prefsPrivate
->sessionKeyCommit
);
759 CFArrayAppendValue(keys
, prefsPrivate
->sessionKeyApply
);
760 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate
->session
, keys
, NULL
);
763 prefsPrivate
->rls
= SCDynamicStoreCreateRunLoopSource(NULL
, prefsPrivate
->session
, 0);
764 prefsPrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
767 if (!_SC_isScheduled(NULL
, runLoop
, runLoopMode
, prefsPrivate
->rlList
)) {
769 * if we do not already have notifications scheduled with
770 * this runLoop / runLoopMode
772 CFRunLoopAddSource(runLoop
, prefsPrivate
->rls
, runLoopMode
);
775 _SC_schedule(prefs
, runLoop
, runLoopMode
, prefsPrivate
->rlList
);
777 pthread_mutex_unlock(&prefsPrivate
->lock
);
783 SCPreferencesUnscheduleFromRunLoop(SCPreferencesRef prefs
,
784 CFRunLoopRef runLoop
,
785 CFStringRef runLoopMode
)
787 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
792 /* sorry, you must provide a session */
793 _SCErrorSet(kSCStatusNoPrefsSession
);
797 pthread_mutex_lock(&prefsPrivate
->lock
);
799 if (prefsPrivate
->rls
== NULL
) {
800 /* if not currently scheduled */
804 if (!_SC_unschedule(NULL
, runLoop
, runLoopMode
, prefsPrivate
->rlList
, FALSE
)) {
805 /* if not currently scheduled */
809 n
= CFArrayGetCount(prefsPrivate
->rlList
);
810 if (n
== 0 || !_SC_isScheduled(NULL
, runLoop
, runLoopMode
, prefsPrivate
->rlList
)) {
812 * if we are no longer scheduled to receive notifications for
813 * this runLoop / runLoopMode
815 CFRunLoopRemoveSource(runLoop
, prefsPrivate
->rls
, runLoopMode
);
818 CFArrayRef changedKeys
;
821 * if *all* notifications have been unscheduled
823 CFRunLoopSourceInvalidate(prefsPrivate
->rls
);
824 CFRelease(prefsPrivate
->rls
);
825 prefsPrivate
->rls
= NULL
;
826 CFRelease(prefsPrivate
->rlList
);
827 prefsPrivate
->rlList
= NULL
;
829 CFRelease(prefs
); // release our reference to the prefs
831 // no need to track changes
832 (void) SCDynamicStoreSetNotificationKeys(prefsPrivate
->session
, NULL
, NULL
);
834 // clear out any pending notifications
835 changedKeys
= SCDynamicStoreCopyNotifiedKeys(prefsPrivate
->session
);
836 if (changedKeys
!= NULL
) {
837 CFRelease(changedKeys
);
846 pthread_mutex_unlock(&prefsPrivate
->lock
);
852 __SCPreferencesSynchronize_helper(SCPreferencesRef prefs
)
855 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
856 uint32_t status
= kSCStatusOK
;
858 if (prefsPrivate
->helper
== -1) {
863 // have the helper "synchronize" the prefs
864 ok
= _SCHelperExec(prefsPrivate
->helper
,
865 SCHELPER_MSG_PREFS_SYNCHRONIZE
,
871 if (prefsPrivate
->helper
!= -1) {
872 _SCHelperClose(prefsPrivate
->helper
);
873 prefsPrivate
->helper
= -1;
882 SCPreferencesSynchronize(SCPreferencesRef prefs
)
884 SCPreferencesPrivateRef prefsPrivate
= (SCPreferencesPrivateRef
)prefs
;
887 /* sorry, you must provide a session */
888 _SCErrorSet(kSCStatusNoPrefsSession
);
892 if (prefsPrivate
->authorizationData
!= NULL
) {
893 __SCPreferencesSynchronize_helper(prefs
);
896 if (prefsPrivate
->prefs
!= NULL
) {
897 CFRelease(prefsPrivate
->prefs
);
898 prefsPrivate
->prefs
= NULL
;
900 if (prefsPrivate
->signature
!= NULL
) {
901 CFRelease(prefsPrivate
->signature
);
902 prefsPrivate
->signature
= NULL
;
904 prefsPrivate
->accessed
= FALSE
;
905 prefsPrivate
->changed
= FALSE
;