]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configunlock.c
configd-53.tar.gz
[apple/configd.git] / configd.tproj / _configunlock.c
1 /*
2 * Copyright (c) 2000-2002 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 * Modification History
25 *
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
28 *
29 * March 24, 2000 Allan Nathanson <ajn@apple.com>
30 * - initial revision
31 */
32
33
34 #include "configd.h"
35 #include "configd_server.h"
36 #include "session.h"
37
38
39 static void
40 _notifyWatchers()
41 {
42 CFIndex keyCnt;
43 const void **keys;
44
45 keyCnt = CFSetGetCount(changedKeys);
46 if (keyCnt == 0)
47 return; /* if nothing to do */
48
49 keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
50 CFSetGetValues(changedKeys, keys);
51 while (--keyCnt >= 0) {
52 CFDictionaryRef dict;
53 CFArrayRef sessionsWatchingKey;
54 CFIndex watcherCnt;
55 const void **watchers;
56 CFDictionaryRef info;
57 CFMutableDictionaryRef newInfo;
58 CFArrayRef changes;
59 CFMutableArrayRef newChanges;
60
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 */
64 continue;
65 }
66
67 /*
68 * Add this key to the list of changes for each of the
69 * sessions which is "watching".
70 */
71 sessionsWatchingKey = CFDictionaryGetValue(dict, kSCDWatchers);
72 watcherCnt = CFArrayGetCount(sessionsWatchingKey);
73 if (watcherCnt > 0) {
74 watchers = CFAllocatorAllocate(NULL, watcherCnt * sizeof(CFNumberRef), 0);
75 CFArrayGetValues(sessionsWatchingKey,
76 CFRangeMake(0, CFArrayGetCount(sessionsWatchingKey)),
77 watchers);
78 while (--watcherCnt >= 0) {
79 CFStringRef sessionKey;
80
81 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), watchers[watcherCnt]);
82 info = CFDictionaryGetValue(sessionData, sessionKey);
83 if (info) {
84 newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
85 } else {
86 newInfo = CFDictionaryCreateMutable(NULL,
87 0,
88 &kCFTypeDictionaryKeyCallBacks,
89 &kCFTypeDictionaryValueCallBacks);
90 }
91
92 changes = CFDictionaryGetValue(newInfo, kSCDChangedKeys);
93 if (changes) {
94 newChanges = CFArrayCreateMutableCopy(NULL, 0, changes);
95 } else {
96 newChanges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
97 }
98
99 if (CFArrayContainsValue(newChanges,
100 CFRangeMake(0, CFArrayGetCount(newChanges)),
101 (CFStringRef)keys[keyCnt]) == FALSE) {
102 CFArrayAppendValue(newChanges, (CFStringRef)keys[keyCnt]);
103 }
104 CFDictionarySetValue(newInfo, kSCDChangedKeys, newChanges);
105 CFRelease(newChanges);
106 CFDictionarySetValue(sessionData, sessionKey, newInfo);
107 CFRelease(newInfo);
108 CFRelease(sessionKey);
109
110 /*
111 * flag this session as needing a kick
112 */
113 if (needsNotification == NULL)
114 needsNotification = CFSetCreateMutable(NULL,
115 0,
116 &kCFTypeSetCallBacks);
117 CFSetAddValue(needsNotification, watchers[watcherCnt]);
118 }
119 CFAllocatorDeallocate(NULL, watchers);
120 }
121 }
122 CFAllocatorDeallocate(NULL, keys);
123
124 /*
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.
128 */
129 CFSetRemoveAllValues(changedKeys);
130
131 }
132
133
134 static void
135 _processDeferredRemovals()
136 {
137 CFIndex keyCnt;
138 const void **keys;
139
140 keyCnt = CFSetGetCount(deferredRemovals);
141 if (keyCnt == 0)
142 return; /* if nothing to do */
143
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]);
150 }
151 CFAllocatorDeallocate(NULL, keys);
152
153 /*
154 * All regex keys associated with removed store dictionary keys have
155 * been removed. Start the list fresh again.
156 */
157 CFSetRemoveAllValues(deferredRemovals);
158
159 return;
160 }
161
162
163 static void
164 _cleanupRemovedSessionKeys(const void *value, void *context)
165 {
166 CFStringRef removedKey = (CFStringRef)value;
167 CFRange dRange;
168 CFStringRef sessionKey;
169 CFStringRef key;
170 CFDictionaryRef sessionDict;
171 CFArrayRef sessionKeys;
172 CFIndex i;
173 CFMutableDictionaryRef newSessionDict;
174
175 dRange = CFStringFind(removedKey, CFSTR(":"), 0);
176 sessionKey = CFStringCreateWithSubstring(NULL,
177 removedKey,
178 CFRangeMake(0, dRange.location));
179 key = CFStringCreateWithSubstring(NULL,
180 removedKey,
181 CFRangeMake(dRange.location+dRange.length,
182 CFStringGetLength(removedKey)-dRange.location-dRange.length));
183
184 /*
185 * remove the key from the session key list
186 */
187 sessionDict = CFDictionaryGetValue(sessionData, sessionKey);
188 if (!sessionDict) {
189 /* if no session */
190 goto done;
191 }
192
193 sessionKeys = CFDictionaryGetValue(sessionDict, kSCDSessionKeys);
194 if (!sessionKeys) {
195 /* if no session keys */
196 goto done;
197 }
198
199 i = CFArrayGetFirstIndexOfValue(sessionKeys,
200 CFRangeMake(0, CFArrayGetCount(sessionKeys)),
201 key);
202 if (i == -1) {
203 /* if this session key has already been removed */
204 goto done;
205 }
206
207 newSessionDict = CFDictionaryCreateMutableCopy(NULL, 0, sessionDict);
208 if (CFArrayGetCount(sessionKeys) == 1) {
209 /* remove the last (session) key */
210 CFDictionaryRemoveValue(newSessionDict, kSCDSessionKeys);
211 } else {
212 CFMutableArrayRef newSessionKeys;
213
214 /* remove the (session) key */
215 newSessionKeys = CFArrayCreateMutableCopy(NULL, 0, sessionKeys);
216 CFArrayRemoveValueAtIndex(newSessionKeys, i);
217 CFDictionarySetValue(newSessionDict, kSCDSessionKeys, newSessionKeys);
218 CFRelease(newSessionKeys);
219 }
220 CFDictionarySetValue(sessionData, sessionKey, newSessionDict);
221 CFRelease(newSessionDict);
222
223 done:
224
225 CFRelease(sessionKey);
226 CFRelease(key);
227
228 return;
229 }
230
231
232 int
233 __SCDynamicStoreUnlock(SCDynamicStoreRef store, Boolean recursive)
234 {
235 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
236 serverSessionRef mySession;
237
238 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("__SCDynamicStoreUnlock:"));
239
240 if (!store || (storePrivate->server == MACH_PORT_NULL)) {
241 return kSCStatusNoStoreSession; /* you must have an open session to play */
242 }
243
244 if ((storeLocked == 0) || !storePrivate->locked) {
245 return kSCStatusNeedLock; /* sorry, you don't have the lock */
246 }
247
248 if ((storeLocked > 1) && recursive) {
249 /* if the lock is being held for a recursive (internal) request */
250 storeLocked--;
251 return kSCStatusOK;
252 }
253
254 /*
255 * all of the changes can be committed to the (real) store.
256 */
257 CFDictionaryRemoveAllValues(storeData_s);
258 CFSetRemoveAllValues (changedKeys_s);
259 CFSetRemoveAllValues (deferredRemovals_s);
260 CFSetRemoveAllValues (removedSessionKeys_s);
261
262 #ifdef DEBUG
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);
267 #endif /* DEBUG */
268
269 /*
270 * push notifications to any session watching those keys which
271 * were recently changed.
272 */
273 _notifyWatchers();
274
275 /*
276 * process any deferred key deletions.
277 */
278 _processDeferredRemovals();
279
280 /*
281 * clean up any removed session keys
282 */
283 CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL);
284 CFSetRemoveAllValues(removedSessionKeys);
285
286 #ifdef DEBUG
287 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("sessions to notify = %@"), needsNotification);
288 #endif /* DEBUG */
289
290 /* Remove the "locked" run loop source for this port */
291 mySession = getSession(storePrivate->server);
292 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked"));
293
294 storeLocked = 0; /* global lock flag */
295 storePrivate->locked = FALSE; /* per-session lock flag */
296
297 return kSCStatusOK;
298 }
299
300
301 kern_return_t
302 _configunlock(mach_port_t server, int *sc_status)
303 {
304 serverSessionRef mySession = getSession(server);
305
306 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Unlock configuration database."));
307 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" server = %d"), server);
308
309 *sc_status = __SCDynamicStoreUnlock(mySession->store, FALSE);
310 if (*sc_status != kSCStatusOK) {
311 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" __SCDynamicStoreUnlock(): %s"), SCErrorString(*sc_status));
312 return KERN_SUCCESS;
313 }
314
315 return KERN_SUCCESS;
316 }