]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCD.c
configd-53.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCD.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 <mach/mach.h>
34 #include <mach/mach_error.h>
35 #include <pthread.h>
36
37 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCPrivate.h>
39 #include "SCDynamicStoreInternal.h"
40 #include "config.h" /* MiG generated file */
41
42 /* framework variables */
43 Boolean _sc_debug = FALSE; /* TRUE if debugging enabled */
44 Boolean _sc_verbose = FALSE; /* TRUE if verbose logging enabled */
45 Boolean _sc_log = TRUE; /* TRUE if SCLog() output goes to syslog */
46
47 static const struct sc_errmsg {
48 int status;
49 char *message;
50 } sc_errmsgs[] = {
51 { kSCStatusAccessError, "Permission denied" },
52 { kSCStatusFailed, "Failed!" },
53 { kSCStatusInvalidArgument, "Invalid argument" },
54 { kSCStatusKeyExists, "Key already defined" },
55 { kSCStatusLocked, "Lock already held" },
56 { kSCStatusMaxLink, "Maximum link count exceeded" },
57 { kSCStatusNeedLock, "Lock required for this operation" },
58 { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" },
59 { kSCStatusNoStoreSession, "Configuration daemon session not active" },
60 { kSCStatusNoConfigFile, "Configuration file not found" },
61 { kSCStatusNoKey, "No such key" },
62 { kSCStatusNoLink, "No such link" },
63 { kSCStatusNoPrefsSession, "Preference session not active" },
64 { kSCStatusNotifierActive, "Notifier is currently active" },
65 { kSCStatusOK, "Success!" },
66 { kSCStatusPrefsBusy, "Configuration daemon busy" },
67 { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" },
68 { kSCStatusStale, "Write attempted on stale version of object" },
69 };
70 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
71
72
73 #define USE_SCCOPYDESCRIPTION
74 #ifdef USE_SCCOPYDESCRIPTION
75
76 // from <CoreFoundation/CFVeryPrivate.h>
77 extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(void *, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments);
78
79 static CFStringRef
80 _SCCopyDescription(void *info, CFDictionaryRef formatOptions)
81 {
82 CFMutableDictionaryRef nFormatOptions;
83 CFStringRef prefix1;
84 CFStringRef prefix2;
85 CFTypeID type = CFGetTypeID(info);
86
87 if (!formatOptions ||
88 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) {
89 prefix1 = CFSTR("");
90 }
91
92 if (type == CFStringGetTypeID()) {
93 return CFStringCreateWithFormat(NULL,
94 formatOptions,
95 CFSTR("%@%@"),
96 prefix1,
97 info);
98 }
99
100 if (type == CFBooleanGetTypeID()) {
101 return CFStringCreateWithFormat(NULL,
102 formatOptions,
103 CFSTR("%@%s"),
104 prefix1,
105 CFBooleanGetValue(info) ? "TRUE" : "FALSE");
106 }
107
108 if (type == CFDataGetTypeID()) {
109 const u_int8_t *data;
110 CFIndex dataLen;
111 CFIndex i;
112 CFMutableStringRef str;
113
114 str = CFStringCreateMutable(NULL, 0);
115 CFStringAppendFormat(str, formatOptions, CFSTR("%@<data> 0x"), prefix1);
116
117 data = CFDataGetBytePtr(info);
118 dataLen = CFDataGetLength(info);
119 for (i = 0; i < dataLen; i++) {
120 CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]);
121 }
122
123 return str;
124 }
125
126 if (type == CFNumberGetTypeID()) {
127 return CFStringCreateWithFormat(NULL,
128 formatOptions,
129 CFSTR("%@%@"),
130 prefix1,
131 info);
132 }
133
134 if (type == CFDateGetTypeID()) {
135 CFGregorianDate gDate;
136 CFStringRef str;
137 CFTimeZoneRef tZone;
138
139 tZone = CFTimeZoneCopySystem();
140 gDate = CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(info), tZone);
141 str = CFStringCreateWithFormat(NULL,
142 formatOptions,
143 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
144 prefix1,
145 gDate.month,
146 gDate.day,
147 gDate.year,
148 gDate.hour,
149 gDate.minute,
150 gDate.second,
151 CFTimeZoneGetName(tZone));
152 CFRelease(tZone);
153 return str;
154 }
155
156 if (!formatOptions ||
157 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) {
158 prefix2 = CFStringCreateCopy(NULL, prefix1);
159 }
160
161 if (formatOptions) {
162 nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions);
163 } else {
164 nFormatOptions = CFDictionaryCreateMutable(NULL,
165 0,
166 &kCFTypeDictionaryKeyCallBacks,
167 &kCFTypeDictionaryValueCallBacks);
168 }
169
170 if (type == CFArrayGetTypeID()) {
171 const void **elements;
172 CFIndex i;
173 CFIndex nElements;
174 CFMutableStringRef str;
175
176 str = CFStringCreateMutable(NULL, 0);
177 CFStringAppendFormat(str, formatOptions, CFSTR("%@<array> {"), prefix1);
178
179 nElements = CFArrayGetCount(info);
180 if (nElements > 0) {
181 elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
182 CFArrayGetValues(info, CFRangeMake(0, nElements), elements);
183 for (i=0; i<nElements; i++) {
184 CFMutableStringRef nPrefix1;
185 CFMutableStringRef nPrefix2;
186 CFStringRef nStr;
187 CFStringRef vStr;
188
189 nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%u"), i);
190
191 nPrefix1 = CFStringCreateMutable(NULL, 0);
192 CFStringAppendFormat(nPrefix1,
193 formatOptions,
194 CFSTR("%@ %@ : "),
195 prefix2,
196 nStr);
197 nPrefix2 = CFStringCreateMutable(NULL, 0);
198 CFStringAppendFormat(nPrefix2,
199 formatOptions,
200 CFSTR("%@ "),
201 prefix2);
202
203 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
204 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
205 CFRelease(nPrefix1);
206 CFRelease(nPrefix2);
207 CFRelease(nStr);
208
209 vStr = _SCCopyDescription((void *)elements[i], nFormatOptions);
210 CFStringAppendFormat(str,
211 formatOptions,
212 CFSTR("\n%@"),
213 vStr);
214 CFRelease(vStr);
215 }
216 CFAllocatorDeallocate(NULL, elements);
217 }
218 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
219
220 CFRelease(nFormatOptions);
221 return str;
222 }
223
224 if (type == CFDictionaryGetTypeID()) {
225 const void **keys;
226 CFIndex i;
227 CFIndex nElements;
228 CFMutableStringRef nPrefix1;
229 CFMutableStringRef nPrefix2;
230 CFMutableStringRef str;
231 const void **values;
232
233 str = CFStringCreateMutable(NULL, 0);
234 CFStringAppendFormat(str, formatOptions, CFSTR("%@<dictionary> {"), prefix1);
235
236 nElements = CFDictionaryGetCount(info);
237 if (nElements > 0) {
238 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
239 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
240 CFDictionaryGetKeysAndValues(info, keys, values);
241 for (i=0; i<nElements; i++) {
242 CFStringRef kStr;
243 CFStringRef vStr;
244
245 kStr = _SCCopyDescription((void *)keys[i], NULL);
246
247 nPrefix1 = CFStringCreateMutable(NULL, 0);
248 CFStringAppendFormat(nPrefix1,
249 formatOptions,
250 CFSTR("%@ %@ : "),
251 prefix2,
252 kStr);
253 nPrefix2 = CFStringCreateMutable(NULL, 0);
254 CFStringAppendFormat(nPrefix2,
255 formatOptions,
256 CFSTR("%@ "),
257 prefix2);
258
259 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
260 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
261 CFRelease(nPrefix1);
262 CFRelease(nPrefix2);
263 CFRelease(kStr);
264
265 vStr = _SCCopyDescription((void *)values[i], nFormatOptions);
266 CFStringAppendFormat(str,
267 formatOptions,
268 CFSTR("\n%@"),
269 vStr);
270 CFRelease(vStr);
271 }
272 CFAllocatorDeallocate(NULL, keys);
273 CFAllocatorDeallocate(NULL, values);
274 }
275 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
276
277 CFRelease(nFormatOptions);
278 return str;
279 }
280
281 {
282 CFStringRef cfStr;
283 CFStringRef str;
284
285 cfStr = CFCopyDescription(info);
286 str = CFStringCreateWithFormat(NULL,
287 formatOptions,
288 CFSTR("%@%@"),
289 prefix1,
290 cfStr);
291 CFRelease(cfStr);
292 return str;
293 }
294 }
295
296 #endif /* USE_SCCOPYDESCRIPTION */
297
298
299 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
300
301
302 __private_extern__ void
303 __SCLog(int level, CFStringRef str)
304 {
305 CFArrayRef lines;
306
307 lines = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR("\n"));
308 if (lines) {
309 int i;
310
311 pthread_mutex_lock(&lock);
312 for (i=0; i<CFArrayGetCount(lines); i++) {
313 CFDataRef line;
314
315 line = CFStringCreateExternalRepresentation(NULL,
316 CFArrayGetValueAtIndex(lines, i),
317 kCFStringEncodingMacRoman,
318 '?');
319 if (line) {
320 syslog (level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line));
321 CFRelease(line);
322 }
323 }
324 pthread_mutex_unlock(&lock);
325 CFRelease(lines);
326 }
327
328 return;
329 }
330
331
332 __private_extern__ void
333 __SCPrint(FILE *stream, CFStringRef str)
334 {
335 CFDataRef line;
336
337 line = CFStringCreateExternalRepresentation(NULL,
338 str,
339 kCFStringEncodingMacRoman,
340 '?');
341 if (line) {
342 pthread_mutex_lock(&lock);
343 fprintf(stream, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line));
344 fflush (stream);
345 pthread_mutex_unlock(&lock);
346 CFRelease(line);
347 }
348
349 return;
350 }
351
352
353 void
354 SCLog(Boolean condition, int level, CFStringRef formatString, ...)
355 {
356 va_list argList;
357 CFStringRef resultString;
358
359 if (!condition) {
360 return;
361 }
362
363 va_start(argList, formatString);
364 #ifdef USE_SCCOPYDESCRIPTION
365 resultString = _CFStringCreateWithFormatAndArgumentsAux(NULL,
366 _SCCopyDescription,
367 NULL,
368 formatString,
369 argList);
370 #else /* USE_SCCOPYDESCRIPTION */
371 resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList);
372 #endif /* !USE_SCCOPYDESCRIPTION */
373 va_end(argList);
374
375 if (_sc_log) {
376 __SCLog(level, resultString);
377 } else {
378 FILE *f = (LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout;
379 CFStringRef newString;
380
381 /* add a new-line */
382 newString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\n"), resultString);
383 __SCPrint(f, newString);
384 CFRelease(newString);
385 }
386 CFRelease(resultString);
387 return;
388 }
389
390
391 void
392 SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...)
393 {
394 va_list argList;
395 CFStringRef resultString;
396
397 if (!condition) {
398 return;
399 }
400
401 va_start(argList, formatString);
402 #ifdef USE_SCCOPYDESCRIPTION
403 resultString = _CFStringCreateWithFormatAndArgumentsAux(NULL,
404 _SCCopyDescription,
405 NULL,
406 formatString,
407 argList);
408 #else /* USE_SCCOPYDESCRIPTION */
409 resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList);
410 #endif /* !USE_SCCOPYDESCRIPTION */
411 va_end(argList);
412
413 __SCPrint(stream, resultString);
414 CFRelease(resultString);
415 return;
416 }
417
418
419 typedef struct {
420 int _sc_error;
421 } __SCThreadSpecificData, *__SCThreadSpecificDataRef;
422
423
424 static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT;
425 static pthread_key_t tsDataKey = NULL;
426
427
428 static void
429 __SCThreadSpecificDataFinalize(void *arg)
430 {
431 __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg;
432
433 if (!tsd) return;
434
435 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
436 return;
437 }
438
439
440 static void
441 __SCThreadSpecificKeyInitialize()
442 {
443 pthread_key_create(&tsDataKey, __SCThreadSpecificDataFinalize);
444 return;
445 }
446
447
448 void
449 _SCErrorSet(int error)
450 {
451 __SCThreadSpecificDataRef tsd;
452
453 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
454
455 tsd = pthread_getspecific(tsDataKey);
456 if (!tsd) {
457 tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0);
458 bzero(tsd, sizeof(__SCThreadSpecificData));
459 pthread_setspecific(tsDataKey, tsd);
460 }
461
462 tsd->_sc_error = error;
463 return;
464 }
465
466
467 int
468 SCError()
469 {
470 __SCThreadSpecificDataRef tsd;
471
472 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
473
474 tsd = pthread_getspecific(tsDataKey);
475 return tsd ? tsd->_sc_error : kSCStatusOK;
476 }
477
478
479 const char *
480 SCErrorString(int status)
481 {
482 int i;
483
484 for (i = 0; i < nSC_ERRMSGS; i++) {
485 if (sc_errmsgs[i].status == status) {
486 return sc_errmsgs[i].message;
487 }
488 }
489
490 if ((status > 0) && (status <= ELAST)) {
491 return strerror(status);
492 }
493
494 return mach_error_string(status);
495 }