]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_configset.c
configd-24.tar.gz
[apple/configd.git] / configd.tproj / _configset.c
1 /*
2 * Copyright (c) 2000 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 #include "configd.h"
24 #include "session.h"
25
26 SCDStatus
27 _SCDSet(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
28 {
29 SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
30 SCDStatus scd_status = SCD_OK;
31 boolean_t wasLocked;
32 CFDictionaryRef dict;
33 CFMutableDictionaryRef newDict;
34 CFNumberRef num;
35 int dictInstance;
36 CFStringRef sessionKey;
37 CFStringRef cacheSessionKey;
38
39 SCDLog(LOG_DEBUG, CFSTR("_SCDSet:"));
40 SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
41 SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(handle));
42 SCDLog(LOG_DEBUG, CFSTR(" instance = %d"), SCDHandleGetInstance(handle));
43
44 if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
45 return SCD_NOSESSION; /* you can't do anything with a closed session */
46 }
47
48 /*
49 * 1. Determine if the cache lock is currently held
50 * and acquire the lock if necessary.
51 */
52 wasLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
53 if (!wasLocked) {
54 scd_status = _SCDLock(session);
55 if (scd_status != SCD_OK) {
56 SCDLog(LOG_DEBUG, CFSTR(" _SCDLock(): %s"), SCDError(scd_status));
57 return scd_status;
58 }
59 }
60
61 /*
62 * 2. Grab the current (or establish a new) dictionary for this key.
63 */
64
65 dict = CFDictionaryGetValue(cacheData, key);
66 if (dict) {
67 newDict = CFDictionaryCreateMutableCopy(NULL,
68 0,
69 dict);
70 } else {
71 newDict = CFDictionaryCreateMutable(NULL,
72 0,
73 &kCFTypeDictionaryKeyCallBacks,
74 &kCFTypeDictionaryValueCallBacks);
75 }
76
77 /*
78 * 3. Make sure that we're not updating the cache with potentially
79 * stale information.
80 */
81
82 if ((num = CFDictionaryGetValue(newDict, kSCDInstance)) == NULL) {
83 /* if first instance */
84 dictInstance = 0;
85 _SCDHandleSetInstance(handle, dictInstance);
86 } else {
87 (void) CFNumberGetValue(num, kCFNumberIntType, &dictInstance);
88 }
89 if (SCDHandleGetInstance(handle) != dictInstance) {
90 /* data may be based on old information */
91 CFRelease(newDict);
92 scd_status = SCD_STALE;
93 goto done;
94 }
95
96 /*
97 * 4. Update the dictionary entry (data & instance) to be saved to
98 * the cache.
99 */
100
101 CFDictionarySetValue(newDict, kSCDData, SCDHandleGetData(handle));
102
103 dictInstance++;
104 num = CFNumberCreate(NULL, kCFNumberIntType, &dictInstance);
105 CFDictionarySetValue(newDict, kSCDInstance, num);
106 CFRelease(num);
107 _SCDHandleSetInstance(handle, dictInstance);
108 SCDLog(LOG_DEBUG, CFSTR(" new instance = %d"), SCDHandleGetInstance(handle));
109
110 /*
111 * 5. Since we are updating this key we need to check and, if
112 * necessary, remove the indication that this key is on
113 * another session's remove-on-close list.
114 */
115 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
116 if (CFDictionaryGetValueIfPresent(newDict, kSCDSession, (void *)&cacheSessionKey) &&
117 !CFEqual(sessionKey, cacheSessionKey)) {
118 CFStringRef removedKey;
119
120 /* We are no longer a session key! */
121 CFDictionaryRemoveValue(newDict, kSCDSession);
122
123 /* add this session key to the (session) removal list */
124 removedKey = CFStringCreateWithFormat(NULL, 0, CFSTR("%@:%@"), cacheSessionKey, key);
125 CFSetAddValue(removedSessionKeys, removedKey);
126 CFRelease(removedKey);
127 }
128 CFRelease(sessionKey);
129
130 /*
131 * 6. Update the dictionary entry in the cache.
132 */
133
134 CFDictionarySetValue(cacheData, key, newDict);
135 CFRelease(newDict);
136
137 /*
138 * 7. For "new" entries to the cache, check the deferred cleanup
139 * list. If the key is flagged for removal, remove it from the
140 * list since any defined regex's for this key are still defined
141 * and valid. If the key is not flagged then iterate over the
142 * sessionData dictionary looking for regex keys which match the
143 * updated key. If a match is found then we mark those keys as
144 * being watched.
145 */
146
147 if (dictInstance == 1) {
148 if (CFSetContainsValue(deferredRemovals, key)) {
149 CFSetRemoveValue(deferredRemovals, key);
150 } else {
151 CFDictionaryApplyFunction(sessionData,
152 (CFDictionaryApplierFunction)_addRegexWatchersBySession,
153 (void *)key);
154 }
155 }
156
157 /*
158 * 8. Mark this key as "changed". Any "watchers" will be notified
159 * as soon as the lock is released.
160 */
161 CFSetAddValue(changedKeys, key);
162
163 /*
164 * 9. Release the lock if we acquired it as part of this request.
165 */
166 done:
167 if (!wasLocked)
168 _SCDUnlock(session);
169
170 return scd_status;
171 }
172
173
174 kern_return_t
175 _configset(mach_port_t server,
176 xmlData_t keyRef, /* raw XML bytes */
177 mach_msg_type_number_t keyLen,
178 xmlData_t dataRef, /* raw XML bytes */
179 mach_msg_type_number_t dataLen,
180 int oldInstance,
181 int *newInstance,
182 int *scd_status
183 )
184 {
185 kern_return_t status;
186 serverSessionRef mySession = getSession(server);
187 CFDataRef xmlKey; /* key (XML serialized) */
188 CFStringRef key; /* key (un-serialized) */
189 CFDataRef xmlData; /* data (XML serialized) */
190 CFPropertyListRef data; /* data (un-serialized) */
191 SCDHandleRef handle;
192 CFStringRef xmlError;
193
194 SCDLog(LOG_DEBUG, CFSTR("Set key to configuration database."));
195 SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
196
197 /* un-serialize the key */
198 xmlKey = CFDataCreate(NULL, keyRef, keyLen);
199 status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
200 if (status != KERN_SUCCESS) {
201 SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
202 /* non-fatal???, proceed */
203 }
204 key = CFPropertyListCreateFromXMLData(NULL,
205 xmlKey,
206 kCFPropertyListImmutable,
207 &xmlError);
208 CFRelease(xmlKey);
209 if (xmlError) {
210 SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
211 *scd_status = SCD_FAILED;
212 return KERN_SUCCESS;
213 }
214
215 /* un-serialize the data */
216 xmlData = CFDataCreate(NULL, dataRef, dataLen);
217 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
218 if (status != KERN_SUCCESS) {
219 SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
220 /* non-fatal???, proceed */
221 }
222 data = CFPropertyListCreateFromXMLData(NULL,
223 xmlData,
224 kCFPropertyListImmutable,
225 &xmlError);
226 CFRelease(xmlData);
227 if (xmlError) {
228 SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() data: %s"), xmlError);
229 CFRelease(key);
230 *scd_status = SCD_FAILED;
231 return KERN_SUCCESS;
232 }
233
234 handle = SCDHandleInit();
235 SCDHandleSetData(handle, data);
236 _SCDHandleSetInstance(handle, oldInstance);
237 *scd_status = _SCDSet(mySession->session, key, handle);
238 if (*scd_status == SCD_OK) {
239 *newInstance = SCDHandleGetInstance(handle);
240 }
241 SCDHandleRelease(handle);
242 CFRelease(key);
243 CFRelease(data);
244
245 return KERN_SUCCESS;
246 }