]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPOpen.c
configd-84.6.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCPOpen.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 * November 9, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCValidation.h>
36 #include <SystemConfiguration/SCPrivate.h>
37 #include "SCPreferencesInternal.h"
38
39 #include <fcntl.h>
40 #include <pthread.h>
41 #include <unistd.h>
42 #include <sys/errno.h>
43
44 static CFStringRef
45 __SCPreferencesCopyDescription(CFTypeRef cf) {
46 CFAllocatorRef allocator = CFGetAllocator(cf);
47 CFMutableStringRef result;
48
49 result = CFStringCreateMutable(allocator, 0);
50 CFStringAppendFormat(result, NULL, CFSTR("<SCPreferences %p [%p]> {\n"), cf, allocator);
51 CFStringAppendFormat(result, NULL, CFSTR("}"));
52
53 return result;
54 }
55
56
57 static void
58 __SCPreferencesDeallocate(CFTypeRef cf)
59 {
60 SCPreferencesPrivateRef sessionPrivate = (SCPreferencesPrivateRef)cf;
61
62 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesDeallocate:"));
63
64 /* release resources */
65 if (sessionPrivate->name) CFRelease(sessionPrivate->name);
66 if (sessionPrivate->prefsID) CFRelease(sessionPrivate->prefsID);
67 if (sessionPrivate->user) CFRelease(sessionPrivate->user);
68 if (sessionPrivate->path) CFAllocatorDeallocate(NULL, sessionPrivate->path);
69 if (sessionPrivate->newPath) CFAllocatorDeallocate(NULL, sessionPrivate->newPath);
70 if (sessionPrivate->signature) CFRelease(sessionPrivate->signature);
71 if (sessionPrivate->session) CFRelease(sessionPrivate->session);
72 if (sessionPrivate->sessionKeyLock) CFRelease(sessionPrivate->sessionKeyLock);
73 if (sessionPrivate->sessionKeyCommit) CFRelease(sessionPrivate->sessionKeyCommit);
74 if (sessionPrivate->sessionKeyApply) CFRelease(sessionPrivate->sessionKeyApply);
75 if (sessionPrivate->prefs) CFRelease(sessionPrivate->prefs);
76
77 return;
78 }
79
80
81 static CFTypeID __kSCPreferencesTypeID = _kCFRuntimeNotATypeID;
82
83
84 static const CFRuntimeClass __SCPreferencesClass = {
85 0, // version
86 "SCPreferences", // className
87 NULL, // init
88 NULL, // copy
89 __SCPreferencesDeallocate, // dealloc
90 NULL, // equal
91 NULL, // hash
92 NULL, // copyFormattingDesc
93 __SCPreferencesCopyDescription // copyDebugDesc
94 };
95
96
97 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
98
99 static void
100 __SCPreferencesInitialize(void) {
101 __kSCPreferencesTypeID = _CFRuntimeRegisterClass(&__SCPreferencesClass);
102 return;
103 }
104
105
106 static SCPreferencesPrivateRef
107 __SCPreferencesCreatePrivate(CFAllocatorRef allocator)
108 {
109 SCPreferencesPrivateRef prefsPrivate;
110 uint32_t size;
111
112 /* initialize runtime */
113 pthread_once(&initialized, __SCPreferencesInitialize);
114
115 /* allocate session */
116 size = sizeof(SCPreferencesPrivate) - sizeof(CFRuntimeBase);
117 prefsPrivate = (SCPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
118 __kSCPreferencesTypeID,
119 size,
120 NULL);
121 if (!prefsPrivate) {
122 return NULL;
123 }
124
125 prefsPrivate->name = NULL;
126 prefsPrivate->prefsID = NULL;
127 prefsPrivate->perUser = FALSE;
128 prefsPrivate->user = NULL;
129 prefsPrivate->path = NULL;
130 prefsPrivate->newPath = NULL; // new prefs path
131 prefsPrivate->signature = NULL;
132 prefsPrivate->session = NULL;
133 prefsPrivate->sessionKeyLock = NULL;
134 prefsPrivate->sessionKeyCommit = NULL;
135 prefsPrivate->sessionKeyApply = NULL;
136 prefsPrivate->prefs = NULL;
137 prefsPrivate->accessed = FALSE;
138 prefsPrivate->changed = FALSE;
139 prefsPrivate->locked = FALSE;
140 prefsPrivate->isRoot = (geteuid() == 0);
141
142 return prefsPrivate;
143 }
144
145
146 __private_extern__ SCPreferencesRef
147 __SCPreferencesCreate(CFAllocatorRef allocator,
148 CFStringRef name,
149 CFStringRef prefsID,
150 Boolean perUser,
151 CFStringRef user)
152 {
153 int fd = -1;
154 SCPreferencesPrivateRef prefsPrivate;
155 int sc_status = kSCStatusOK;
156 struct stat statBuf;
157 CFMutableDataRef xmlData;
158 CFStringRef xmlError;
159
160 /*
161 * allocate and initialize a new session
162 */
163 prefsPrivate = __SCPreferencesCreatePrivate(allocator);
164 if (!prefsPrivate) {
165 return NULL;
166 }
167
168 retry :
169
170 /*
171 * convert prefsID to path
172 */
173 prefsPrivate->path = __SCPreferencesPath(allocator,
174 prefsID,
175 perUser,
176 user,
177 (prefsPrivate->newPath == NULL));
178 if (prefsPrivate->path == NULL) {
179 sc_status = kSCStatusFailed;
180 goto error;
181 }
182
183 /*
184 * open file
185 */
186 fd = open(prefsPrivate->path, O_RDONLY, 0644);
187 if (fd == -1) {
188 switch (errno) {
189 case ENOENT :
190 /* no prefs file */
191 if (!perUser &&
192 ((prefsID == NULL) || !CFStringHasPrefix(prefsID, CFSTR("/")))) {
193 /* if default preference ID or relative path */
194 if (prefsPrivate->newPath == NULL) {
195 /*
196 * we've looked in the "new" prefs directory
197 * without success. Save the "new" path and
198 * look in the "old" prefs directory.
199 */
200 prefsPrivate->newPath = prefsPrivate->path;
201 goto retry;
202 } else {
203 /*
204 * we've looked in both the "new" and "old"
205 * prefs directories without success. USe
206 * the "new" path.
207 */
208 CFAllocatorDeallocate(NULL, prefsPrivate->path);
209 prefsPrivate->path = prefsPrivate->newPath;
210 prefsPrivate->newPath = NULL;
211 }
212 }
213
214 /* start fresh */
215 bzero(&statBuf, sizeof(statBuf));
216 goto create_1;
217 case EACCES :
218 sc_status = kSCStatusAccessError;
219 break;
220 default :
221 sc_status = kSCStatusFailed;
222 break;
223 }
224 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("open() failed: %s"), strerror(errno));
225 goto error;
226 }
227
228 /*
229 * check file, create signature
230 */
231 if (fstat(fd, &statBuf) == -1) {
232 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("fstat() failed: %s"), strerror(errno));
233 sc_status = kSCStatusFailed;
234 goto error;
235 }
236
237 create_1 :
238
239 prefsPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
240
241 if (statBuf.st_size > 0) {
242 CFDictionaryRef dict;
243
244 /*
245 * extract property list
246 */
247 xmlData = CFDataCreateMutable(allocator, statBuf.st_size);
248 CFDataSetLength(xmlData, statBuf.st_size);
249 if (read(fd, (void *)CFDataGetBytePtr(xmlData), statBuf.st_size) != statBuf.st_size) {
250 /* corrupt prefs file, start fresh */
251 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCPOpen read(): could not load preference data."));
252 CFRelease(xmlData);
253 xmlData = NULL;
254 goto create_2;
255 }
256
257 /*
258 * load preferences
259 */
260 dict = CFPropertyListCreateFromXMLData(allocator,
261 xmlData,
262 kCFPropertyListImmutable,
263 &xmlError);
264 CFRelease(xmlData);
265 if (!dict) {
266 /* corrupt prefs file, start fresh */
267 if (xmlError) {
268 SCLog(TRUE, LOG_ERR,
269 CFSTR("_SCPOpen CFPropertyListCreateFromXMLData(): %@"),
270 xmlError);
271 CFRelease(xmlError);
272 }
273 goto create_2;
274 }
275
276 /*
277 * make sure that we've got a dictionary
278 */
279 if (!isA_CFDictionary(dict)) {
280 /* corrupt prefs file, start fresh */
281 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCPOpen CFGetTypeID(): not a dictionary."));
282 CFRelease(dict);
283 goto create_2;
284 }
285
286 prefsPrivate->prefs = CFDictionaryCreateMutableCopy(allocator, 0, dict);
287 CFRelease(dict);
288 }
289
290 create_2 :
291
292 if (fd != -1) {
293 (void) close(fd);
294 fd = -1;
295 }
296
297 if (prefsPrivate->prefs == NULL) {
298 /*
299 * new file, create empty preferences
300 */
301 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCPOpen(): creating new dictionary."));
302 prefsPrivate->prefs = CFDictionaryCreateMutable(allocator,
303 0,
304 &kCFTypeDictionaryKeyCallBacks,
305 &kCFTypeDictionaryValueCallBacks);
306 prefsPrivate->changed = TRUE;
307 }
308
309 /*
310 * all OK
311 */
312 prefsPrivate->name = CFStringCreateCopy(allocator, name);
313 if (prefsID) prefsPrivate->prefsID = CFStringCreateCopy(allocator, prefsID);
314 prefsPrivate->perUser = perUser;
315 if (user) prefsPrivate->user = CFStringCreateCopy(allocator, user);
316 return (SCPreferencesRef)prefsPrivate;
317
318 error :
319
320 if (fd != -1) (void) close(fd);
321 CFRelease(prefsPrivate);
322 _SCErrorSet(sc_status);
323 return NULL;
324 }
325
326
327 SCPreferencesRef
328 SCPreferencesCreate(CFAllocatorRef allocator,
329 CFStringRef name,
330 CFStringRef prefsID)
331 {
332 if (_sc_verbose) {
333 SCLog(TRUE, LOG_DEBUG, CFSTR("SCPreferencesCreate:"));
334 SCLog(TRUE, LOG_DEBUG, CFSTR(" name = %@"), name);
335 SCLog(TRUE, LOG_DEBUG, CFSTR(" prefsID = %@"), prefsID);
336 }
337
338 return __SCPreferencesCreate(allocator, name, prefsID, FALSE, NULL);
339 }
340
341
342 SCPreferencesRef
343 SCUserPreferencesCreate(CFAllocatorRef allocator,
344 CFStringRef name,
345 CFStringRef prefsID,
346 CFStringRef user)
347 {
348 if (_sc_verbose) {
349 SCLog(TRUE, LOG_DEBUG, CFSTR("SCUserPreferencesCreate:"));
350 SCLog(TRUE, LOG_DEBUG, CFSTR(" name = %@"), name);
351 SCLog(TRUE, LOG_DEBUG, CFSTR(" prefsID = %@"), prefsID);
352 SCLog(TRUE, LOG_DEBUG, CFSTR(" user = %@"), user);
353 }
354
355 return __SCPreferencesCreate(allocator, name, prefsID, TRUE, user);
356 }
357
358
359 CFTypeID
360 SCPreferencesGetTypeID(void) {
361 pthread_once(&initialized, __SCPreferencesInitialize); /* initialize runtime */
362 return __kSCPreferencesTypeID;
363 }