2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
29 * March 24, 2000 Allan Nathanson <ajn@apple.com>
35 #include "configd_server.h"
45 keyCnt
= CFSetGetCount(changedKeys
);
47 return; /* if nothing to do */
49 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
50 CFSetGetValues(changedKeys
, keys
);
51 while (--keyCnt
>= 0) {
53 CFArrayRef sessionsWatchingKey
;
55 const void **watchers
;
57 CFMutableDictionaryRef newInfo
;
59 CFMutableArrayRef newChanges
;
61 dict
= CFDictionaryGetValue(storeData
, (CFStringRef
)keys
[keyCnt
]);
62 if ((dict
== NULL
) || (CFDictionaryContainsKey(dict
, kSCDWatchers
) == FALSE
)) {
63 /* key doesn't exist or nobody cares if it changed */
68 * Add this key to the list of changes for each of the
69 * sessions which is "watching".
71 sessionsWatchingKey
= CFDictionaryGetValue(dict
, kSCDWatchers
);
72 watcherCnt
= CFArrayGetCount(sessionsWatchingKey
);
74 watchers
= CFAllocatorAllocate(NULL
, watcherCnt
* sizeof(CFNumberRef
), 0);
75 CFArrayGetValues(sessionsWatchingKey
,
76 CFRangeMake(0, CFArrayGetCount(sessionsWatchingKey
)),
78 while (--watcherCnt
>= 0) {
79 CFStringRef sessionKey
;
81 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@"), watchers
[watcherCnt
]);
82 info
= CFDictionaryGetValue(sessionData
, sessionKey
);
84 newInfo
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
86 newInfo
= CFDictionaryCreateMutable(NULL
,
88 &kCFTypeDictionaryKeyCallBacks
,
89 &kCFTypeDictionaryValueCallBacks
);
92 changes
= CFDictionaryGetValue(newInfo
, kSCDChangedKeys
);
94 newChanges
= CFArrayCreateMutableCopy(NULL
, 0, changes
);
96 newChanges
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
99 if (CFArrayContainsValue(newChanges
,
100 CFRangeMake(0, CFArrayGetCount(newChanges
)),
101 (CFStringRef
)keys
[keyCnt
]) == FALSE
) {
102 CFArrayAppendValue(newChanges
, (CFStringRef
)keys
[keyCnt
]);
104 CFDictionarySetValue(newInfo
, kSCDChangedKeys
, newChanges
);
105 CFRelease(newChanges
);
106 CFDictionarySetValue(sessionData
, sessionKey
, newInfo
);
108 CFRelease(sessionKey
);
111 * flag this session as needing a kick
113 if (needsNotification
== NULL
)
114 needsNotification
= CFSetCreateMutable(NULL
,
116 &kCFTypeSetCallBacks
);
117 CFSetAddValue(needsNotification
, watchers
[watcherCnt
]);
119 CFAllocatorDeallocate(NULL
, watchers
);
122 CFAllocatorDeallocate(NULL
, keys
);
125 * The list of changed keys have been updated for any sessions
126 * monitoring changes to the "store". The next step, handled by
127 * the "configd" server, is to push out any needed notifications.
129 CFSetRemoveAllValues(changedKeys
);
135 _processDeferredRemovals()
140 keyCnt
= CFSetGetCount(deferredRemovals
);
142 return; /* if nothing to do */
144 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
145 CFSetGetValues(deferredRemovals
, keys
);
146 while (--keyCnt
>= 0) {
147 CFDictionaryApplyFunction(sessionData
,
148 (CFDictionaryApplierFunction
)_removeRegexWatchersBySession
,
149 (void *)keys
[keyCnt
]);
151 CFAllocatorDeallocate(NULL
, keys
);
154 * All regex keys associated with removed store dictionary keys have
155 * been removed. Start the list fresh again.
157 CFSetRemoveAllValues(deferredRemovals
);
164 _cleanupRemovedSessionKeys(const void *value
, void *context
)
166 CFStringRef removedKey
= (CFStringRef
)value
;
168 CFStringRef sessionKey
;
170 CFDictionaryRef sessionDict
;
171 CFArrayRef sessionKeys
;
173 CFMutableDictionaryRef newSessionDict
;
175 dRange
= CFStringFind(removedKey
, CFSTR(":"), 0);
176 sessionKey
= CFStringCreateWithSubstring(NULL
,
178 CFRangeMake(0, dRange
.location
));
179 key
= CFStringCreateWithSubstring(NULL
,
181 CFRangeMake(dRange
.location
+dRange
.length
,
182 CFStringGetLength(removedKey
)-dRange
.location
-dRange
.length
));
185 * remove the key from the session key list
187 sessionDict
= CFDictionaryGetValue(sessionData
, sessionKey
);
193 sessionKeys
= CFDictionaryGetValue(sessionDict
, kSCDSessionKeys
);
195 /* if no session keys */
199 i
= CFArrayGetFirstIndexOfValue(sessionKeys
,
200 CFRangeMake(0, CFArrayGetCount(sessionKeys
)),
203 /* if this session key has already been removed */
207 newSessionDict
= CFDictionaryCreateMutableCopy(NULL
, 0, sessionDict
);
208 if (CFArrayGetCount(sessionKeys
) == 1) {
209 /* remove the last (session) key */
210 CFDictionaryRemoveValue(newSessionDict
, kSCDSessionKeys
);
212 CFMutableArrayRef newSessionKeys
;
214 /* remove the (session) key */
215 newSessionKeys
= CFArrayCreateMutableCopy(NULL
, 0, sessionKeys
);
216 CFArrayRemoveValueAtIndex(newSessionKeys
, i
);
217 CFDictionarySetValue(newSessionDict
, kSCDSessionKeys
, newSessionKeys
);
218 CFRelease(newSessionKeys
);
220 CFDictionarySetValue(sessionData
, sessionKey
, newSessionDict
);
221 CFRelease(newSessionDict
);
225 CFRelease(sessionKey
);
233 __SCDynamicStoreUnlock(SCDynamicStoreRef store
, Boolean recursive
)
235 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
236 serverSessionRef mySession
;
238 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("__SCDynamicStoreUnlock:"));
240 if (!store
|| (storePrivate
->server
== MACH_PORT_NULL
)) {
241 return kSCStatusNoStoreSession
; /* you must have an open session to play */
244 if ((storeLocked
== 0) || !storePrivate
->locked
) {
245 return kSCStatusNeedLock
; /* sorry, you don't have the lock */
248 if ((storeLocked
> 1) && recursive
) {
249 /* if the lock is being held for a recursive (internal) request */
255 * all of the changes can be committed to the (real) store.
257 CFDictionaryRemoveAllValues(storeData_s
);
258 CFSetRemoveAllValues (changedKeys_s
);
259 CFSetRemoveAllValues (deferredRemovals_s
);
260 CFSetRemoveAllValues (removedSessionKeys_s
);
263 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("keys I changed = %@"), changedKeys
);
264 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("keys flagged for removal = %@"), deferredRemovals
);
265 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("keys I'm watching = %@"), storePrivate
->keys
);
266 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("regex keys I'm watching = %@"), storePrivate
->reKeys
);
270 * push notifications to any session watching those keys which
271 * were recently changed.
276 * process any deferred key deletions.
278 _processDeferredRemovals();
281 * clean up any removed session keys
283 CFSetApplyFunction(removedSessionKeys
, _cleanupRemovedSessionKeys
, NULL
);
284 CFSetRemoveAllValues(removedSessionKeys
);
287 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("sessions to notify = %@"), needsNotification
);
290 /* Remove the "locked" run loop source for this port */
291 mySession
= getSession(storePrivate
->server
);
292 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession
->serverRunLoopSource
, CFSTR("locked"));
294 storeLocked
= 0; /* global lock flag */
295 storePrivate
->locked
= FALSE
; /* per-session lock flag */
302 _configunlock(mach_port_t server
, int *sc_status
)
304 serverSessionRef mySession
= getSession(server
);
306 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("Unlock configuration database."));
307 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR(" server = %d"), server
);
309 *sc_status
= __SCDynamicStoreUnlock(mySession
->store
, FALSE
);
310 if (*sc_status
!= kSCStatusOK
) {
311 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR(" __SCDynamicStoreUnlock(): %s"), SCErrorString(*sc_status
));