]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCD.c
configd-1109.60.2.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_log = FALSE;
590 Boolean do_print = FALSE;
591 Boolean do_syslog = FALSE;
592
593 if (_sc_log > kSCLogDestinationFile) {
594 do_log = TRUE;
595
596 if (_SC_isInstallEnvironment()) {
597 /*
598 * os_log(3) messages are not persisted in the
599 * install environment. But, the installer does
600 * capture syslog(3) messages.
601 */
602 do_syslog = TRUE;
603 }
604
605 if (_sc_log >= kSCLogDestinationBoth) {
606 do_print = TRUE; // log AND print requested
607 }
608 } else {
609 do_print = TRUE; // print requested
610 }
611
612 if (do_log) {
613 if (!do_print && !do_syslog) {
614 // if only os_log requested
615 os_log_pack_send(pack, log, type);
616 } else {
617 // if os_log and print (or syslog) requested
618 composed = os_log_pack_send_and_compose(pack, log, type, buffer, sizeof(buffer));
619 }
620 } else {
621 // if print-only requested
622 mach_get_times(NULL, &pack->olp_continuous_time, &pack->olp_wall_time);
623 composed = os_log_pack_compose(pack, log, type, buffer, sizeof(buffer));
624 }
625
626 if (do_print &&
627 (
628 (level < LOG_INFO) || // print most messages
629 ((level == LOG_INFO) && _sc_verbose) || // with _sc_verbose, include LOG_INFO
630 _sc_debug // with _sc_debug, include LOG_DEBUG
631 )
632 ) {
633 // if printing
634 pthread_mutex_lock(&lock);
635 if (addTime) {
636 struct tm tm_now;
637 struct timeval tv_now;
638
639 tv_now.tv_sec = (time_t)&pack->olp_wall_time.tv_sec;
640 tv_now.tv_usec = (suseconds_t)((uint64_t)&pack->olp_wall_time.tv_nsec / NSEC_PER_USEC);
641 (void)localtime_r(&tv_now.tv_sec, &tm_now);
642 (void)fprintf(stdout, "%2d:%02d:%02d.%03d ",
643 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000);
644 }
645 (void)fprintf(stdout, "%s\n", composed);
646 fflush (stdout);
647 pthread_mutex_unlock(&lock);
648 }
649
650 if (do_syslog &&
651 (
652 (level < LOG_INFO) ||
653 ((level == LOG_INFO) && _SC_isAppleInternal()) ||
654 _sc_debug
655 )
656 ) {
657 // if [install/upgrade] syslog'ing
658 syslog(level | LOG_INSTALL, "%s", composed);
659 }
660
661 if (composed != buffer_ptr) {
662 free(composed);
663 }
664
665 return;
666 }
667
668
669 void
670 SCLog(Boolean condition, int level, CFStringRef formatString, ...)
671 {
672 va_list formatArguments;
673 va_list formatArguments_print;
674 Boolean log = FALSE;
675 Boolean print = FALSE;
676
677 if (!condition) {
678 return;
679 }
680
681 /*
682 * Note: The following are the expected values for _sc_log
683 *
684 * 0 if SC messages should be written to stdout/stderr
685 * 1 if SC messages should be logged w/os_log(3)
686 * 2 if SC messages should be written to stdout/stderr AND logged
687 * 3 if SC messages should be logged AND written to stdout/stderr (w/o timestamp)
688 */
689
690 if (_sc_log > kSCLogDestinationFile) {
691 log = TRUE; // log requested
692 va_start(formatArguments, formatString);
693
694 if (_sc_log >= kSCLogDestinationBoth) {
695 print = TRUE; // log AND print requested
696 va_copy(formatArguments_print, formatArguments);
697 }
698 } else {
699 print = TRUE; // print requested
700 va_start(formatArguments_print, formatString);
701 }
702
703 if (log) {
704 const char *__format;
705
706 __format = CFStringGetCStringPtr(formatString, kCFStringEncodingUTF8);
707 if (__format != NULL) {
708 os_log_type_t __type;
709
710 __type = _SC_syslog_os_log_mapping(level);
711 __SCLog(__builtin_return_address(0), __type, __format, formatArguments);
712 }
713 va_end(formatArguments);
714 }
715
716 if (print) {
717 __SCPrint((LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout,
718 formatString,
719 formatArguments_print,
720 (_sc_log == kSCLogDestinationBoth), // trace
721 TRUE); // add newline
722 va_end(formatArguments_print);
723 }
724
725 return;
726 }
727
728
729 void
730 SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...)
731 {
732 va_list formatArguments;
733
734 if (!condition) {
735 return;
736 }
737
738 va_start(formatArguments, formatString);
739 __SCPrint(stream, formatString, formatArguments, FALSE, FALSE);
740 va_end(formatArguments);
741
742 return;
743 }
744
745
746 #pragma mark -
747 #pragma mark SC error handling / logging
748
749
750 const CFStringRef kCFErrorDomainSystemConfiguration = CFSTR("com.apple.SystemConfiguration");
751
752
753 static const struct sc_errmsg {
754 int status;
755 char *message;
756 } sc_errmsgs[] = {
757 { kSCStatusAccessError, "Permission denied" },
758 { kSCStatusConnectionIgnore, "Network connection information not available at this time" },
759 { kSCStatusConnectionNoService, "Network service for connection not available" },
760 { kSCStatusFailed, "Failed!" },
761 { kSCStatusInvalidArgument, "Invalid argument" },
762 { kSCStatusKeyExists, "Key already defined" },
763 { kSCStatusLocked, "Lock already held" },
764 { kSCStatusMaxLink, "Maximum link count exceeded" },
765 { kSCStatusNeedLock, "Lock required for this operation" },
766 { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" },
767 { kSCStatusNoStoreSession, "Configuration daemon session not active" },
768 { kSCStatusNoConfigFile, "Configuration file not found" },
769 { kSCStatusNoKey, "No such key" },
770 { kSCStatusNoLink, "No such link" },
771 { kSCStatusNoPrefsSession, "Preference session not active" },
772 { kSCStatusNotifierActive, "Notifier is currently active" },
773 { kSCStatusOK, "Success!" },
774 { kSCStatusPrefsBusy, "Preferences update currently in progress" },
775 { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" },
776 { kSCStatusStale, "Write attempted on stale version of object" },
777 };
778 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
779
780 void
781 _SCErrorSet(int error)
782 {
783 __SCThreadSpecificDataRef tsd;
784
785 tsd = __SCGetThreadSpecificData();
786 tsd->_sc_error = error;
787 return;
788 }
789
790
791 CFErrorRef
792 SCCopyLastError(void)
793 {
794 CFStringRef domain;
795 CFErrorRef error;
796 int i;
797 int code;
798 __SCThreadSpecificDataRef tsd;
799 CFMutableDictionaryRef userInfo = NULL;
800
801 tsd = __SCGetThreadSpecificData();
802 code =tsd->_sc_error;
803
804 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
805 if (sc_errmsgs[i].status == code) {
806 CFStringRef str;
807
808 domain = kCFErrorDomainSystemConfiguration;
809 userInfo = CFDictionaryCreateMutable(NULL,
810 0,
811 &kCFCopyStringDictionaryKeyCallBacks,
812 &kCFTypeDictionaryValueCallBacks);
813 str = CFStringCreateWithCString(NULL,
814 sc_errmsgs[i].message,
815 kCFStringEncodingASCII);
816 CFDictionarySetValue(userInfo, kCFErrorDescriptionKey, str);
817 CFRelease(str);
818 goto done;
819 }
820 }
821
822 if ((code > 0) && (code <= ELAST)) {
823 domain = kCFErrorDomainPOSIX;
824 goto done;
825 }
826
827 domain = kCFErrorDomainMach;
828
829 done :
830
831 error = CFErrorCreate(NULL, domain, code, userInfo);
832 if (userInfo != NULL) CFRelease(userInfo);
833 return error;
834 }
835
836
837 int
838 SCError(void)
839 {
840 __SCThreadSpecificDataRef tsd;
841
842 tsd = __SCGetThreadSpecificData();
843 return tsd->_sc_error;
844 }
845
846
847 const char *
848 SCErrorString(int status)
849 {
850 int i;
851
852 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
853 if (sc_errmsgs[i].status == status) {
854 return sc_errmsgs[i].message;
855 }
856 }
857
858 if ((status > 0) && (status <= ELAST)) {
859 return strerror(status);
860 }
861
862 if ((status >= BOOTSTRAP_SUCCESS) && (status <= BOOTSTRAP_NO_MEMORY)) {
863 return bootstrap_strerror(status);
864 }
865
866 return mach_error_string(status);
867 }