]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_notifyadd.c
configd-453.16.tar.gz
[apple/configd.git] / configd.tproj / _notifyadd.c
1 /*
2 * Copyright (c) 2000-2004, 2006, 2008, 2010, 2011 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 #include "configd.h"
35 #include "session.h"
36 #include "pattern.h"
37
38
39 static __inline__ void
40 my_CFArrayApplyFunction(CFArrayRef theArray,
41 CFArrayApplierFunction applier,
42 void *context)
43 {
44 CFAllocatorRef myAllocator;
45 CFArrayRef myArray;
46
47 myAllocator = CFGetAllocator(theArray);
48 myArray = CFArrayCreateCopy(myAllocator, theArray);
49 CFArrayApplyFunction(myArray, CFRangeMake(0, CFArrayGetCount(myArray)), applier, context);
50 CFRelease(myArray);
51 return;
52 }
53
54
55 static int
56 hasKey(CFMutableArrayRef keys, CFStringRef key)
57 {
58 if (keys != NULL) {
59 CFIndex n;
60
61 n = CFArrayGetCount(keys);
62 if (CFArrayContainsValue(keys, CFRangeMake(0, n), key)) {
63 /* sorry, pattern already exists in notifier list */
64 return kSCStatusKeyExists;
65 }
66 }
67
68 return kSCStatusOK;
69 }
70
71
72 static void
73 addKey(CFMutableArrayRef *keysP, CFStringRef key)
74 {
75 if (*keysP == NULL) {
76 *keysP = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
77 }
78
79 CFArrayAppendValue(*keysP, key);
80 return;
81 }
82
83
84 __private_extern__
85 int
86 __SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean isRegex, Boolean internal)
87 {
88 int sc_status = kSCStatusOK;
89 CFNumberRef sessionNum = NULL;
90 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
91
92 if (_configd_trace) {
93 SCTrace(TRUE, _configd_trace,
94 CFSTR("%s : %5d : %s : %@\n"),
95 internal ? "*watch+" : "watch+ ",
96 storePrivate->server,
97 isRegex ? "pattern" : "key",
98 key);
99 }
100
101 sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &storePrivate->server);
102
103 if (isRegex) {
104 sc_status = hasKey(storePrivate->patterns, key);
105 if (sc_status != kSCStatusOK) {
106 goto done;
107 }
108
109 /*
110 * add this session as a pattern watcher
111 */
112 if (!patternAddSession(key, sessionNum)) {
113 sc_status = kSCStatusInvalidArgument;
114 goto done;
115 }
116
117 /* add pattern to this sessions notifier list */
118 addKey(&storePrivate->patterns, key);
119 } else {
120 sc_status = hasKey(storePrivate->keys, key);
121 if (sc_status != kSCStatusOK) {
122 goto done;
123 }
124
125 /*
126 * We are watching a specific key. As such, update the
127 * store to mark our interest in any changes.
128 */
129 _addWatcher(sessionNum, key);
130
131 /* add key to this sessions notifier list */
132 addKey(&storePrivate->keys, key);
133 }
134
135 done :
136
137 if (sessionNum != NULL) CFRelease(sessionNum);
138 return sc_status;
139 }
140
141
142 __private_extern__
143 kern_return_t
144 _notifyadd(mach_port_t server,
145 xmlData_t keyRef, /* raw XML bytes */
146 mach_msg_type_number_t keyLen,
147 int isRegex,
148 int *sc_status
149 )
150 {
151 CFStringRef key = NULL; /* key (un-serialized) */
152 serverSessionRef mySession;
153
154 /* un-serialize the key */
155 if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) {
156 *sc_status = kSCStatusFailed;
157 goto done;
158 }
159
160 if (!isA_CFString(key)) {
161 *sc_status = kSCStatusInvalidArgument;
162 goto done;
163 }
164
165 mySession = getSession(server);
166 if (mySession == NULL) {
167 *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */
168 goto done;
169 }
170
171 *sc_status = __SCDynamicStoreAddWatchedKey(mySession->store, key, isRegex != 0, FALSE);
172
173 done :
174
175 if (key) CFRelease(key);
176 return KERN_SUCCESS;
177 }
178
179
180 /*
181 * "context" argument for removeOldKey() and addNewKey()
182 */
183 typedef struct {
184 SCDynamicStoreRef store;
185 CFArrayRef oldKeys; /* for addNewKey */
186 CFArrayRef newKeys; /* for removeOldKey */
187 Boolean isRegex;
188 int sc_status;
189 } updateKeysContext, *updateKeysContextRef;
190
191
192 static void
193 removeOldKey(const void *value, void *context)
194 {
195 CFStringRef oldKey = (CFStringRef)value;
196 updateKeysContextRef myContextRef = (updateKeysContextRef)context;
197
198 if (myContextRef->sc_status != kSCStatusOK) {
199 return;
200 }
201
202 if ((myContextRef->newKeys == NULL) ||
203 !CFArrayContainsValue(myContextRef->newKeys,
204 CFRangeMake(0, CFArrayGetCount(myContextRef->newKeys)),
205 oldKey)) {
206 /* the old notification key is not being retained, remove it */
207 myContextRef->sc_status = __SCDynamicStoreRemoveWatchedKey(myContextRef->store,
208 oldKey,
209 myContextRef->isRegex,
210 TRUE);
211 }
212
213 return;
214 }
215
216
217 static void
218 addNewKey(const void *value, void *context)
219 {
220 CFStringRef newKey = (CFStringRef)value;
221 updateKeysContextRef myContextRef = (updateKeysContextRef)context;
222
223 if (myContextRef->sc_status != kSCStatusOK) {
224 return;
225 }
226
227 if ((myContextRef->oldKeys == NULL) ||
228 !CFArrayContainsValue(myContextRef->oldKeys,
229 CFRangeMake(0, CFArrayGetCount(myContextRef->oldKeys)),
230 newKey)) {
231 /* if this is a new notification key */
232 myContextRef->sc_status = __SCDynamicStoreAddWatchedKey(myContextRef->store,
233 newKey,
234 myContextRef->isRegex,
235 TRUE);
236 }
237
238 return;
239 }
240
241
242 __private_extern__
243 int
244 __SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store, CFArrayRef keys, CFArrayRef patterns)
245 {
246 updateKeysContext myContext;
247 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
248
249 if (_configd_trace) {
250 SCTrace(TRUE, _configd_trace,
251 CFSTR("watch : %5d : %d keys, %d patterns\n"),
252 storePrivate->server,
253 keys ? CFArrayGetCount(keys) : 0,
254 patterns ? CFArrayGetCount(patterns) : 0);
255 }
256
257 myContext.store = store;
258 myContext.sc_status = kSCStatusOK;
259
260 /* remove any previously registered keys, register any new keys */
261 myContext.oldKeys = NULL;
262 myContext.newKeys = keys;
263 myContext.isRegex = FALSE;
264 if (storePrivate->keys != NULL) {
265 myContext.oldKeys = CFArrayCreateCopy(NULL, storePrivate->keys);
266 my_CFArrayApplyFunction(storePrivate->keys, removeOldKey, &myContext);
267 }
268 if (keys != NULL) {
269 CFArrayApplyFunction(keys,
270 CFRangeMake(0, CFArrayGetCount(keys)),
271 addNewKey,
272 &myContext);
273 }
274 if (myContext.oldKeys != NULL) CFRelease(myContext.oldKeys);
275
276 /* remove any previously registered patterns, register any new patterns */
277 myContext.oldKeys = NULL;
278 myContext.newKeys = patterns;
279 myContext.isRegex = TRUE;
280 if (storePrivate->patterns != NULL) {
281 myContext.oldKeys = CFArrayCreateCopy(NULL, storePrivate->patterns);
282 my_CFArrayApplyFunction(storePrivate->patterns, removeOldKey, &myContext);
283 }
284 if (patterns != NULL) {
285 CFArrayApplyFunction(patterns,
286 CFRangeMake(0, CFArrayGetCount(patterns)),
287 addNewKey,
288 &myContext);
289 }
290 if (myContext.oldKeys != NULL) CFRelease(myContext.oldKeys);
291
292 return myContext.sc_status;
293 }
294
295
296 __private_extern__
297 kern_return_t
298 _notifyset(mach_port_t server,
299 xmlData_t keysRef, /* raw XML bytes */
300 mach_msg_type_number_t keysLen,
301 xmlData_t patternsRef, /* raw XML bytes */
302 mach_msg_type_number_t patternsLen,
303 int *sc_status
304 )
305 {
306 CFArrayRef keys = NULL; /* key (un-serialized) */
307 serverSessionRef mySession;
308 CFArrayRef patterns = NULL; /* patterns (un-serialized) */
309
310 *sc_status = kSCStatusOK;
311
312 if ((keysRef != NULL) && (keysLen > 0)) {
313 /* un-serialize the keys */
314 if (!_SCUnserialize((CFPropertyListRef *)&keys, NULL, (void *)keysRef, keysLen)) {
315 *sc_status = kSCStatusFailed;
316 }
317 }
318
319 if ((patternsRef != NULL) && (patternsLen > 0)) {
320 /* un-serialize the patterns */
321 if (!_SCUnserialize((CFPropertyListRef *)&patterns, NULL, (void *)patternsRef, patternsLen)) {
322 *sc_status = kSCStatusFailed;
323 }
324 }
325
326 if (*sc_status != kSCStatusOK) {
327 goto done;
328 }
329
330 if ((keys != NULL) && !isA_CFArray(keys)) {
331 *sc_status = kSCStatusInvalidArgument;
332 goto done;
333 }
334
335 if ((patterns != NULL) && !isA_CFArray(patterns)) {
336 *sc_status = kSCStatusInvalidArgument;
337 goto done;
338 }
339
340 mySession = getSession(server);
341 if (mySession == NULL) {
342 /* you must have an open session to play */
343 *sc_status = kSCStatusNoStoreSession;
344 goto done;
345 }
346
347 *sc_status = __SCDynamicStoreSetNotificationKeys(mySession->store, keys, patterns);
348
349 done :
350
351 if (keys != NULL) CFRelease(keys);
352 if (patterns != NULL) CFRelease(patterns);
353
354 return KERN_SUCCESS;
355 }