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