]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configunlock.c
configd-24.1.tar.gz
[apple/configd.git] / configd.tproj / _configunlock.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23
24 #include "configd.h"
25 #include "configd_server.h"
26 #include "session.h"
27
28
29 static void
30 _notifyWatchers()
31 {
32 CFIndex keyCnt;
33 void **keys;
34
35 if ((keyCnt = CFSetGetCount(changedKeys)) == 0)
36 return; /* if nothing to do */
37
38 keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
39 CFSetGetValues(changedKeys, keys);
40 while (--keyCnt >= 0) {
41 CFDictionaryRef dict;
42 CFArrayRef sessionsWatchingKey;
43 CFIndex watcherCnt;
44 void **watchers;
45 CFDictionaryRef info;
46 CFMutableDictionaryRef newInfo;
47 CFArrayRef changes;
48 CFMutableArrayRef newChanges;
49
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 */
53 continue;
54 }
55
56 /*
57 * Add this key to the list of changes for each of the
58 * sessions which is "watching".
59 */
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)),
65 watchers);
66 while (--watcherCnt >= 0) {
67 CFStringRef sessionKey;
68
69 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), watchers[watcherCnt]);
70 info = CFDictionaryGetValue(sessionData, sessionKey);
71 if (info) {
72 newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
73 } else {
74 newInfo = CFDictionaryCreateMutable(NULL,
75 0,
76 &kCFTypeDictionaryKeyCallBacks,
77 &kCFTypeDictionaryValueCallBacks);
78 }
79
80 changes = CFDictionaryGetValue(newInfo, kSCDChangedKeys);
81 if (changes) {
82 newChanges = CFArrayCreateMutableCopy(NULL, 0, changes);
83 } else {
84 newChanges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
85 }
86
87 if (CFArrayContainsValue(newChanges,
88 CFRangeMake(0, CFArrayGetCount(newChanges)),
89 (CFStringRef)keys[keyCnt]) == FALSE) {
90 CFArrayAppendValue(newChanges, (CFStringRef)keys[keyCnt]);
91 }
92 CFDictionarySetValue(newInfo, kSCDChangedKeys, newChanges);
93 CFRelease(newChanges);
94 CFDictionarySetValue(sessionData, sessionKey, newInfo);
95 CFRelease(newInfo);
96 CFRelease(sessionKey);
97
98 /*
99 * flag this session as needing a kick
100 */
101 if (needsNotification == NULL)
102 needsNotification = CFSetCreateMutable(NULL,
103 0,
104 &kCFTypeSetCallBacks);
105 CFSetAddValue(needsNotification, watchers[watcherCnt]);
106 }
107 CFAllocatorDeallocate(NULL, watchers);
108 }
109 CFAllocatorDeallocate(NULL, keys);
110
111 /*
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.
115 */
116 CFSetRemoveAllValues(changedKeys);
117
118 }
119
120
121 static void
122 _processDeferredRemovals()
123 {
124 CFIndex keyCnt;
125 void **keys;
126
127 if ((keyCnt = CFSetGetCount(deferredRemovals)) == 0)
128 return; /* if nothing to do */
129
130 keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
131 CFSetGetValues(deferredRemovals, keys);
132 while (--keyCnt >= 0) {
133 CFDictionaryApplyFunction(sessionData,
134 (CFDictionaryApplierFunction)_removeRegexWatchersBySession,
135 keys[keyCnt]);
136 }
137 CFAllocatorDeallocate(NULL, keys);
138
139 /*
140 * All regex keys associated with removed cache dictionary keys have
141 * been removed. Start the list fresh again.
142 */
143 CFSetRemoveAllValues(deferredRemovals);
144
145 return;
146 }
147
148
149 static void
150 _cleanupRemovedSessionKeys(const void *value, void *context)
151 {
152 CFStringRef removedKey = (CFStringRef)value;
153 CFRange dRange;
154 CFStringRef sessionKey;
155 CFStringRef key;
156 CFDictionaryRef sessionDict;
157 CFArrayRef sessionKeys;
158 CFIndex i;
159 CFMutableDictionaryRef newSessionDict;
160
161 dRange = CFStringFind(removedKey, CFSTR(":"), 0);
162 sessionKey = CFStringCreateWithSubstring(NULL,
163 removedKey,
164 CFRangeMake(0, dRange.location));
165 key = CFStringCreateWithSubstring(NULL,
166 removedKey,
167 CFRangeMake(dRange.location+dRange.length,
168 CFStringGetLength(removedKey)-dRange.location-dRange.length));
169
170 /*
171 * remove the key from the session key list
172 */
173 sessionDict = CFDictionaryGetValue(sessionData, sessionKey);
174 if (!sessionDict) {
175 /* if no session */
176 goto done;
177 }
178
179 sessionKeys = CFDictionaryGetValue(sessionDict, kSCDSessionKeys);
180 if (!sessionKeys) {
181 /* if no session keys */
182 goto done;
183 }
184
185 i = CFArrayGetFirstIndexOfValue(sessionKeys,
186 CFRangeMake(0, CFArrayGetCount(sessionKeys)),
187 key);
188 if (i == -1) {
189 /* if this session key has already been removed */
190 goto done;
191 }
192
193 newSessionDict = CFDictionaryCreateMutableCopy(NULL, 0, sessionDict);
194 if (CFArrayGetCount(sessionKeys) == 1) {
195 /* remove the last (session) key */
196 CFDictionaryRemoveValue(newSessionDict, kSCDSessionKeys);
197 } else {
198 CFMutableArrayRef newSessionKeys;
199
200 /* remove the (session) key */
201 newSessionKeys = CFArrayCreateMutableCopy(NULL, 0, sessionKeys);
202 CFArrayRemoveValueAtIndex(newSessionKeys, i);
203 CFDictionarySetValue(newSessionDict, kSCDSessionKeys, newSessionKeys);
204 CFRelease(newSessionKeys);
205 }
206 CFDictionarySetValue(sessionData, sessionKey, newSessionDict);
207 CFRelease(newSessionDict);
208
209 done:
210
211 CFRelease(sessionKey);
212 CFRelease(key);
213
214 return;
215 }
216
217
218 SCDStatus
219 _SCDUnlock(SCDSessionRef session)
220 {
221 SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
222 serverSessionRef mySession;
223
224 SCDLog(LOG_DEBUG, CFSTR("_SCDUnlock:"));
225
226 if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
227 return SCD_NOSESSION;
228 }
229
230 if (!SCDOptionGet(NULL, kSCDOptionIsLocked) || !SCDOptionGet(session, kSCDOptionIsLocked)) {
231 return SCD_NEEDLOCK; /* sorry, you don't have the lock */
232 }
233
234 /*
235 * all of the changes can be committed to the (real) cache.
236 */
237 CFDictionaryRemoveAllValues(cacheData_s);
238 CFSetRemoveAllValues (changedKeys_s);
239 CFSetRemoveAllValues (deferredRemovals_s);
240 CFSetRemoveAllValues (removedSessionKeys_s);
241
242 #ifdef DEBUG
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);
247 #endif /* DEBUG */
248
249 /*
250 * push notifications to any session watching those keys which
251 * were recently changed.
252 */
253 _notifyWatchers();
254
255 /*
256 * process any deferred key deletions.
257 */
258 _processDeferredRemovals();
259
260 /*
261 * clean up any removed session keys
262 */
263 CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL);
264 CFSetRemoveAllValues(removedSessionKeys);
265
266 #ifdef DEBUG
267 SCDLog(LOG_DEBUG, CFSTR("sessions to notify = %@"), needsNotification);
268 #endif /* DEBUG */
269
270 /* Remove the "locked" run loop source for this port */
271 mySession = getSession(sessionPrivate->server);
272 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked"));
273
274 SCDOptionSet(NULL, kSCDOptionIsLocked, FALSE); /* global lock flag */
275 SCDOptionSet(session, kSCDOptionIsLocked, FALSE); /* per-session lock flag */
276
277 return SCD_OK;
278 }
279
280
281 kern_return_t
282 _configunlock(mach_port_t server, int *scd_status)
283 {
284 serverSessionRef mySession = getSession(server);
285
286 SCDLog(LOG_DEBUG, CFSTR("Unlock configuration database."));
287 SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
288
289 *scd_status = _SCDUnlock(mySession->session);
290 if (*scd_status != SCD_OK) {
291 SCDLog(LOG_DEBUG, CFSTR(" _SCDUnlock(): %s"), SCDError(*scd_status));
292 return KERN_SUCCESS;
293 }
294
295 return KERN_SUCCESS;
296 }