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