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