]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCD.c
configd-1061.141.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCD.c
1 /*
2 * Copyright (c) 2000-2008, 2010-2020 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_time.h>
36 #include <mach/mach_error.h>
37 #include <servers/bootstrap.h>
38 #include <pthread.h>
39 #include <sys/time.h>
40
41 #define OS_LOG_PACK_SPI
42 #include <os/log.h>
43 #include <os/log_private.h>
44
45 #include "SCDynamicStoreInternal.h"
46 #include "SCD.h"
47 #include "config.h" /* MiG generated file */
48
49 #define INSTALL_ENVIRONMENT "__OSINSTALL_ENVIRONMENT"
50
51 /* framework variables */
52 int _sc_debug = FALSE; /* non-zero if debugging enabled */
53 int _sc_verbose = FALSE; /* non-zero if verbose logging enabled */
54 _SCLogDestination _sc_log = kSCLogDestinationDefault;
55
56
57 #pragma mark -
58 #pragma mark Thread specific data
59
60
61 static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT;
62 static pthread_key_t tsDataKey;
63
64
65 static void
66 __SCThreadSpecificDataFinalize(void *arg)
67 {
68 __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg;
69
70 if (tsd != NULL) {
71 if (tsd->_sc_store != NULL) CFRelease(tsd->_sc_store);
72 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
73 }
74 return;
75 }
76
77
78 static void
79 __SCThreadSpecificKeyInitialize()
80 {
81 pthread_key_create(&tsDataKey, __SCThreadSpecificDataFinalize);
82 return;
83 }
84
85
86 __private_extern__
87 __SCThreadSpecificDataRef
88 __SCGetThreadSpecificData()
89 {
90 __SCThreadSpecificDataRef tsd;
91 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
92
93 tsd = pthread_getspecific(tsDataKey);
94 if (tsd == NULL) {
95 tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0);
96 tsd->_sc_error = kSCStatusOK;
97 tsd->_sc_store = NULL;
98 pthread_setspecific(tsDataKey, tsd);
99 }
100
101 return tsd;
102 }
103
104
105 #pragma mark -
106 #pragma mark Logging
107
108
109 #define ENABLE_SC_FORMATTING
110 #ifdef ENABLE_SC_FORMATTING
111 // from <CoreFoundation/ForFoundationOnly.h>
112 extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(CFTypeRef, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments);
113 #endif /* ENABLE_SC_FORMATTING */
114
115
116 CFStringRef
117 _SCCopyDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
118 {
119 #ifdef ENABLE_SC_FORMATTING
120 CFMutableDictionaryRef nFormatOptions;
121 CFStringRef prefix1;
122 CFStringRef prefix2;
123 CFTypeID type = CFGetTypeID(cf);
124
125 if (!formatOptions ||
126 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) {
127 prefix1 = CFSTR("");
128 }
129
130 if (type == CFStringGetTypeID()) {
131 return CFStringCreateWithFormat(NULL,
132 formatOptions,
133 CFSTR("%@%@"),
134 prefix1,
135 cf);
136 }
137
138 if (type == CFBooleanGetTypeID()) {
139 return CFStringCreateWithFormat(NULL,
140 formatOptions,
141 CFSTR("%@%s"),
142 prefix1,
143 CFBooleanGetValue(cf) ? "TRUE" : "FALSE");
144 }
145
146 if (type == CFDataGetTypeID()) {
147 const uint8_t *data;
148 CFIndex dataLen;
149 CFIndex i;
150 CFMutableStringRef str;
151
152 str = CFStringCreateMutable(NULL, 0);
153 CFStringAppendFormat(str, formatOptions, CFSTR("%@<data> 0x"), prefix1);
154
155 data = CFDataGetBytePtr(cf);
156 dataLen = CFDataGetLength(cf);
157 for (i = 0; i < dataLen; i++) {
158 CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]);
159 }
160
161 return str;
162 }
163
164 if (type == CFNumberGetTypeID()) {
165 return CFStringCreateWithFormat(NULL,
166 formatOptions,
167 CFSTR("%@%@"),
168 prefix1,
169 cf);
170 }
171
172 if (type == CFDateGetTypeID()) {
173 CFCalendarRef calendar;
174 CFStringRef str;
175 CFTimeZoneRef tz;
176 int MM, DD, YYYY, hh, mm, ss;
177
178 calendar = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
179 tz = CFTimeZoneCopySystem();
180 CFCalendarSetTimeZone(calendar, tz);
181 CFRelease(tz);
182 CFCalendarDecomposeAbsoluteTime(calendar,
183 CFDateGetAbsoluteTime(cf),
184 "MdyHms",
185 &MM, &DD, &YYYY, &hh, &mm, &ss);
186 CFRelease(calendar);
187
188 str = CFStringCreateWithFormat(NULL,
189 formatOptions,
190 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"),
191 prefix1,
192 MM, DD, YYYY, hh, mm, ss);
193 return str;
194 }
195
196 if ((formatOptions == NULL) ||
197 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) {
198 prefix2 = prefix1;
199 }
200
201 if (formatOptions != NULL) {
202 nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions);
203 } else {
204 nFormatOptions = CFDictionaryCreateMutable(NULL,
205 0,
206 &kCFTypeDictionaryKeyCallBacks,
207 &kCFTypeDictionaryValueCallBacks);
208 }
209 assert(nFormatOptions != NULL);
210
211 #define N_QUICK 32
212
213 if (type == CFArrayGetTypeID()) {
214 const void * elements_q[N_QUICK];
215 const void ** elements = elements_q;
216 CFIndex i;
217 CFIndex nElements;
218 CFMutableStringRef str;
219
220 str = CFStringCreateMutable(NULL, 0);
221 CFStringAppendFormat(str, formatOptions, CFSTR("%@<array> {"), prefix1);
222
223 nElements = CFArrayGetCount(cf);
224 if (nElements > 0) {
225 if (nElements > (CFIndex)(sizeof(elements_q)/sizeof(CFTypeRef)))
226 elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
227 CFArrayGetValues(cf, CFRangeMake(0, nElements), elements);
228 for (i = 0; i < nElements; i++) {
229 CFMutableStringRef nPrefix1;
230 CFMutableStringRef nPrefix2;
231 CFStringRef nStr;
232 CFStringRef vStr;
233
234 nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"), i);
235
236 nPrefix1 = CFStringCreateMutable(NULL, 0);
237 CFStringAppendFormat(nPrefix1,
238 formatOptions,
239 CFSTR("%@ %@ : "),
240 prefix2,
241 nStr);
242 nPrefix2 = CFStringCreateMutable(NULL, 0);
243 CFStringAppendFormat(nPrefix2,
244 formatOptions,
245 CFSTR("%@ "),
246 prefix2);
247
248 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
249 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
250 CFRelease(nPrefix1);
251 CFRelease(nPrefix2);
252 CFRelease(nStr);
253
254 vStr = _SCCopyDescription((CFTypeRef)elements[i], nFormatOptions);
255 CFStringAppendFormat(str,
256 formatOptions,
257 CFSTR("\n%@"),
258 vStr);
259 CFRelease(vStr);
260 }
261 if (elements != elements_q) CFAllocatorDeallocate(NULL, elements);
262 }
263 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
264
265 CFRelease(nFormatOptions);
266 return str;
267 }
268
269 if (type == CFDictionaryGetTypeID()) {
270 const void * keys_q[N_QUICK];
271 const void ** keys = keys_q;
272 CFIndex i;
273 CFIndex nElements;
274 CFMutableStringRef nPrefix1;
275 CFMutableStringRef nPrefix2;
276 CFMutableStringRef str;
277
278 str = CFStringCreateMutable(NULL, 0);
279 CFStringAppendFormat(str, formatOptions, CFSTR("%@<dictionary> {"), prefix1);
280
281 nElements = CFDictionaryGetCount(cf);
282 if (nElements > 0) {
283 CFComparatorFunction compFunc = NULL;
284 CFMutableArrayRef sortedKeys;
285
286 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
287 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
288 }
289 CFDictionaryGetKeysAndValues(cf, keys, NULL);
290
291 sortedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
292 for (i = 0; i < nElements; i++) {
293 CFArrayAppendValue(sortedKeys, (CFStringRef)keys[i]);
294 }
295
296 if (isA_CFString(keys[0])) {
297 compFunc = (CFComparatorFunction)CFStringCompare;
298 }
299 else if (isA_CFNumber(keys[0])) {
300 compFunc = (CFComparatorFunction)CFNumberCompare;
301 }
302 else if (isA_CFDate(keys[0])) {
303 compFunc = (CFComparatorFunction)CFDateCompare;
304 }
305
306 if (compFunc != NULL) {
307 CFArraySortValues(sortedKeys,
308 CFRangeMake(0, nElements),
309 compFunc,
310 NULL);
311 }
312
313 for (i = 0; i < nElements; i++) {
314 CFStringRef key;
315 CFStringRef kStr;
316 CFTypeRef val;
317 CFStringRef vStr;
318
319 key = CFArrayGetValueAtIndex(sortedKeys, i);
320 kStr = _SCCopyDescription((CFTypeRef)key, NULL);
321
322 nPrefix1 = CFStringCreateMutable(NULL, 0);
323 CFStringAppendFormat(nPrefix1,
324 formatOptions,
325 CFSTR("%@ %@ : "),
326 prefix2,
327 kStr);
328 nPrefix2 = CFStringCreateMutable(NULL, 0);
329 CFStringAppendFormat(nPrefix2,
330 formatOptions,
331 CFSTR("%@ "),
332 prefix2);
333
334 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
335 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
336 CFRelease(nPrefix1);
337 CFRelease(nPrefix2);
338 CFRelease(kStr);
339
340 val = CFDictionaryGetValue(cf, key);
341 vStr = _SCCopyDescription((CFTypeRef)val, nFormatOptions);
342 CFStringAppendFormat(str,
343 formatOptions,
344 CFSTR("\n%@"),
345 vStr);
346 CFRelease(vStr);
347 }
348
349 CFRelease(sortedKeys);
350
351 if (keys != keys_q) {
352 CFAllocatorDeallocate(NULL, keys);
353 }
354 }
355 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
356
357 CFRelease(nFormatOptions);
358 return str;
359 }
360
361 CFRelease(nFormatOptions);
362 #endif /* ENABLE_SC_FORMATTING */
363
364 return CFStringCreateWithFormat(NULL,
365 formatOptions,
366 CFSTR("%@%@"),
367 prefix1,
368 cf);
369 }
370
371
372 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
373
374 Boolean
375 _SC_isInstallEnvironment() {
376 static dispatch_once_t once;
377 static Boolean is_install;
378
379 dispatch_once(&once, ^{
380 is_install = (getenv(INSTALL_ENVIRONMENT) != NULL);
381 });
382
383 return is_install;
384 }
385
386
387 os_log_t
388 _SC_LOG_DEFAULT(void)
389 {
390 static os_log_t log = NULL;
391
392 if (log == NULL) {
393 log = os_log_create("com.apple.SystemConfiguration", "");
394 }
395
396 return log;
397 }
398
399
400 os_log_type_t
401 _SC_syslog_os_log_mapping(int level)
402 {
403 if (level < 0) {
404 level = ~level;
405 }
406
407 switch (level) {
408 case LOG_EMERG :
409 case LOG_ALERT :
410 case LOG_CRIT :
411 return OS_LOG_TYPE_ERROR;
412
413 case LOG_ERR :
414 case LOG_WARNING :
415 case LOG_NOTICE :
416 return OS_LOG_TYPE_DEFAULT;
417
418 case LOG_INFO :
419 return OS_LOG_TYPE_INFO;
420
421 case LOG_DEBUG :
422 return OS_LOG_TYPE_DEBUG;
423 }
424
425 return OS_LOG_TYPE_DEFAULT;
426 };
427
428 static void
429 __SCLog(void *ret_addr, os_log_type_t type, const char *formatString, va_list formatArguments)
430 {
431 os_log_with_args(_SC_LOG_DEFAULT(),
432 type,
433 formatString,
434 formatArguments,
435 ret_addr);
436 return;
437 }
438
439
440 static void
441 __SCPrint(FILE *stream, CFStringRef formatString, va_list formatArguments, Boolean addTime, Boolean addNL)
442 {
443 char *line;
444 CFStringRef str;
445 CFIndex usedBufLen;
446
447 #ifdef ENABLE_SC_FORMATTING
448 str = _CFStringCreateWithFormatAndArgumentsAux(NULL,
449 _SCCopyDescription,
450 NULL,
451 formatString,
452 formatArguments);
453 #else /* ENABLE_SC_FORMATTING */
454 str = CFStringCreateWithFormatAndArguments (NULL,
455 NULL,
456 formatString,
457 formatArguments);
458 #endif /* !ENABLE_SC_FORMATTING */
459
460 line =_SC_cfstring_to_cstring_ext(str,
461 NULL,
462 0,
463 kCFStringEncodingUTF8,
464 (UInt8)'?',
465 &usedBufLen);
466 CFRelease(str);
467 if (!line) {
468 return;
469 }
470
471 pthread_mutex_lock(&lock);
472 if (addTime) {
473 struct tm tm_now;
474 struct timeval tv_now;
475
476 (void)gettimeofday(&tv_now, NULL);
477 (void)localtime_r(&tv_now.tv_sec, &tm_now);
478 (void)fprintf(stream, "%2d:%02d:%02d.%03d ",
479 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000);
480 }
481 (void)fwrite((const void *)line, usedBufLen, 1, stream);
482 if (addNL) {
483 (void)fputc('\n', stream);
484 }
485 fflush (stream);
486 pthread_mutex_unlock(&lock);
487 CFAllocatorDeallocate(NULL, line);
488
489 return;
490 }
491
492
493 /*
494 * NOTE: We need to keep this function in place (for a least a while) to ensure
495 * that any [old] code that was using an earlier version of SC_log() will
496 * have the needed support code to perform the actual logging. Newly
497 * compiled code uses the new/replacement _SC_log_send() function.
498 */
499 void
500 __SC_Log(int level, CFStringRef format_CF, os_log_t log, os_log_type_t type, const char *format, ...)
501 {
502 #pragma unused(level)
503 Boolean do_log = FALSE;
504 Boolean do_print = FALSE;
505 va_list args_log;
506 va_list args_print;
507
508 if (_sc_log > kSCLogDestinationFile) {
509 do_log = TRUE; // log requested
510 va_start(args_log, format);
511
512 if (_sc_log >= kSCLogDestinationBoth) {
513 do_print = TRUE; // log AND print requested
514 va_copy(args_print, args_log);
515 }
516 } else {
517 do_print = TRUE; // print requested
518 va_start(args_print, format);
519 }
520
521 if (do_log) {
522 os_log_with_args(log,
523 type,
524 format,
525 args_log,
526 __builtin_return_address(0));
527 va_end(args_log);
528 }
529
530 if (do_print) {
531 __SCPrint(stdout,
532 format_CF,
533 args_print,
534 (_sc_log == kSCLogDestinationBoth), // trace
535 TRUE); // add newline
536 va_end(args_print);
537 }
538
539 return;
540 }
541
542
543 Boolean
544 __SC_log_enabled(int level, os_log_t log, os_log_type_t type)
545 {
546 if (os_log_type_enabled(log, type)) {
547 return TRUE;
548 }
549
550 if (_sc_log != kSCLogDestinationDefault) {
551 // if os_log'ing not enabled and the messages is targeted to stdout/stderr
552 if (level < LOG_INFO) {
553 // if not LOG_INFO/LOG_DEBUG message, print
554 return TRUE;
555 } else if ((level == LOG_INFO) && _sc_verbose) {
556 // if LOG_INFO and _sc_verbose, print
557 return TRUE;
558 } else if (_sc_debug) {
559 // if _sc_debug, print
560 return TRUE;
561 }
562 }
563
564 if (_SC_isInstallEnvironment()) {
565 // if OSInstaller environment
566 if (level < LOG_INFO) {
567 // if not LOG_INFO/LOG_DEBUG message, syslog
568 return TRUE;
569 } else if ((level == LOG_INFO) && _SC_isAppleInternal()) {
570 // if LOG_INFO and internal, syslog
571 return TRUE;
572 } else if (_sc_debug) {
573 // if _sc_debug, syslog
574 return TRUE;
575 }
576 }
577
578 return FALSE;
579 }
580
581
582 void
583 __SC_log_send(int level, os_log_t log, os_log_type_t type, os_log_pack_t pack)
584 {
585 Boolean addTime = (_sc_log == kSCLogDestinationBoth);
586 char buffer[256];
587 const char *buffer_ptr = buffer;
588 char *composed = NULL;
589 Boolean do_print = FALSE;
590 Boolean do_syslog = FALSE;
591
592 if (_sc_log > kSCLogDestinationFile) {
593 if (_SC_isInstallEnvironment()) {
594 /*
595 * os_log(3) messages are not persisted in the
596 * install environment. So, we use syslog(3)
597 * instead.
598 */
599 do_syslog = TRUE;
600 }
601
602 if (_sc_log >= kSCLogDestinationBoth) {
603 do_print = TRUE; // log AND print requested
604 }
605 } else {
606 do_print = TRUE; // print requested
607 }
608
609 if (!do_print && !do_syslog) {
610 // if only os_log requested
611 os_log_pack_send(pack, log, type);
612 } else if (do_print && !do_syslog) {
613 // if os_log and print requested
614 composed = os_log_pack_send_and_compose(pack, log, type, buffer, sizeof(buffer));
615 } else {
616 // if print-only and/or syslog requested
617 mach_get_times(NULL, &pack->olp_continuous_time, &pack->olp_wall_time);
618 composed = os_log_pack_compose(pack, log, type, buffer, sizeof(buffer));
619 }
620
621 if (do_print &&
622 (
623 (level < LOG_INFO) || // print most messages
624 ((level == LOG_INFO) && _sc_verbose) || // with _sc_verbose, include LOG_INFO
625 _sc_debug // with _sc_debug, include LOG_DEBUG
626 )
627 ) {
628 // if printing
629 pthread_mutex_lock(&lock);
630 if (addTime) {
631 struct tm tm_now;
632 struct timeval tv_now;
633
634 tv_now.tv_sec = (time_t)&pack->olp_wall_time.tv_sec;
635 tv_now.tv_usec = (suseconds_t)((uint64_t)&pack->olp_wall_time.tv_nsec / NSEC_PER_USEC);
636 (void)localtime_r(&tv_now.tv_sec, &tm_now);
637 (void)fprintf(stdout, "%2d:%02d:%02d.%03d ",
638 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000);
639 }
640 (void)fprintf(stdout, "%s\n", composed);
641 fflush (stdout);
642 pthread_mutex_unlock(&lock);
643 }
644
645 if (do_syslog &&
646 (
647 (level < LOG_INFO) ||
648 ((level == LOG_INFO) && _SC_isAppleInternal()) ||
649 _sc_debug
650 )
651 ) {
652 // if [install/upgrade] syslog'ing
653 syslog(level | LOG_INSTALL, "%s", composed);
654 }
655
656 if (composed != buffer_ptr) {
657 free(composed);
658 }
659
660 return;
661 }
662
663
664 void
665 SCLog(Boolean condition, int level, CFStringRef formatString, ...)
666 {
667 va_list formatArguments;
668 va_list formatArguments_print;
669 Boolean log = FALSE;
670 Boolean print = FALSE;
671
672 if (!condition) {
673 return;
674 }
675
676 /*
677 * Note: The following are the expected values for _sc_log
678 *
679 * 0 if SC messages should be written to stdout/stderr
680 * 1 if SC messages should be logged w/os_log(3)
681 * 2 if SC messages should be written to stdout/stderr AND logged
682 * 3 if SC messages should be logged AND written to stdout/stderr (w/o timestamp)
683 */
684
685 if (_sc_log > kSCLogDestinationFile) {
686 log = TRUE; // log requested
687 va_start(formatArguments, formatString);
688
689 if (_sc_log >= kSCLogDestinationBoth) {
690 print = TRUE; // log AND print requested
691 va_copy(formatArguments_print, formatArguments);
692 }
693 } else {
694 print = TRUE; // print requested
695 va_start(formatArguments_print, formatString);
696 }
697
698 if (log) {
699 const char *__format;
700
701 __format = CFStringGetCStringPtr(formatString, kCFStringEncodingUTF8);
702 if (__format != NULL) {
703 os_log_type_t __type;
704
705 __type = _SC_syslog_os_log_mapping(level);
706 __SCLog(__builtin_return_address(0), __type, __format, formatArguments);
707 }
708 va_end(formatArguments);
709 }
710
711 if (print) {
712 __SCPrint((LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout,
713 formatString,
714 formatArguments_print,
715 (_sc_log == kSCLogDestinationBoth), // trace
716 TRUE); // add newline
717 va_end(formatArguments_print);
718 }
719
720 return;
721 }
722
723
724 void
725 SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...)
726 {
727 va_list formatArguments;
728
729 if (!condition) {
730 return;
731 }
732
733 va_start(formatArguments, formatString);
734 __SCPrint(stream, formatString, formatArguments, FALSE, FALSE);
735 va_end(formatArguments);
736
737 return;
738 }
739
740
741 #pragma mark -
742 #pragma mark SC error handling / logging
743
744
745 const CFStringRef kCFErrorDomainSystemConfiguration = CFSTR("com.apple.SystemConfiguration");
746
747
748 static const struct sc_errmsg {
749 int status;
750 char *message;
751 } sc_errmsgs[] = {
752 { kSCStatusAccessError, "Permission denied" },
753 { kSCStatusConnectionIgnore, "Network connection information not available at this time" },
754 { kSCStatusConnectionNoService, "Network service for connection not available" },
755 { kSCStatusFailed, "Failed!" },
756 { kSCStatusInvalidArgument, "Invalid argument" },
757 { kSCStatusKeyExists, "Key already defined" },
758 { kSCStatusLocked, "Lock already held" },
759 { kSCStatusMaxLink, "Maximum link count exceeded" },
760 { kSCStatusNeedLock, "Lock required for this operation" },
761 { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" },
762 { kSCStatusNoStoreSession, "Configuration daemon session not active" },
763 { kSCStatusNoConfigFile, "Configuration file not found" },
764 { kSCStatusNoKey, "No such key" },
765 { kSCStatusNoLink, "No such link" },
766 { kSCStatusNoPrefsSession, "Preference session not active" },
767 { kSCStatusNotifierActive, "Notifier is currently active" },
768 { kSCStatusOK, "Success!" },
769 { kSCStatusPrefsBusy, "Preferences update currently in progress" },
770 { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" },
771 { kSCStatusStale, "Write attempted on stale version of object" },
772 };
773 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
774
775 void
776 _SCErrorSet(int error)
777 {
778 __SCThreadSpecificDataRef tsd;
779
780 tsd = __SCGetThreadSpecificData();
781 tsd->_sc_error = error;
782 return;
783 }
784
785
786 CFErrorRef
787 SCCopyLastError(void)
788 {
789 CFStringRef domain;
790 CFErrorRef error;
791 int i;
792 int code;
793 __SCThreadSpecificDataRef tsd;
794 CFMutableDictionaryRef userInfo = NULL;
795
796 tsd = __SCGetThreadSpecificData();
797 code =tsd->_sc_error;
798
799 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
800 if (sc_errmsgs[i].status == code) {
801 CFStringRef str;
802
803 domain = kCFErrorDomainSystemConfiguration;
804 userInfo = CFDictionaryCreateMutable(NULL,
805 0,
806 &kCFCopyStringDictionaryKeyCallBacks,
807 &kCFTypeDictionaryValueCallBacks);
808 str = CFStringCreateWithCString(NULL,
809 sc_errmsgs[i].message,
810 kCFStringEncodingASCII);
811 CFDictionarySetValue(userInfo, kCFErrorDescriptionKey, str);
812 CFRelease(str);
813 goto done;
814 }
815 }
816
817 if ((code > 0) && (code <= ELAST)) {
818 domain = kCFErrorDomainPOSIX;
819 goto done;
820 }
821
822 domain = kCFErrorDomainMach;
823
824 done :
825
826 error = CFErrorCreate(NULL, domain, code, userInfo);
827 if (userInfo != NULL) CFRelease(userInfo);
828 return error;
829 }
830
831
832 int
833 SCError(void)
834 {
835 __SCThreadSpecificDataRef tsd;
836
837 tsd = __SCGetThreadSpecificData();
838 return tsd->_sc_error;
839 }
840
841
842 const char *
843 SCErrorString(int status)
844 {
845 int i;
846
847 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
848 if (sc_errmsgs[i].status == status) {
849 return sc_errmsgs[i].message;
850 }
851 }
852
853 if ((status > 0) && (status <= ELAST)) {
854 return strerror(status);
855 }
856
857 if ((status >= BOOTSTRAP_SUCCESS) && (status <= BOOTSTRAP_NO_MEMORY)) {
858 return bootstrap_strerror(status);
859 }
860
861 return mach_error_string(status);
862 }