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