]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCD.c
configd-293.4.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCD.c
1 /*
2 * Copyright (c) 2000-2008 Apple 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 * March 24, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <mach/mach.h>
35 #include <mach/mach_error.h>
36 #include <servers/bootstrap.h>
37 #include <pthread.h>
38 #include <sys/time.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
46 /* framework variables */
47 int _sc_debug = FALSE; /* non-zero if debugging enabled */
48 int _sc_verbose = FALSE; /* non-zero if verbose logging enabled */
49 int _sc_log = TRUE; /* 0 if SC messages should be written to stdout/stderr,
50 1 if SC messages should be logged w/asl(3),
51 2 if SC messages should be written to stdout/stderr AND logged */
52
53
54 #pragma mark -
55 #pragma mark Thread specific data
56
57
58 typedef struct {
59 aslclient _asl;
60 int _sc_error;
61 } __SCThreadSpecificData, *__SCThreadSpecificDataRef;
62
63
64 static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT;
65 static pthread_key_t tsDataKey;
66
67
68 static void
69 __SCThreadSpecificDataFinalize(void *arg)
70 {
71 __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg;
72
73 if (tsd != NULL) {
74 if (tsd->_asl != NULL) asl_close(tsd->_asl);
75 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
76 }
77 return;
78 }
79
80
81 static void
82 __SCThreadSpecificKeyInitialize()
83 {
84 pthread_key_create(&tsDataKey, __SCThreadSpecificDataFinalize);
85 return;
86 }
87
88
89 static __SCThreadSpecificDataRef
90 __SCGetThreadSpecificData()
91 {
92 __SCThreadSpecificDataRef tsd;
93
94 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
95
96 tsd = pthread_getspecific(tsDataKey);
97 if (tsd == NULL) {
98 tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0);
99 tsd->_asl = asl_open(NULL, NULL, 0);
100 asl_set_filter(tsd->_asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
101 tsd->_sc_error = kSCStatusOK;
102 pthread_setspecific(tsDataKey, tsd);
103 }
104
105 return tsd;
106 }
107
108
109 #pragma mark -
110 #pragma mark Logging
111
112
113 #define ENABLE_SC_FORMATTING
114 #ifdef ENABLE_SC_FORMATTING
115 // from <CoreFoundation/ForFoundationOnly.h>
116 extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(CFTypeRef, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments);
117 #endif /* ENABLE_SC_FORMATTING */
118
119
120 CFStringRef
121 _SCCopyDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
122 {
123 #ifdef ENABLE_SC_FORMATTING
124 CFMutableDictionaryRef nFormatOptions;
125 CFStringRef prefix1;
126 CFStringRef prefix2;
127 CFTypeID type = CFGetTypeID(cf);
128
129 if (!formatOptions ||
130 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) {
131 prefix1 = CFSTR("");
132 }
133
134 if (type == CFStringGetTypeID()) {
135 return CFStringCreateWithFormat(NULL,
136 formatOptions,
137 CFSTR("%@%@"),
138 prefix1,
139 cf);
140 }
141
142 if (type == CFBooleanGetTypeID()) {
143 return CFStringCreateWithFormat(NULL,
144 formatOptions,
145 CFSTR("%@%s"),
146 prefix1,
147 CFBooleanGetValue(cf) ? "TRUE" : "FALSE");
148 }
149
150 if (type == CFDataGetTypeID()) {
151 const uint8_t *data;
152 CFIndex dataLen;
153 CFIndex i;
154 CFMutableStringRef str;
155
156 str = CFStringCreateMutable(NULL, 0);
157 CFStringAppendFormat(str, formatOptions, CFSTR("%@<data> 0x"), prefix1);
158
159 data = CFDataGetBytePtr(cf);
160 dataLen = CFDataGetLength(cf);
161 for (i = 0; i < dataLen; i++) {
162 CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]);
163 }
164
165 return str;
166 }
167
168 if (type == CFNumberGetTypeID()) {
169 return CFStringCreateWithFormat(NULL,
170 formatOptions,
171 CFSTR("%@%@"),
172 prefix1,
173 cf);
174 }
175
176 if (type == CFDateGetTypeID()) {
177 CFGregorianDate gDate;
178 CFStringRef str;
179 CFTimeZoneRef tZone;
180
181 tZone = CFTimeZoneCopySystem();
182 gDate = CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(cf), tZone);
183 str = CFStringCreateWithFormat(NULL,
184 formatOptions,
185 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
186 prefix1,
187 gDate.month,
188 gDate.day,
189 gDate.year,
190 gDate.hour,
191 gDate.minute,
192 gDate.second,
193 CFTimeZoneGetName(tZone));
194 CFRelease(tZone);
195 return str;
196 }
197
198 if (!formatOptions ||
199 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) {
200 prefix2 = prefix1;
201 }
202
203 if (formatOptions) {
204 nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions);
205 } else {
206 nFormatOptions = CFDictionaryCreateMutable(NULL,
207 0,
208 &kCFTypeDictionaryKeyCallBacks,
209 &kCFTypeDictionaryValueCallBacks);
210 }
211
212 #define N_QUICK 32
213
214 if (type == CFArrayGetTypeID()) {
215 const void * elements_q[N_QUICK];
216 const void ** elements = elements_q;
217 CFIndex i;
218 CFIndex nElements;
219 CFMutableStringRef str;
220
221 str = CFStringCreateMutable(NULL, 0);
222 CFStringAppendFormat(str, formatOptions, CFSTR("%@<array> {"), prefix1);
223
224 nElements = CFArrayGetCount(cf);
225 if (nElements > 0) {
226 if (nElements > (CFIndex)(sizeof(elements_q)/sizeof(CFTypeRef)))
227 elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
228 CFArrayGetValues(cf, CFRangeMake(0, nElements), elements);
229 for (i = 0; i < nElements; i++) {
230 CFMutableStringRef nPrefix1;
231 CFMutableStringRef nPrefix2;
232 CFStringRef nStr;
233 CFStringRef vStr;
234
235 nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%u"), i);
236
237 nPrefix1 = CFStringCreateMutable(NULL, 0);
238 CFStringAppendFormat(nPrefix1,
239 formatOptions,
240 CFSTR("%@ %@ : "),
241 prefix2,
242 nStr);
243 nPrefix2 = CFStringCreateMutable(NULL, 0);
244 CFStringAppendFormat(nPrefix2,
245 formatOptions,
246 CFSTR("%@ "),
247 prefix2);
248
249 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
250 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
251 CFRelease(nPrefix1);
252 CFRelease(nPrefix2);
253 CFRelease(nStr);
254
255 vStr = _SCCopyDescription((CFTypeRef)elements[i], nFormatOptions);
256 CFStringAppendFormat(str,
257 formatOptions,
258 CFSTR("\n%@"),
259 vStr);
260 CFRelease(vStr);
261 }
262 if (elements != elements_q) CFAllocatorDeallocate(NULL, elements);
263 }
264 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
265
266 CFRelease(nFormatOptions);
267 return str;
268 }
269
270 if (type == CFDictionaryGetTypeID()) {
271 const void * keys_q[N_QUICK];
272 const void ** keys = keys_q;
273 CFIndex i;
274 CFIndex nElements;
275 CFMutableStringRef nPrefix1;
276 CFMutableStringRef nPrefix2;
277 CFMutableStringRef str;
278 const void * values_q[N_QUICK];
279 const void ** values = values_q;
280
281 str = CFStringCreateMutable(NULL, 0);
282 CFStringAppendFormat(str, formatOptions, CFSTR("%@<dictionary> {"), prefix1);
283
284 nElements = CFDictionaryGetCount(cf);
285 if (nElements > 0) {
286 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
287 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
288 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
289 }
290 CFDictionaryGetKeysAndValues(cf, keys, values);
291 for (i = 0; i < nElements; i++) {
292 CFStringRef kStr;
293 CFStringRef vStr;
294
295 kStr = _SCCopyDescription((CFTypeRef)keys[i], NULL);
296
297 nPrefix1 = CFStringCreateMutable(NULL, 0);
298 CFStringAppendFormat(nPrefix1,
299 formatOptions,
300 CFSTR("%@ %@ : "),
301 prefix2,
302 kStr);
303 nPrefix2 = CFStringCreateMutable(NULL, 0);
304 CFStringAppendFormat(nPrefix2,
305 formatOptions,
306 CFSTR("%@ "),
307 prefix2);
308
309 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
310 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
311 CFRelease(nPrefix1);
312 CFRelease(nPrefix2);
313 CFRelease(kStr);
314
315 vStr = _SCCopyDescription((CFTypeRef)values[i], nFormatOptions);
316 CFStringAppendFormat(str,
317 formatOptions,
318 CFSTR("\n%@"),
319 vStr);
320 CFRelease(vStr);
321 }
322 if (keys != keys_q) {
323 CFAllocatorDeallocate(NULL, keys);
324 CFAllocatorDeallocate(NULL, values);
325 }
326 }
327 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
328
329 CFRelease(nFormatOptions);
330 return str;
331 }
332
333 CFRelease(nFormatOptions);
334 #endif /* ENABLE_SC_FORMATTING */
335
336 return CFStringCreateWithFormat(NULL,
337 formatOptions,
338 CFSTR("%@%@"),
339 prefix1,
340 cf);
341 }
342
343
344 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
345
346
347 static void
348 __SCLog(aslclient asl, aslmsg msg, int level, CFStringRef formatString, va_list formatArguments)
349 {
350 CFDataRef line;
351 CFArrayRef lines;
352 CFStringRef str;
353
354 if (asl == NULL) {
355 __SCThreadSpecificDataRef tsd;
356
357 tsd = __SCGetThreadSpecificData();
358 asl = tsd->_asl;
359 }
360
361 #ifdef ENABLE_SC_FORMATTING
362 str = _CFStringCreateWithFormatAndArgumentsAux(NULL,
363 _SCCopyDescription,
364 NULL,
365 formatString,
366 formatArguments);
367 #else /* ENABLE_SC_FORMATTING */
368 str = CFStringCreateWithFormatAndArguments (NULL,
369 NULL,
370 formatString,
371 formatArguments);
372 #endif /* !ENABLE_SC_FORMATTING */
373
374 if (level >= 0) {
375 lines = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR("\n"));
376 if (lines != NULL) {
377 int i;
378 int n = CFArrayGetCount(lines);
379
380 for (i = 0; i < n; i++) {
381 line = CFStringCreateExternalRepresentation(NULL,
382 CFArrayGetValueAtIndex(lines, i),
383 kCFStringEncodingUTF8,
384 (UInt8)'?');
385 if (line) {
386 asl_log(asl, msg, level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line));
387 CFRelease(line);
388 }
389 }
390 CFRelease(lines);
391 }
392 } else {
393 line = CFStringCreateExternalRepresentation(NULL,
394 str,
395 kCFStringEncodingUTF8,
396 (UInt8)'?');
397 if (line) {
398 asl_log(asl, msg, ~level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line));
399 CFRelease(line);
400 }
401 }
402 CFRelease(str);
403
404 return;
405 }
406
407
408 static void
409 __SCPrint(FILE *stream, CFStringRef formatString, va_list formatArguments, Boolean trace, Boolean addNL)
410 {
411 CFDataRef line;
412 CFStringRef str;
413
414 #ifdef ENABLE_SC_FORMATTING
415 str = _CFStringCreateWithFormatAndArgumentsAux(NULL,
416 _SCCopyDescription,
417 NULL,
418 formatString,
419 formatArguments);
420 #else /* ENABLE_SC_FORMATTING */
421 str = CFStringCreateWithFormatAndArguments (NULL,
422 NULL,
423 formatString,
424 formatArguments);
425 #endif /* !ENABLE_SC_FORMATTING */
426
427 line = CFStringCreateExternalRepresentation(NULL,
428 str,
429 kCFStringEncodingUTF8,
430 (UInt8)'?');
431 CFRelease(str);
432 if (!line) {
433 return;
434 }
435
436 pthread_mutex_lock(&lock);
437 if (trace) {
438 struct tm tm_now;
439 struct timeval tv_now;
440
441 (void)gettimeofday(&tv_now, NULL);
442 (void)localtime_r(&tv_now.tv_sec, &tm_now);
443 (void)fprintf(stream, "%2d:%02d:%02d.%03d ",
444 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000);
445 }
446 (void)fwrite((const void *)CFDataGetBytePtr(line), (size_t)CFDataGetLength(line), 1, stream);
447 if (addNL) {
448 (void)fputc('\n', stream);
449 }
450 fflush (stream);
451 pthread_mutex_unlock(&lock);
452 CFRelease(line);
453
454 return;
455 }
456
457
458 void
459 SCLog(Boolean condition, int level, CFStringRef formatString, ...)
460 {
461 va_list formatArguments;
462
463 if (!condition) {
464 return;
465 }
466
467 va_start(formatArguments, formatString);
468 if (_sc_log > 0) {
469 __SCLog(NULL, NULL, level, formatString, formatArguments);
470 }
471 if (_sc_log != 1) {
472 __SCPrint((LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout,
473 formatString,
474 formatArguments,
475 (_sc_log > 0), // trace
476 TRUE); // add newline
477 }
478 va_end(formatArguments);
479
480 return;
481 }
482
483
484 void
485 SCLOG(aslclient asl, aslmsg msg, int level, CFStringRef formatString, ...)
486 {
487 va_list formatArguments;
488
489 va_start(formatArguments, formatString);
490 if (_sc_log > 0) {
491 __SCLog(asl, msg, level, formatString, formatArguments);
492 }
493 if (_sc_log != 1) {
494 if (level < 0) {
495 level = ~level;
496 }
497 __SCPrint((level > ASL_LEVEL_NOTICE) ? stderr : stdout,
498 formatString,
499 formatArguments,
500 (_sc_log > 0), // trace
501 TRUE); // add newline
502 }
503 va_end(formatArguments);
504
505 return;
506 }
507
508
509 void
510 SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...)
511 {
512 va_list formatArguments;
513
514 if (!condition) {
515 return;
516 }
517
518 va_start(formatArguments, formatString);
519 __SCPrint(stream, formatString, formatArguments, FALSE, FALSE);
520 va_end(formatArguments);
521
522 return;
523 }
524
525
526 void
527 SCTrace(Boolean condition, FILE *stream, CFStringRef formatString, ...)
528 {
529 va_list formatArguments;
530
531 if (!condition) {
532 return;
533 }
534
535 va_start(formatArguments, formatString);
536 __SCPrint(stream, formatString, formatArguments, TRUE, FALSE);
537 va_end(formatArguments);
538
539 return;
540 }
541
542
543 #pragma mark -
544 #pragma mark SC error handling / logging
545
546
547 const CFStringRef kCFErrorDomainSystemConfiguration = CFSTR("com.apple.SystemConfiguration");
548
549
550 static const struct sc_errmsg {
551 int status;
552 char *message;
553 } sc_errmsgs[] = {
554 { kSCStatusAccessError, "Permission denied" },
555 { kSCStatusConnectionNoService, "Network service for connection not available" },
556 { kSCStatusFailed, "Failed!" },
557 { kSCStatusInvalidArgument, "Invalid argument" },
558 { kSCStatusKeyExists, "Key already defined" },
559 { kSCStatusLocked, "Lock already held" },
560 { kSCStatusMaxLink, "Maximum link count exceeded" },
561 { kSCStatusNeedLock, "Lock required for this operation" },
562 { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" },
563 { kSCStatusNoStoreSession, "Configuration daemon session not active" },
564 { kSCStatusNoConfigFile, "Configuration file not found" },
565 { kSCStatusNoKey, "No such key" },
566 { kSCStatusNoLink, "No such link" },
567 { kSCStatusNoPrefsSession, "Preference session not active" },
568 { kSCStatusNotifierActive, "Notifier is currently active" },
569 { kSCStatusOK, "Success!" },
570 { kSCStatusPrefsBusy, "Preferences update currently in progress" },
571 { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" },
572 { kSCStatusStale, "Write attempted on stale version of object" },
573 };
574 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
575
576
577 void
578 _SCErrorSet(int error)
579 {
580 __SCThreadSpecificDataRef tsd;
581
582 tsd = __SCGetThreadSpecificData();
583 tsd->_sc_error = error;
584 return;
585 }
586
587
588 CFErrorRef
589 SCCopyLastError(void)
590 {
591 CFStringRef domain;
592 CFErrorRef error;
593 int i;
594 int code;
595 __SCThreadSpecificDataRef tsd;
596 CFMutableDictionaryRef userInfo = NULL;
597
598 tsd = __SCGetThreadSpecificData();
599 code =tsd->_sc_error;
600
601 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
602 if (sc_errmsgs[i].status == code) {
603 CFStringRef str;
604
605 domain = kCFErrorDomainSystemConfiguration;
606 userInfo = CFDictionaryCreateMutable(NULL,
607 0,
608 &kCFCopyStringDictionaryKeyCallBacks,
609 &kCFTypeDictionaryValueCallBacks);
610 str = CFStringCreateWithCString(NULL,
611 sc_errmsgs[i].message,
612 kCFStringEncodingASCII);
613 CFDictionarySetValue(userInfo, kCFErrorDescriptionKey, str);
614 CFRelease(str);
615 goto done;
616 }
617 }
618
619 if ((code > 0) && (code <= ELAST)) {
620 domain = kCFErrorDomainPOSIX;
621 goto done;
622 }
623
624 domain = kCFErrorDomainMach;
625
626 done :
627
628 error = CFErrorCreate(NULL, domain, code, userInfo);
629 if (userInfo != NULL) CFRelease(userInfo);
630 return error;
631 }
632
633
634 int
635 SCError(void)
636 {
637 __SCThreadSpecificDataRef tsd;
638
639 tsd = __SCGetThreadSpecificData();
640 return tsd->_sc_error;
641 }
642
643
644 const char *
645 SCErrorString(int status)
646 {
647 int i;
648
649 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
650 if (sc_errmsgs[i].status == status) {
651 return sc_errmsgs[i].message;
652 }
653 }
654
655 if ((status > 0) && (status <= ELAST)) {
656 return strerror(status);
657 }
658
659 if ((status >= BOOTSTRAP_SUCCESS) && (status <= BOOTSTRAP_NO_MEMORY)) {
660 return bootstrap_strerror(status);
661 }
662
663 return mach_error_string(status);
664 }