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