]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configset.c
configd-84.1.tar.gz
[apple/configd.git] / configd.tproj / _configset.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Modification History
28 *
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
31 *
32 * March 24, 2000 Allan Nathanson <ajn@apple.com>
33 * - initial revision
34 */
35
36
37 #include "configd.h"
38 #include "session.h"
39 #include "pattern.h"
40
41
42 __private_extern__
43 int
44 __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal)
45 {
46 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
47 int sc_status = kSCStatusOK;
48 CFDictionaryRef dict;
49 CFMutableDictionaryRef newDict;
50 Boolean newEntry = FALSE;
51 CFStringRef sessionKey;
52 CFStringRef storeSessionKey;
53
54 if (_configd_verbose) {
55 CFPropertyListRef val;
56
57 (void) _SCUnserialize(&val, value, NULL, NULL);
58 SCLog(TRUE, LOG_DEBUG, CFSTR("__SCDynamicStoreSetValue:"));
59 SCLog(TRUE, LOG_DEBUG, CFSTR(" key = %@"), key);
60 SCLog(TRUE, LOG_DEBUG, CFSTR(" value = %@"), val);
61 CFRelease(val);
62 }
63
64 if (!store || (storePrivate->server == MACH_PORT_NULL)) {
65 return kSCStatusNoStoreSession; /* you must have an open session to play */
66 }
67
68 if (_configd_trace) {
69 SCTrace(TRUE, _configd_trace,
70 CFSTR("%s : %5d : %@\n"),
71 internal ? "*set " : "set ",
72 storePrivate->server,
73 key);
74 }
75
76 /*
77 * 1. Ensure that we hold the lock.
78 */
79 sc_status = __SCDynamicStoreLock(store, TRUE);
80 if (sc_status != kSCStatusOK) {
81 return sc_status;
82 }
83
84 /*
85 * 2. Grab the current (or establish a new) dictionary for this key.
86 */
87
88 dict = CFDictionaryGetValue(storeData, key);
89 if (dict) {
90 newDict = CFDictionaryCreateMutableCopy(NULL,
91 0,
92 dict);
93 } else {
94 newDict = CFDictionaryCreateMutable(NULL,
95 0,
96 &kCFTypeDictionaryKeyCallBacks,
97 &kCFTypeDictionaryValueCallBacks);
98 }
99
100 /*
101 * 3. Update the dictionary entry to be saved to the store.
102 */
103 newEntry = !CFDictionaryContainsKey(newDict, kSCDData);
104 CFDictionarySetValue(newDict, kSCDData, value);
105
106 /*
107 * 4. Since we are updating this key we need to check and, if
108 * necessary, remove the indication that this key is on
109 * another session's remove-on-close list.
110 */
111 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
112 if (CFDictionaryGetValueIfPresent(newDict, kSCDSession, (void *)&storeSessionKey) &&
113 !CFEqual(sessionKey, storeSessionKey)) {
114 CFStringRef removedKey;
115
116 /* We are no longer a session key! */
117 CFDictionaryRemoveValue(newDict, kSCDSession);
118
119 /* add this session key to the (session) removal list */
120 removedKey = CFStringCreateWithFormat(NULL, 0, CFSTR("%@:%@"), storeSessionKey, key);
121 CFSetAddValue(removedSessionKeys, removedKey);
122 CFRelease(removedKey);
123 }
124 CFRelease(sessionKey);
125
126 /*
127 * 5. Update the dictionary entry in the store.
128 */
129
130 CFDictionarySetValue(storeData, key, newDict);
131 CFRelease(newDict);
132
133 /*
134 * 6. For "new" entries to the store, check the deferred cleanup
135 * list. If the key is flagged for removal, remove it from the
136 * list since any defined regex's for this key are still defined
137 * and valid. If the key is not flagged then iterate over the
138 * sessionData dictionary looking for regex keys which match the
139 * updated key. If a match is found then we mark those keys as
140 * being watched.
141 */
142
143 if (newEntry) {
144 if (CFSetContainsValue(deferredRemovals, key)) {
145 CFSetRemoveValue(deferredRemovals, key);
146 } else {
147 patternAddKey(key);
148 }
149 }
150
151 /*
152 * 7. Mark this key as "changed". Any "watchers" will be notified
153 * as soon as the lock is released.
154 */
155 CFSetAddValue(changedKeys, key);
156
157 /*
158 * 8. Release our lock.
159 */
160 __SCDynamicStoreUnlock(store, TRUE);
161
162 return sc_status;
163 }
164
165 __private_extern__
166 kern_return_t
167 _configset(mach_port_t server,
168 xmlData_t keyRef, /* raw XML bytes */
169 mach_msg_type_number_t keyLen,
170 xmlData_t dataRef, /* raw XML bytes */
171 mach_msg_type_number_t dataLen,
172 int oldInstance,
173 int *newInstance,
174 int *sc_status
175 )
176 {
177 serverSessionRef mySession = getSession(server);
178 CFStringRef key; /* key (un-serialized) */
179 CFDataRef data; /* data (un-serialized) */
180
181 if (_configd_verbose) {
182 SCLog(TRUE, LOG_DEBUG, CFSTR("Set key to configuration database."));
183 SCLog(TRUE, LOG_DEBUG, CFSTR(" server = %d"), server);
184 }
185
186 *sc_status = kSCStatusOK;
187
188 /* un-serialize the key */
189 if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) {
190 *sc_status = kSCStatusFailed;
191 } else if (!isA_CFString(key)) {
192 *sc_status = kSCStatusInvalidArgument;
193 }
194
195 /* un-serialize the data */
196 if (!_SCUnserializeData(&data, (void *)dataRef, dataLen)) {
197 *sc_status = kSCStatusFailed;
198 }
199
200 if (!mySession) {
201 *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */
202 }
203
204 if (*sc_status != kSCStatusOK) {
205 if (key) CFRelease(key);
206 if (data) CFRelease(data);
207 return KERN_SUCCESS;
208 }
209
210 *sc_status = __SCDynamicStoreSetValue(mySession->store, key, data, FALSE);
211 *newInstance = 0;
212
213 CFRelease(key);
214 CFRelease(data);
215
216 return KERN_SUCCESS;
217 }
218
219 static void
220 setSpecificKey(const void *key, const void *value, void *context)
221 {
222 CFStringRef k = (CFStringRef)key;
223 CFDataRef v = (CFDataRef)value;
224 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
225
226 if (!isA_CFString(k)) {
227 return;
228 }
229
230 if (!isA_CFData(v)) {
231 return;
232 }
233
234 (void) __SCDynamicStoreSetValue(store, k, v, TRUE);
235
236 return;
237 }
238
239 static void
240 removeSpecificKey(const void *value, void *context)
241 {
242 CFStringRef k = (CFStringRef)value;
243 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
244
245 if (!isA_CFString(k)) {
246 return;
247 }
248
249 (void) __SCDynamicStoreRemoveValue(store, k, TRUE);
250
251 return;
252 }
253
254 static void
255 notifySpecificKey(const void *value, void *context)
256 {
257 CFStringRef k = (CFStringRef)value;
258 SCDynamicStoreRef store = (SCDynamicStoreRef)context;
259
260 if (!isA_CFString(k)) {
261 return;
262 }
263
264 (void) __SCDynamicStoreNotifyValue(store, k, TRUE);
265
266 return;
267 }
268
269 __private_extern__
270 int
271 __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify)
272 {
273 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
274 int sc_status = kSCStatusOK;
275
276 if (_configd_verbose) {
277 CFDictionaryRef expDict;
278
279 expDict = keysToSet ? _SCUnserializeMultiple(keysToSet) : NULL;
280 SCLog(TRUE, LOG_DEBUG, CFSTR("__SCDynamicStoreSetMultiple:"));
281 SCLog(TRUE, LOG_DEBUG, CFSTR(" keysToSet = %@"), expDict);
282 SCLog(TRUE, LOG_DEBUG, CFSTR(" keysToRemove = %@"), keysToRemove);
283 SCLog(TRUE, LOG_DEBUG, CFSTR(" keysToNotify = %@"), keysToNotify);
284 if (expDict) CFRelease(expDict);
285 }
286
287 if (!store || (storePrivate->server == MACH_PORT_NULL)) {
288 return kSCStatusNoStoreSession; /* you must have an open session to play */
289 }
290
291 if (_configd_trace) {
292 SCTrace(TRUE, _configd_trace,
293 CFSTR("set m : %5d : %d set, %d remove, %d notify\n"),
294 storePrivate->server,
295 keysToSet ? CFDictionaryGetCount(keysToSet) : 0,
296 keysToRemove ? CFArrayGetCount (keysToRemove) : 0,
297 keysToNotify ? CFArrayGetCount (keysToNotify) : 0);
298 }
299
300 /*
301 * Ensure that we hold the lock
302 */
303 sc_status = __SCDynamicStoreLock(store, TRUE);
304 if (sc_status != kSCStatusOK) {
305 return sc_status;
306 }
307
308 /*
309 * Set the new/updated keys
310 */
311 if (keysToSet) {
312 CFDictionaryApplyFunction(keysToSet,
313 setSpecificKey,
314 (void *)store);
315 }
316
317 /*
318 * Remove the specified keys
319 */
320 if (keysToRemove) {
321 CFArrayApplyFunction(keysToRemove,
322 CFRangeMake(0, CFArrayGetCount(keysToRemove)),
323 removeSpecificKey,
324 (void *)store);
325 }
326
327 /*
328 * Notify the specified keys
329 */
330 if (keysToNotify) {
331 CFArrayApplyFunction(keysToNotify,
332 CFRangeMake(0, CFArrayGetCount(keysToNotify)),
333 notifySpecificKey,
334 (void *)store);
335 }
336
337 /* Release our lock */
338 __SCDynamicStoreUnlock(store, TRUE);
339
340 return sc_status;
341 }
342
343 __private_extern__
344 kern_return_t
345 _configset_m(mach_port_t server,
346 xmlData_t dictRef,
347 mach_msg_type_number_t dictLen,
348 xmlData_t removeRef,
349 mach_msg_type_number_t removeLen,
350 xmlData_t notifyRef,
351 mach_msg_type_number_t notifyLen,
352 int *sc_status)
353 {
354 serverSessionRef mySession = getSession(server);
355 CFDictionaryRef dict = NULL; /* key/value dictionary (un-serialized) */
356 CFArrayRef remove = NULL; /* keys to remove (un-serialized) */
357 CFArrayRef notify = NULL; /* keys to notify (un-serialized) */
358
359 if (_configd_verbose) {
360 SCLog(TRUE, LOG_DEBUG, CFSTR("Set/remove/notify keys to configuration database."));
361 SCLog(TRUE, LOG_DEBUG, CFSTR(" server = %d"), server);
362 }
363
364 *sc_status = kSCStatusOK;
365
366 if (dictRef && (dictLen > 0)) {
367 /* un-serialize the key/value pairs to set */
368 if (!_SCUnserialize((CFPropertyListRef *)&dict, NULL, (void *)dictRef, dictLen)) {
369 *sc_status = kSCStatusFailed;
370 } else if (!isA_CFDictionary(dict)) {
371 *sc_status = kSCStatusInvalidArgument;
372 }
373 }
374
375 if (removeRef && (removeLen > 0)) {
376 /* un-serialize the keys to remove */
377 if (!_SCUnserialize((CFPropertyListRef *)&remove, NULL, (void *)removeRef, removeLen)) {
378 *sc_status = kSCStatusFailed;
379 } else if (!isA_CFArray(remove)) {
380 *sc_status = kSCStatusInvalidArgument;
381 }
382 }
383
384 if (notifyRef && (notifyLen > 0)) {
385 /* un-serialize the keys to notify */
386 if (!_SCUnserialize((CFPropertyListRef *)&notify, NULL, (void *)notifyRef, notifyLen)) {
387 *sc_status = kSCStatusFailed;
388 } else if (!isA_CFArray(notify)) {
389 *sc_status = kSCStatusInvalidArgument;
390 }
391 }
392
393 if (!mySession) {
394 /* you must have an open session to play */
395 *sc_status = kSCStatusNoStoreSession;
396 }
397
398 if (*sc_status != kSCStatusOK) {
399 goto done;
400 }
401
402 *sc_status = __SCDynamicStoreSetMultiple(mySession->store, dict, remove, notify);
403
404 done :
405
406 if (dict) CFRelease(dict);
407 if (remove) CFRelease(remove);
408 if (notify) CFRelease(notify);
409
410 return KERN_SUCCESS;
411 }