]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configunlock.c
configd-1061.101.1.tar.gz
[apple/configd.git] / configd.tproj / _configunlock.c
1 /*
2 * Copyright (c) 2000-2004, 2006, 2011, 2015, 2017, 2019 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34
35 #include "configd.h"
36 #include "configd_server.h"
37 #include "session.h"
38 #include "pattern.h"
39
40
41 #define N_QUICK 32
42
43
44 static void
45 _notifyWatchers()
46 {
47 CFIndex keyCnt;
48 const void * keys_q[N_QUICK];
49 const void ** keys = keys_q;
50
51 keyCnt = CFSetGetCount(changedKeys);
52 if (keyCnt == 0)
53 return; /* if nothing to do */
54
55 if (keyCnt > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef)))
56 keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
57
58 CFSetGetValues(changedKeys, keys);
59
60 while (--keyCnt >= 0) {
61 CFStringRef changedKey = (CFStringRef)keys[keyCnt];
62 CFDictionaryRef dict;
63 CFArrayRef sessionsWatchingKey;
64 CFIndex watcherCnt;
65 const void * watchers_q[N_QUICK];
66 const void ** watchers = watchers_q;
67
68 dict = CFDictionaryGetValue(storeData, changedKey);
69 if ((dict == NULL) || !CFDictionaryContainsKey(dict, kSCDWatchers)) {
70 /* key doesn't exist or nobody cares if it changed */
71 continue;
72 }
73
74 /*
75 * Add this key to the list of changes for each of the
76 * sessions which is "watching".
77 */
78 sessionsWatchingKey = CFDictionaryGetValue(dict, kSCDWatchers);
79 watcherCnt = CFArrayGetCount(sessionsWatchingKey);
80 if (watcherCnt == 0) {
81 /* if no watchers */
82 continue;
83 }
84
85 if (watcherCnt > (CFIndex)(sizeof(watchers_q) / sizeof(CFNumberRef)))
86 watchers = CFAllocatorAllocate(NULL, watcherCnt * sizeof(CFNumberRef), 0);
87
88 CFArrayGetValues(sessionsWatchingKey, CFRangeMake(0, watcherCnt), watchers);
89
90 while (--watcherCnt >= 0) {
91 serverSessionRef session;
92 CFNumberRef watchedSession = watchers[watcherCnt];
93
94 session = getSessionNum(watchedSession);
95 if (session->changedKeys == NULL) {
96 session->changedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
97 }
98 if (!CFArrayContainsValue(session->changedKeys,
99 CFRangeMake(0, CFArrayGetCount(session->changedKeys)),
100 changedKey)) {
101 CFArrayAppendValue(session->changedKeys, changedKey);
102 }
103
104 /*
105 * flag this session as needing a kick
106 */
107 if (needsNotification == NULL)
108 needsNotification = CFSetCreateMutable(NULL,
109 0,
110 &kCFTypeSetCallBacks);
111 CFSetAddValue(needsNotification, watchedSession);
112 }
113
114 if (watchers != watchers_q) CFAllocatorDeallocate(NULL, watchers);
115 }
116
117 if (keys != keys_q) CFAllocatorDeallocate(NULL, keys);
118
119 /*
120 * The list of changed keys have been updated for any sessions
121 * monitoring changes to the "store". The next step, handled by
122 * the "configd" server, is to push out any needed notifications.
123 */
124 CFSetRemoveAllValues(changedKeys);
125
126 }
127
128
129 static void
130 _processDeferredRemovals()
131 {
132 CFIndex keyCnt;
133 const void * keys_q[N_QUICK];
134 const void ** keys = keys_q;
135
136 keyCnt = CFSetGetCount(deferredRemovals);
137 if (keyCnt == 0)
138 return; /* if nothing to do */
139
140 if (keyCnt > (CFIndex)(sizeof(keys_q) / sizeof(CFStringRef)))
141 keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
142
143 CFSetGetValues(deferredRemovals, keys);
144
145 while (--keyCnt >= 0) {
146 patternRemoveKey((CFStringRef)keys[keyCnt]);
147 }
148
149 if (keys != keys_q) CFAllocatorDeallocate(NULL, keys);
150
151 /*
152 * All regex keys associated with removed store dictionary keys have
153 * been removed. Start the list fresh again.
154 */
155 CFSetRemoveAllValues(deferredRemovals);
156
157 return;
158 }
159
160
161 static void
162 _cleanupRemovedSessionKeys(const void *value, void *context)
163 {
164 #pragma unused(context)
165 CFStringRef removedKey = (CFStringRef)value;
166 CFRange dRange;
167 serverSessionRef session;
168 CFStringRef sessionKey;
169 CFStringRef key;
170 CFIndex i;
171
172 dRange = CFStringFind(removedKey, CFSTR(":"), 0);
173 sessionKey = CFStringCreateWithSubstring(NULL,
174 removedKey,
175 CFRangeMake(0, dRange.location));
176 key = CFStringCreateWithSubstring(NULL,
177 removedKey,
178 CFRangeMake(dRange.location+dRange.length,
179 CFStringGetLength(removedKey)-dRange.location-dRange.length));
180
181 session = getSessionStr(sessionKey);
182 if (session == NULL) {
183 /* if no session */
184 goto done;
185 }
186
187 i = CFArrayGetFirstIndexOfValue(session->sessionKeys,
188 CFRangeMake(0, CFArrayGetCount(session->sessionKeys)),
189 key);
190 if (i == kCFNotFound) {
191 /* if this session key has already been removed */
192 goto done;
193 }
194 CFArrayRemoveValueAtIndex(session->sessionKeys, i);
195 if (CFArrayGetCount(session->sessionKeys) == 0) {
196 CFRelease(session->sessionKeys);
197 session->sessionKeys = NULL;
198 }
199
200 done:
201
202 CFRelease(sessionKey);
203 CFRelease(key);
204
205 return;
206 }
207
208
209 __private_extern__
210 int
211 __SCDynamicStorePush(void)
212 {
213 /*
214 * push notifications to any session watching those keys which
215 * were recently changed.
216 */
217 _notifyWatchers();
218
219 /*
220 * process any deferred key deletions.
221 */
222 _processDeferredRemovals();
223
224 /*
225 * clean up any removed session keys
226 */
227 CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL);
228 CFSetRemoveAllValues(removedSessionKeys);
229
230 return kSCStatusOK;
231 }