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