]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configset.c
configd-395.7.tar.gz
[apple/configd.git] / configd.tproj / _configset.c
1 /*
2 * Copyright (c) 2000-2004, 2006, 2008 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 "session.h"
37 #include "pattern.h"
38
39
40 __private_extern__
41 int
42 __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal)
43 {
44 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
45 int sc_status = kSCStatusOK;
46 CFDictionaryRef dict;
47 CFMutableDictionaryRef newDict;
48 Boolean newEntry = FALSE;
49 CFStringRef sessionKey;
50 CFStringRef storeSessionKey;
51
52 if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
53 return kSCStatusNoStoreSession; /* you must have an open session to play */
54 }
55
56 if (_configd_trace) {
57 SCTrace(TRUE, _configd_trace,
58 CFSTR("%s%s : %5d : %@\n"),
59 internal ? "*set " : "set ",
60 storePrivate->useSessionKeys ? "t " : " ",
61 storePrivate->server,
62 key);
63 }
64
65 /*
66 * 1. Ensure that we hold the lock.
67 */
68 sc_status = __SCDynamicStoreLock(store, TRUE);
69 if (sc_status != kSCStatusOK) {
70 return sc_status;
71 }
72
73 /*
74 * 2. Grab the current (or establish a new) dictionary for this key.
75 */
76
77 dict = CFDictionaryGetValue(storeData, key);
78 if (dict) {
79 newDict = CFDictionaryCreateMutableCopy(NULL,
80 0,
81 dict);
82 } else {
83 newDict = CFDictionaryCreateMutable(NULL,
84 0,
85 &kCFTypeDictionaryKeyCallBacks,
86 &kCFTypeDictionaryValueCallBacks);
87 }
88
89 /*
90 * 3. Update the dictionary entry to be saved to the store.
91 */
92 newEntry = !CFDictionaryContainsKey(newDict, kSCDData);
93 CFDictionarySetValue(newDict, kSCDData, value);
94
95 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
96
97 /*
98 * 4. Manage per-session keys.
99 */
100 if (storePrivate->useSessionKeys) {
101 if (newEntry) {
102 CFArrayRef keys;
103 CFMutableDictionaryRef newSession;
104 CFMutableArrayRef newKeys;
105 CFDictionaryRef session;
106
107 /*
108 * Add this key to my list of per-session keys
109 */
110 session = CFDictionaryGetValue(sessionData, sessionKey);
111 keys = CFDictionaryGetValue(session, kSCDSessionKeys);
112 if ((keys == NULL) ||
113 (CFArrayGetFirstIndexOfValue(keys,
114 CFRangeMake(0, CFArrayGetCount(keys)),
115 key) == kCFNotFound)) {
116 /*
117 * if no session keys defined "or" keys defined but not
118 * this one...
119 */
120 if (keys != NULL) {
121 /* this is the first session key */
122 newKeys = CFArrayCreateMutableCopy(NULL, 0, keys);
123 } else {
124 /* this is an additional session key */
125 newKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
126 }
127 CFArrayAppendValue(newKeys, key);
128
129 /* update session dictionary */
130 newSession = CFDictionaryCreateMutableCopy(NULL, 0, session);
131 CFDictionarySetValue(newSession, kSCDSessionKeys, newKeys);
132 CFRelease(newKeys);
133 CFDictionarySetValue(sessionData, sessionKey, newSession);
134 CFRelease(newSession);
135 }
136
137 /*
138 * Mark the key as a "session" key and track the creator.
139 */
140 CFDictionarySetValue(newDict, kSCDSession, sessionKey);
141 } else {
142 /*
143 * Since we are using per-session keys and this key already
144 * exists, check if it was created by "our" session
145 */
146 dict = CFDictionaryGetValue(storeData, key);
147 if (!CFDictionaryGetValueIfPresent(dict, kSCDSession, (void *)&storeSessionKey) ||
148 !CFEqual(sessionKey, storeSessionKey)) {
149 /*
150 * if the key exists and is not a session key or
151 * if the key exists it's not "our" session.
152 */
153 sc_status = kSCStatusKeyExists;
154 CFRelease(sessionKey);
155 CFRelease(newDict);
156 goto done;
157 }
158 }
159 } else {
160 /*
161 * Since we are updating this key we need to check and, if
162 * necessary, remove the indication that this key is on
163 * another session's remove-on-close list.
164 */
165 if (!newEntry &&
166 CFDictionaryGetValueIfPresent(newDict, kSCDSession, (void *)&storeSessionKey) &&
167 !CFEqual(sessionKey, storeSessionKey)) {
168 CFStringRef removedKey;
169
170 /* We are no longer a session key! */
171 CFDictionaryRemoveValue(newDict, kSCDSession);
172
173 /* add this session key to the (session) removal list */
174 removedKey = CFStringCreateWithFormat(NULL, 0, CFSTR("%@:%@"), storeSessionKey, key);
175 CFSetAddValue(removedSessionKeys, removedKey);
176 CFRelease(removedKey);
177 }
178 }
179
180 CFRelease(sessionKey);
181
182 /*
183 * 5. Update the dictionary entry in the store.
184 */
185
186 CFDictionarySetValue(storeData, key, newDict);
187 CFRelease(newDict);
188
189 /*
190 * 6. For "new" entries to the store, check the deferred cleanup
191 * list. If the key is flagged for removal, remove it from the
192 * list since any defined regex's for this key are still defined
193 * and valid. If the key is not flagged then iterate over the
194 * sessionData dictionary looking for regex keys which match the
195 * updated key. If a match is found then we mark those keys as
196 * being watched.
197 */
198
199 if (newEntry) {
200 if (CFSetContainsValue(deferredRemovals, key)) {
201 CFSetRemoveValue(deferredRemovals, key);
202 } else {
203 patternAddKey(key);
204 }
205 }
206
207 /*
208 * 7. Mark this key as "changed". Any "watchers" will be notified
209 * as soon as the lock is released.
210 */
211 CFSetAddValue(changedKeys, key);
212
213 done :
214
215 /*
216 * 8. Release our lock.
217 */
218 __SCDynamicStoreUnlock(store, TRUE);
219
220 return sc_status;
221 }
222
223 __private_extern__
224 kern_return_t
225 _configset(mach_port_t server,
226 xmlData_t keyRef, /* raw XML bytes */
227 mach_msg_type_number_t keyLen,
228 xmlData_t dataRef, /* raw XML bytes */
229 mach_msg_type_number_t dataLen,
230 int oldInstance,
231 int *newInstance,
232 int *sc_status
233 )
234 {
235 CFDataRef data = NULL; /* data (un-serialized) */
236 CFStringRef key = NULL; /* key (un-serialized) */
237 serverSessionRef mySession;
238
239 *sc_status = kSCStatusOK;
240
241 /* un-serialize the key */
242 if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) {
243 *sc_status = kSCStatusFailed;
244 }
245
246 /* un-serialize the data */
247 if (!_SCUnserializeData(&data, (void *)dataRef, dataLen)) {
248 *sc_status = kSCStatusFailed;
249 }
250
251 if (*sc_status != kSCStatusOK) {
252 goto done;
253 }
254
255 if (!isA_CFString(key)) {
256 *sc_status = kSCStatusInvalidArgument;
257 goto done;
258 }
259
260 mySession = getSession(server);
261 if (mySession == NULL) {
262 *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */
263 goto done;
264 }
265
266 *sc_status = __SCDynamicStoreSetValue(mySession->store, key, data, FALSE);
267 *newInstance = 0;
268
269 done :
270
271 if (key) CFRelease(key);
272 if (data) CFRelease(data);
273 return KERN_SUCCESS;
274 }
275
276 static void
277 setSpecificKey(const void *key, const void *value, void *context)
278 {
279 CFStringRef k = (CFStringRef)key;
280 CFDataRef v = (CFDataRef)value;
281 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
282
283 if (!isA_CFString(k)) {
284 return;
285 }
286
287 if (!isA_CFData(v)) {
288 return;
289 }
290
291 (void) __SCDynamicStoreSetValue(store, k, v, TRUE);
292
293 return;
294 }
295
296 static void
297 removeSpecificKey(const void *value, void *context)
298 {
299 CFStringRef k = (CFStringRef)value;
300 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
301
302 if (!isA_CFString(k)) {
303 return;
304 }
305
306 (void) __SCDynamicStoreRemoveValue(store, k, TRUE);
307
308 return;
309 }
310
311 static void
312 notifySpecificKey(const void *value, void *context)
313 {
314 CFStringRef k = (CFStringRef)value;
315 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
316
317 if (!isA_CFString(k)) {
318 return;
319 }
320
321 (void) __SCDynamicStoreNotifyValue(store, k, TRUE);
322
323 return;
324 }
325
326 __private_extern__
327 int
328 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify)
329 {
330 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
331 int sc_status = kSCStatusOK;
332
333 if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) {
334 return kSCStatusNoStoreSession; /* you must have an open session to play */
335 }
336
337 if (_configd_trace) {
338 SCTrace(TRUE, _configd_trace,
339 CFSTR("set m : %5d : %d set, %d remove, %d notify\n"),
340 storePrivate->server,
341 keysToSet ? CFDictionaryGetCount(keysToSet) : 0,
342 keysToRemove ? CFArrayGetCount (keysToRemove) : 0,
343 keysToNotify ? CFArrayGetCount (keysToNotify) : 0);
344 }
345
346 /*
347 * Ensure that we hold the lock
348 */
349 sc_status = __SCDynamicStoreLock(store, TRUE);
350 if (sc_status != kSCStatusOK) {
351 return sc_status;
352 }
353
354 /*
355 * Set the new/updated keys
356 */
357 if (keysToSet) {
358 CFDictionaryApplyFunction(keysToSet,
359 setSpecificKey,
360 (void *)store);
361 }
362
363 /*
364 * Remove the specified keys
365 */
366 if (keysToRemove) {
367 CFArrayApplyFunction(keysToRemove,
368 CFRangeMake(0, CFArrayGetCount(keysToRemove)),
369 removeSpecificKey,
370 (void *)store);
371 }
372
373 /*
374 * Notify the specified keys
375 */
376 if (keysToNotify) {
377 CFArrayApplyFunction(keysToNotify,
378 CFRangeMake(0, CFArrayGetCount(keysToNotify)),
379 notifySpecificKey,
380 (void *)store);
381 }
382
383 /* Release our lock */
384 __SCDynamicStoreUnlock(store, TRUE);
385
386 return sc_status;
387 }
388
389 __private_extern__
390 kern_return_t
391 _configset_m(mach_port_t server,
392 xmlData_t dictRef,
393 mach_msg_type_number_t dictLen,
394 xmlData_t removeRef,
395 mach_msg_type_number_t removeLen,
396 xmlData_t notifyRef,
397 mach_msg_type_number_t notifyLen,
398 int *sc_status)
399 {
400 CFDictionaryRef dict = NULL; /* key/value dictionary (un-serialized) */
401 serverSessionRef mySession;
402 CFArrayRef notify = NULL; /* keys to notify (un-serialized) */
403 CFArrayRef remove = NULL; /* keys to remove (un-serialized) */
404
405 *sc_status = kSCStatusOK;
406
407 if ((dictRef != NULL) && (dictLen > 0)) {
408 /* un-serialize the key/value pairs to set */
409 if (!_SCUnserialize((CFPropertyListRef *)&dict, NULL, (void *)dictRef, dictLen)) {
410 *sc_status = kSCStatusFailed;
411 }
412 }
413
414 if ((removeRef != NULL) && (removeLen > 0)) {
415 /* un-serialize the keys to remove */
416 if (!_SCUnserialize((CFPropertyListRef *)&remove, NULL, (void *)removeRef, removeLen)) {
417 *sc_status = kSCStatusFailed;
418 }
419 }
420
421 if ((notifyRef != NULL) && (notifyLen > 0)) {
422 /* un-serialize the keys to notify */
423 if (!_SCUnserialize((CFPropertyListRef *)&notify, NULL, (void *)notifyRef, notifyLen)) {
424 *sc_status = kSCStatusFailed;
425 }
426 }
427
428 if (*sc_status != kSCStatusOK) {
429 goto done;
430 }
431
432 if ((dict != NULL) && !isA_CFDictionary(dict)) {
433 *sc_status = kSCStatusInvalidArgument;
434 goto done;
435 }
436
437 if ((remove != NULL) && !isA_CFArray(remove)) {
438 *sc_status = kSCStatusInvalidArgument;
439 goto done;
440 }
441
442 if ((notify != NULL) && !isA_CFArray(notify)) {
443 *sc_status = kSCStatusInvalidArgument;
444 goto done;
445 }
446
447 mySession = getSession(server);
448 if (mySession == NULL) {
449 /* you must have an open session to play */
450 *sc_status = kSCStatusNoStoreSession;
451 goto done;
452 }
453
454 *sc_status = __SCDynamicStoreSetMultiple(mySession->store, dict, remove, notify);
455
456 done :
457
458 if (dict != NULL) CFRelease(dict);
459 if (remove != NULL) CFRelease(remove);
460 if (notify != NULL) CFRelease(notify);
461
462 return KERN_SUCCESS;
463 }