2 * Copyright (c) 2000 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@
25 #include "configd_server.h"
35 if ((keyCnt
= CFSetGetCount(changedKeys
)) == 0)
36 return; /* if nothing to do */
38 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
39 CFSetGetValues(changedKeys
, keys
);
40 while (--keyCnt
>= 0) {
42 CFArrayRef sessionsWatchingKey
;
46 CFMutableDictionaryRef newInfo
;
48 CFMutableArrayRef newChanges
;
50 dict
= CFDictionaryGetValue(cacheData
, (CFStringRef
)keys
[keyCnt
]);
51 if ((dict
== NULL
) || (CFDictionaryContainsKey(dict
, kSCDWatchers
) == FALSE
)) {
52 /* key doesn't exist or nobody cares if it changed */
57 * Add this key to the list of changes for each of the
58 * sessions which is "watching".
60 sessionsWatchingKey
= CFDictionaryGetValue(dict
, kSCDWatchers
);
61 watcherCnt
= CFArrayGetCount(sessionsWatchingKey
);
62 watchers
= CFAllocatorAllocate(NULL
, watcherCnt
* sizeof(CFNumberRef
), 0);
63 CFArrayGetValues(sessionsWatchingKey
,
64 CFRangeMake(0, CFArrayGetCount(sessionsWatchingKey
)),
66 while (--watcherCnt
>= 0) {
67 CFStringRef sessionKey
;
69 sessionKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@"), watchers
[watcherCnt
]);
70 info
= CFDictionaryGetValue(sessionData
, sessionKey
);
72 newInfo
= CFDictionaryCreateMutableCopy(NULL
, 0, info
);
74 newInfo
= CFDictionaryCreateMutable(NULL
,
76 &kCFTypeDictionaryKeyCallBacks
,
77 &kCFTypeDictionaryValueCallBacks
);
80 changes
= CFDictionaryGetValue(newInfo
, kSCDChangedKeys
);
82 newChanges
= CFArrayCreateMutableCopy(NULL
, 0, changes
);
84 newChanges
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
87 if (CFArrayContainsValue(newChanges
,
88 CFRangeMake(0, CFArrayGetCount(newChanges
)),
89 (CFStringRef
)keys
[keyCnt
]) == FALSE
) {
90 CFArrayAppendValue(newChanges
, (CFStringRef
)keys
[keyCnt
]);
92 CFDictionarySetValue(newInfo
, kSCDChangedKeys
, newChanges
);
93 CFRelease(newChanges
);
94 CFDictionarySetValue(sessionData
, sessionKey
, newInfo
);
96 CFRelease(sessionKey
);
99 * flag this session as needing a kick
101 if (needsNotification
== NULL
)
102 needsNotification
= CFSetCreateMutable(NULL
,
104 &kCFTypeSetCallBacks
);
105 CFSetAddValue(needsNotification
, watchers
[watcherCnt
]);
107 CFAllocatorDeallocate(NULL
, watchers
);
109 CFAllocatorDeallocate(NULL
, keys
);
112 * The list of changed keys have been updated for any sessions
113 * monitoring changes to the "cache". The next step, handled by
114 * the "configd" server, is to push out any needed notifications.
116 CFSetRemoveAllValues(changedKeys
);
122 _processDeferredRemovals()
127 if ((keyCnt
= CFSetGetCount(deferredRemovals
)) == 0)
128 return; /* if nothing to do */
130 keys
= CFAllocatorAllocate(NULL
, keyCnt
* sizeof(CFStringRef
), 0);
131 CFSetGetValues(deferredRemovals
, keys
);
132 while (--keyCnt
>= 0) {
133 CFDictionaryApplyFunction(sessionData
,
134 (CFDictionaryApplierFunction
)_removeRegexWatchersBySession
,
137 CFAllocatorDeallocate(NULL
, keys
);
140 * All regex keys associated with removed cache dictionary keys have
141 * been removed. Start the list fresh again.
143 CFSetRemoveAllValues(deferredRemovals
);
150 _cleanupRemovedSessionKeys(const void *value
, void *context
)
152 CFStringRef removedKey
= (CFStringRef
)value
;
154 CFStringRef sessionKey
;
156 CFDictionaryRef sessionDict
;
157 CFArrayRef sessionKeys
;
159 CFMutableDictionaryRef newSessionDict
;
161 dRange
= CFStringFind(removedKey
, CFSTR(":"), 0);
162 sessionKey
= CFStringCreateWithSubstring(NULL
,
164 CFRangeMake(0, dRange
.location
));
165 key
= CFStringCreateWithSubstring(NULL
,
167 CFRangeMake(dRange
.location
+dRange
.length
,
168 CFStringGetLength(removedKey
)-dRange
.location
-dRange
.length
));
171 * remove the key from the session key list
173 sessionDict
= CFDictionaryGetValue(sessionData
, sessionKey
);
179 sessionKeys
= CFDictionaryGetValue(sessionDict
, kSCDSessionKeys
);
181 /* if no session keys */
185 i
= CFArrayGetFirstIndexOfValue(sessionKeys
,
186 CFRangeMake(0, CFArrayGetCount(sessionKeys
)),
189 /* if this session key has already been removed */
193 newSessionDict
= CFDictionaryCreateMutableCopy(NULL
, 0, sessionDict
);
194 if (CFArrayGetCount(sessionKeys
) == 1) {
195 /* remove the last (session) key */
196 CFDictionaryRemoveValue(newSessionDict
, kSCDSessionKeys
);
198 CFMutableArrayRef newSessionKeys
;
200 /* remove the (session) key */
201 newSessionKeys
= CFArrayCreateMutableCopy(NULL
, 0, sessionKeys
);
202 CFArrayRemoveValueAtIndex(newSessionKeys
, i
);
203 CFDictionarySetValue(newSessionDict
, kSCDSessionKeys
, newSessionKeys
);
204 CFRelease(newSessionKeys
);
206 CFDictionarySetValue(sessionData
, sessionKey
, newSessionDict
);
207 CFRelease(newSessionDict
);
211 CFRelease(sessionKey
);
219 _SCDUnlock(SCDSessionRef session
)
221 SCDSessionPrivateRef sessionPrivate
= (SCDSessionPrivateRef
)session
;
222 serverSessionRef mySession
;
224 SCDLog(LOG_DEBUG
, CFSTR("_SCDUnlock:"));
226 if ((session
== NULL
) || (sessionPrivate
->server
== MACH_PORT_NULL
)) {
227 return SCD_NOSESSION
;
230 if (!SCDOptionGet(NULL
, kSCDOptionIsLocked
) || !SCDOptionGet(session
, kSCDOptionIsLocked
)) {
231 return SCD_NEEDLOCK
; /* sorry, you don't have the lock */
235 * all of the changes can be committed to the (real) cache.
237 CFDictionaryRemoveAllValues(cacheData_s
);
238 CFSetRemoveAllValues (changedKeys_s
);
239 CFSetRemoveAllValues (deferredRemovals_s
);
240 CFSetRemoveAllValues (removedSessionKeys_s
);
243 SCDLog(LOG_DEBUG
, CFSTR("keys I changed = %@"), changedKeys
);
244 SCDLog(LOG_DEBUG
, CFSTR("keys flagged for removal = %@"), deferredRemovals
);
245 SCDLog(LOG_DEBUG
, CFSTR("keys I'm watching = %@"), sessionPrivate
->keys
);
246 SCDLog(LOG_DEBUG
, CFSTR("regex keys I'm watching = %@"), sessionPrivate
->reKeys
);
250 * push notifications to any session watching those keys which
251 * were recently changed.
256 * process any deferred key deletions.
258 _processDeferredRemovals();
261 * clean up any removed session keys
263 CFSetApplyFunction(removedSessionKeys
, _cleanupRemovedSessionKeys
, NULL
);
264 CFSetRemoveAllValues(removedSessionKeys
);
267 SCDLog(LOG_DEBUG
, CFSTR("sessions to notify = %@"), needsNotification
);
270 /* Remove the "locked" run loop source for this port */
271 mySession
= getSession(sessionPrivate
->server
);
272 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession
->serverRunLoopSource
, CFSTR("locked"));
274 SCDOptionSet(NULL
, kSCDOptionIsLocked
, FALSE
); /* global lock flag */
275 SCDOptionSet(session
, kSCDOptionIsLocked
, FALSE
); /* per-session lock flag */
282 _configunlock(mach_port_t server
, int *scd_status
)
284 serverSessionRef mySession
= getSession(server
);
286 SCDLog(LOG_DEBUG
, CFSTR("Unlock configuration database."));
287 SCDLog(LOG_DEBUG
, CFSTR(" server = %d"), server
);
289 *scd_status
= _SCDUnlock(mySession
->session
);
290 if (*scd_status
!= SCD_OK
) {
291 SCDLog(LOG_DEBUG
, CFSTR(" _SCDUnlock(): %s"), SCDError(*scd_status
));