2 * Copyright (c) 2000-2003 Apple Computer, 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 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
36 #include "configd_server.h"
48 const void * keys_q
[N_QUICK
];
49 const void ** keys
= keys_q
;
51 keyCnt
= CFSetGetCount(changedKeys
);
53 return; /* if nothing to do */
55 if (keyCnt
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
)))
56 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
58 CFSetGetValues(changedKeys
, keys
);
60 while (--keyCnt
>= 0) {
64 CFMutableDictionaryRef newInfo
;
65 CFMutableArrayRef newChanges
;
66 CFArrayRef sessionsWatchingKey
;
68 const void * watchers_q
[N_QUICK
];
69 const void ** watchers
= watchers_q
;
71 dict
= CFDictionaryGetValue(storeData
, (CFStringRef
)keys
[keyCnt
]);
72 if ((dict
== NULL
) || (CFDictionaryContainsKey(dict
, kSCDWatchers
) == FALSE
)) {
73 /* key doesn't exist or nobody cares if it changed */
78 * Add this key to the list of changes for each of the
79 * sessions which is "watching".
81 sessionsWatchingKey
= CFDictionaryGetValue(dict
, kSCDWatchers
);
82 watcherCnt
= CFArrayGetCount(sessionsWatchingKey
);
83 if (watcherCnt
== 0) {
88 if (watcherCnt
> (CFIndex
)(sizeof(watchers_q
) / sizeof(CFNumberRef
)))
89 watchers
= CFAllocatorAllocate(NULL
, watcherCnt
* sizeof(CFNumberRef
), 0);
91 CFArrayGetValues(sessionsWatchingKey
, CFRangeMake(0, watcherCnt
), watchers
);
93 while (--watcherCnt
>= 0) {
94 CFStringRef sessionKey
;
96 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@"), watchers
[watcherCnt
]);
97 info
= CFDictionaryGetValue(sessionData
, sessionKey
);
99 newInfo
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
101 newInfo
= CFDictionaryCreateMutable(NULL
,
103 &kCFTypeDictionaryKeyCallBacks
,
104 &kCFTypeDictionaryValueCallBacks
);
107 changes
= CFDictionaryGetValue(newInfo
, kSCDChangedKeys
);
109 newChanges
= CFArrayCreateMutableCopy(NULL
, 0, changes
);
111 newChanges
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
114 if (CFArrayContainsValue(newChanges
,
115 CFRangeMake(0, CFArrayGetCount(newChanges
)),
116 (CFStringRef
)keys
[keyCnt
]) == FALSE
) {
117 CFArrayAppendValue(newChanges
, (CFStringRef
)keys
[keyCnt
]);
119 CFDictionarySetValue(newInfo
, kSCDChangedKeys
, newChanges
);
120 CFRelease(newChanges
);
121 CFDictionarySetValue(sessionData
, sessionKey
, newInfo
);
123 CFRelease(sessionKey
);
126 * flag this session as needing a kick
128 if (needsNotification
== NULL
)
129 needsNotification
= CFSetCreateMutable(NULL
,
131 &kCFTypeSetCallBacks
);
132 CFSetAddValue(needsNotification
, watchers
[watcherCnt
]);
135 if (watchers
!= watchers_q
) CFAllocatorDeallocate(NULL
, watchers
);
138 if (keys
!= keys_q
) CFAllocatorDeallocate(NULL
, keys
);
141 * The list of changed keys have been updated for any sessions
142 * monitoring changes to the "store". The next step, handled by
143 * the "configd" server, is to push out any needed notifications.
145 CFSetRemoveAllValues(changedKeys
);
151 _processDeferredRemovals()
154 const void * keys_q
[N_QUICK
];
155 const void ** keys
= keys_q
;
157 keyCnt
= CFSetGetCount(deferredRemovals
);
159 return; /* if nothing to do */
161 if (keyCnt
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFStringRef
)))
162 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
164 CFSetGetValues(deferredRemovals
, keys
);
166 while (--keyCnt
>= 0) {
167 patternRemoveKey((CFStringRef
)keys
[keyCnt
]);
170 if (keys
!= keys_q
) CFAllocatorDeallocate(NULL
, keys
);
173 * All regex keys associated with removed store dictionary keys have
174 * been removed. Start the list fresh again.
176 CFSetRemoveAllValues(deferredRemovals
);
183 _cleanupRemovedSessionKeys(const void *value
, void *context
)
185 CFStringRef removedKey
= (CFStringRef
)value
;
187 CFStringRef sessionKey
;
189 CFDictionaryRef sessionDict
;
190 CFArrayRef sessionKeys
;
192 CFMutableDictionaryRef newSessionDict
;
194 dRange
= CFStringFind(removedKey
, CFSTR(":"), 0);
195 sessionKey
= CFStringCreateWithSubstring(NULL
,
197 CFRangeMake(0, dRange
.location
));
198 key
= CFStringCreateWithSubstring(NULL
,
200 CFRangeMake(dRange
.location
+dRange
.length
,
201 CFStringGetLength(removedKey
)-dRange
.location
-dRange
.length
));
204 * remove the key from the session key list
206 sessionDict
= CFDictionaryGetValue(sessionData
, sessionKey
);
212 sessionKeys
= CFDictionaryGetValue(sessionDict
, kSCDSessionKeys
);
214 /* if no session keys */
218 i
= CFArrayGetFirstIndexOfValue(sessionKeys
,
219 CFRangeMake(0, CFArrayGetCount(sessionKeys
)),
221 if (i
== kCFNotFound
) {
222 /* if this session key has already been removed */
226 newSessionDict
= CFDictionaryCreateMutableCopy(NULL
, 0, sessionDict
);
227 if (CFArrayGetCount(sessionKeys
) == 1) {
228 /* remove the last (session) key */
229 CFDictionaryRemoveValue(newSessionDict
, kSCDSessionKeys
);
231 CFMutableArrayRef newSessionKeys
;
233 /* remove the (session) key */
234 newSessionKeys
= CFArrayCreateMutableCopy(NULL
, 0, sessionKeys
);
235 CFArrayRemoveValueAtIndex(newSessionKeys
, i
);
236 CFDictionarySetValue(newSessionDict
, kSCDSessionKeys
, newSessionKeys
);
237 CFRelease(newSessionKeys
);
239 CFDictionarySetValue(sessionData
, sessionKey
, newSessionDict
);
240 CFRelease(newSessionDict
);
244 CFRelease(sessionKey
);
253 __SCDynamicStoreUnlock(SCDynamicStoreRef store
, Boolean recursive
)
255 serverSessionRef mySession
;
256 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
258 if (!store
|| (storePrivate
->server
== MACH_PORT_NULL
)) {
259 return kSCStatusNoStoreSession
; /* you must have an open session to play */
262 if ((storeLocked
== 0) || !storePrivate
->locked
) {
263 return kSCStatusNeedLock
; /* sorry, you don't have the lock */
266 if ((storeLocked
> 1) && recursive
) {
267 /* if the lock is being held for a recursive (internal) request */
272 if (!recursive
&& _configd_trace
) {
273 SCTrace(TRUE
, _configd_trace
, CFSTR("unlock : %5d\n"), storePrivate
->server
);
277 * all of the changes can be committed to the (real) store.
279 CFDictionaryRemoveAllValues(storeData_s
);
280 CFDictionaryRemoveAllValues(patternData_s
);
281 CFSetRemoveAllValues (changedKeys_s
);
282 CFSetRemoveAllValues (deferredRemovals_s
);
283 CFSetRemoveAllValues (removedSessionKeys_s
);
286 * push notifications to any session watching those keys which
287 * were recently changed.
292 * process any deferred key deletions.
294 _processDeferredRemovals();
297 * clean up any removed session keys
299 CFSetApplyFunction(removedSessionKeys
, _cleanupRemovedSessionKeys
, NULL
);
300 CFSetRemoveAllValues(removedSessionKeys
);
302 /* Remove the "locked" run loop source for this port */
303 mySession
= getSession(storePrivate
->server
);
304 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession
->serverRunLoopSource
, CFSTR("locked"));
306 storeLocked
= 0; /* global lock flag */
307 storePrivate
->locked
= FALSE
; /* per-session lock flag */
315 _configunlock(mach_port_t server
, int *sc_status
)
317 serverSessionRef mySession
= getSession(server
);
320 *sc_status
= kSCStatusNoStoreSession
; /* you must have an open session to play */
324 *sc_status
= __SCDynamicStoreUnlock(mySession
->store
, FALSE
);
325 if (*sc_status
!= kSCStatusOK
) {