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