2 * Copyright (c) 2000-2008, 2010-2020 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
34 #include <mach/mach.h>
35 #include <mach/mach_error.h>
36 #include <servers/bootstrap.h>
40 #include <os/log_private.h>
42 #include "SCDynamicStoreInternal.h"
44 #include "config.h" /* MiG generated file */
46 #define INSTALL_ENVIRONMENT "__OSINSTALL_ENVIRONMENT"
48 /* framework variables */
49 int _sc_debug
= FALSE
; /* non-zero if debugging enabled */
50 int _sc_verbose
= FALSE
; /* non-zero if verbose logging enabled */
51 int _sc_log
= 1; /* 0 if SC messages should be written to stdout/stderr,
52 1 if SC messages should be logged w/os_log(3),
53 2 if SC messages should be logged AND written to stdout/stderr
54 3 if SC messages should be logged AND written to stdout/stderr (w/o timestamp) */
58 #pragma mark Thread specific data
61 static pthread_once_t tsKeyInitialized
= PTHREAD_ONCE_INIT
;
62 static pthread_key_t tsDataKey
;
66 __SCThreadSpecificDataFinalize(void *arg
)
68 __SCThreadSpecificDataRef tsd
= (__SCThreadSpecificDataRef
)arg
;
71 if (tsd
->_sc_store
!= NULL
) CFRelease(tsd
->_sc_store
);
72 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
79 __SCThreadSpecificKeyInitialize()
81 pthread_key_create(&tsDataKey
, __SCThreadSpecificDataFinalize
);
87 __SCThreadSpecificDataRef
88 __SCGetThreadSpecificData()
90 __SCThreadSpecificDataRef tsd
;
91 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
93 tsd
= pthread_getspecific(tsDataKey
);
95 tsd
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__SCThreadSpecificData
), 0);
96 tsd
->_sc_error
= kSCStatusOK
;
97 tsd
->_sc_store
= NULL
;
98 pthread_setspecific(tsDataKey
, tsd
);
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 */
117 _SCCopyDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
119 #ifdef ENABLE_SC_FORMATTING
120 CFMutableDictionaryRef nFormatOptions
;
123 CFTypeID type
= CFGetTypeID(cf
);
125 if (!formatOptions
||
126 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX1"), (const void **)&prefix1
)) {
130 if (type
== CFStringGetTypeID()) {
131 return CFStringCreateWithFormat(NULL
,
138 if (type
== CFBooleanGetTypeID()) {
139 return CFStringCreateWithFormat(NULL
,
143 CFBooleanGetValue(cf
) ? "TRUE" : "FALSE");
146 if (type
== CFDataGetTypeID()) {
150 CFMutableStringRef str
;
152 str
= CFStringCreateMutable(NULL
, 0);
153 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<data> 0x"), prefix1
);
155 data
= CFDataGetBytePtr(cf
);
156 dataLen
= CFDataGetLength(cf
);
157 for (i
= 0; i
< dataLen
; i
++) {
158 CFStringAppendFormat(str
, NULL
, CFSTR("%02x"), data
[i
]);
164 if (type
== CFNumberGetTypeID()) {
165 return CFStringCreateWithFormat(NULL
,
172 if (type
== CFDateGetTypeID()) {
173 CFCalendarRef calendar
;
176 int MM
, DD
, YYYY
, hh
, mm
, ss
;
178 calendar
= CFCalendarCreateWithIdentifier(NULL
, kCFGregorianCalendar
);
179 tz
= CFTimeZoneCopySystem();
180 CFCalendarSetTimeZone(calendar
, tz
);
182 CFCalendarDecomposeAbsoluteTime(calendar
,
183 CFDateGetAbsoluteTime(cf
),
185 &MM
, &DD
, &YYYY
, &hh
, &mm
, &ss
);
188 str
= CFStringCreateWithFormat(NULL
,
190 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"),
192 MM
, DD
, YYYY
, hh
, mm
, ss
);
196 if ((formatOptions
== NULL
) ||
197 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX2"), (const void **)&prefix2
)) {
201 if (formatOptions
!= NULL
) {
202 nFormatOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, formatOptions
);
204 nFormatOptions
= CFDictionaryCreateMutable(NULL
,
206 &kCFTypeDictionaryKeyCallBacks
,
207 &kCFTypeDictionaryValueCallBacks
);
209 assert(nFormatOptions
!= NULL
);
213 if (type
== CFArrayGetTypeID()) {
214 const void * elements_q
[N_QUICK
];
215 const void ** elements
= elements_q
;
218 CFMutableStringRef str
;
220 str
= CFStringCreateMutable(NULL
, 0);
221 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<array> {"), prefix1
);
223 nElements
= CFArrayGetCount(cf
);
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
;
234 nStr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%ld"), i
);
236 nPrefix1
= CFStringCreateMutable(NULL
, 0);
237 CFStringAppendFormat(nPrefix1
,
242 nPrefix2
= CFStringCreateMutable(NULL
, 0);
243 CFStringAppendFormat(nPrefix2
,
248 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
249 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
254 vStr
= _SCCopyDescription((CFTypeRef
)elements
[i
], nFormatOptions
);
255 CFStringAppendFormat(str
,
261 if (elements
!= elements_q
) CFAllocatorDeallocate(NULL
, elements
);
263 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
265 CFRelease(nFormatOptions
);
269 if (type
== CFDictionaryGetTypeID()) {
270 const void * keys_q
[N_QUICK
];
271 const void ** keys
= keys_q
;
274 CFMutableStringRef nPrefix1
;
275 CFMutableStringRef nPrefix2
;
276 CFMutableStringRef str
;
278 str
= CFStringCreateMutable(NULL
, 0);
279 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
281 nElements
= CFDictionaryGetCount(cf
);
283 CFComparatorFunction compFunc
= NULL
;
284 CFMutableArrayRef sortedKeys
;
286 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
287 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
289 CFDictionaryGetKeysAndValues(cf
, keys
, NULL
);
291 sortedKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
292 for (i
= 0; i
< nElements
; i
++) {
293 CFArrayAppendValue(sortedKeys
, (CFStringRef
)keys
[i
]);
296 if (isA_CFString(keys
[0])) {
297 compFunc
= (CFComparatorFunction
)CFStringCompare
;
299 else if (isA_CFNumber(keys
[0])) {
300 compFunc
= (CFComparatorFunction
)CFNumberCompare
;
302 else if (isA_CFDate(keys
[0])) {
303 compFunc
= (CFComparatorFunction
)CFDateCompare
;
306 if (compFunc
!= NULL
) {
307 CFArraySortValues(sortedKeys
,
308 CFRangeMake(0, nElements
),
313 for (i
= 0; i
< nElements
; i
++) {
319 key
= CFArrayGetValueAtIndex(sortedKeys
, i
);
320 kStr
= _SCCopyDescription((CFTypeRef
)key
, NULL
);
322 nPrefix1
= CFStringCreateMutable(NULL
, 0);
323 CFStringAppendFormat(nPrefix1
,
328 nPrefix2
= CFStringCreateMutable(NULL
, 0);
329 CFStringAppendFormat(nPrefix2
,
334 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
335 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
340 val
= CFDictionaryGetValue(cf
, key
);
341 vStr
= _SCCopyDescription((CFTypeRef
)val
, nFormatOptions
);
342 CFStringAppendFormat(str
,
349 CFRelease(sortedKeys
);
351 if (keys
!= keys_q
) {
352 CFAllocatorDeallocate(NULL
, keys
);
355 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
357 CFRelease(nFormatOptions
);
361 CFRelease(nFormatOptions
);
362 #endif /* ENABLE_SC_FORMATTING */
364 return CFStringCreateWithFormat(NULL
,
372 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
375 _SC_isInstallEnvironment() {
376 static dispatch_once_t once
;
377 static Boolean is_install
;
379 dispatch_once(&once
, ^{
380 is_install
= (getenv(INSTALL_ENVIRONMENT
) != NULL
);
388 _SC_LOG_DEFAULT(void)
390 static os_log_t log
= NULL
;
393 log
= os_log_create("com.apple.SystemConfiguration", "");
401 _SC_syslog_os_log_mapping(int level
)
411 return OS_LOG_TYPE_ERROR
;
416 return OS_LOG_TYPE_DEFAULT
;
419 return OS_LOG_TYPE_INFO
;
422 return OS_LOG_TYPE_DEBUG
;
425 return OS_LOG_TYPE_DEFAULT
;
429 __SCLog(void *ret_addr
, os_log_type_t type
, const char *formatString
, va_list formatArguments
)
431 os_log_with_args(_SC_LOG_DEFAULT(),
441 __SCPrint(FILE *stream
, CFStringRef formatString
, va_list formatArguments
, Boolean trace
, Boolean addNL
)
447 #ifdef ENABLE_SC_FORMATTING
448 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
453 #else /* ENABLE_SC_FORMATTING */
454 str
= CFStringCreateWithFormatAndArguments (NULL
,
458 #endif /* !ENABLE_SC_FORMATTING */
460 line
=_SC_cfstring_to_cstring_ext(str
,
463 kCFStringEncodingUTF8
,
471 pthread_mutex_lock(&lock
);
474 struct timeval tv_now
;
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);
481 (void)fwrite((const void *)line
, usedBufLen
, 1, stream
);
483 (void)fputc('\n', stream
);
486 pthread_mutex_unlock(&lock
);
487 CFAllocatorDeallocate(NULL
, line
);
494 __SC_Log(int level
, CFStringRef format_CF
, os_log_t log
, os_log_type_t type
, const char *format
, ...)
496 #pragma unused(level)
497 Boolean do_log
= FALSE
;
498 Boolean do_print
= FALSE
;
503 * Note: The following are the expected values for _sc_log
505 * 0 if SC messages should be written to stdout/stderr
506 * 1 if SC messages should be logged w/os_log(3)
507 * 2 if SC messages should be written to stdout/stderr AND logged
508 * 3 if SC messages should be logged AND written to stdout/stderr (w/o timestamp)
512 do_log
= TRUE
; // log requested
513 va_start(args_log
, format
);
516 do_print
= TRUE
; // log AND print requested
517 va_copy(args_print
, args_log
);
520 do_print
= TRUE
; // print requested
521 va_start(args_print
, format
);
525 os_log_with_args(log
,
529 __builtin_return_address(0));
537 (_sc_log
== 2), // trace
538 TRUE
); // add newline
547 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
549 va_list formatArguments
;
550 va_list formatArguments_print
;
552 Boolean print
= FALSE
;
559 * Note: The following are the expected values for _sc_log
561 * 0 if SC messages should be written to stdout/stderr
562 * 1 if SC messages should be logged w/os_log(3)
563 * 2 if SC messages should be written to stdout/stderr AND logged
564 * 3 if SC messages should be logged AND written to stdout/stderr (w/o timestamp)
568 log
= TRUE
; // log requested
569 va_start(formatArguments
, formatString
);
572 print
= TRUE
; // log AND print requested
573 va_copy(formatArguments_print
, formatArguments
);
576 print
= TRUE
; // print requested
577 va_start(formatArguments_print
, formatString
);
581 const char *__format
;
583 __format
= CFStringGetCStringPtr(formatString
, kCFStringEncodingUTF8
);
584 if (__format
!= NULL
) {
585 os_log_type_t __type
;
587 __type
= _SC_syslog_os_log_mapping(level
);
588 __SCLog(__builtin_return_address(0), __type
, __format
, formatArguments
);
590 va_end(formatArguments
);
594 __SCPrint((LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
,
596 formatArguments_print
,
597 (_sc_log
== 2), // trace
598 TRUE
); // add newline
599 va_end(formatArguments_print
);
607 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
609 va_list formatArguments
;
615 va_start(formatArguments
, formatString
);
616 __SCPrint(stream
, formatString
, formatArguments
, FALSE
, FALSE
);
617 va_end(formatArguments
);
624 #pragma mark SC error handling / logging
627 const CFStringRef kCFErrorDomainSystemConfiguration
= CFSTR("com.apple.SystemConfiguration");
630 static const struct sc_errmsg
{
634 { kSCStatusAccessError
, "Permission denied" },
635 { kSCStatusConnectionIgnore
, "Network connection information not available at this time" },
636 { kSCStatusConnectionNoService
, "Network service for connection not available" },
637 { kSCStatusFailed
, "Failed!" },
638 { kSCStatusInvalidArgument
, "Invalid argument" },
639 { kSCStatusKeyExists
, "Key already defined" },
640 { kSCStatusLocked
, "Lock already held" },
641 { kSCStatusMaxLink
, "Maximum link count exceeded" },
642 { kSCStatusNeedLock
, "Lock required for this operation" },
643 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
644 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
645 { kSCStatusNoConfigFile
, "Configuration file not found" },
646 { kSCStatusNoKey
, "No such key" },
647 { kSCStatusNoLink
, "No such link" },
648 { kSCStatusNoPrefsSession
, "Preference session not active" },
649 { kSCStatusNotifierActive
, "Notifier is currently active" },
650 { kSCStatusOK
, "Success!" },
651 { kSCStatusPrefsBusy
, "Preferences update currently in progress" },
652 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
653 { kSCStatusStale
, "Write attempted on stale version of object" },
655 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
658 _SCErrorSet(int error
)
660 __SCThreadSpecificDataRef tsd
;
662 tsd
= __SCGetThreadSpecificData();
663 tsd
->_sc_error
= error
;
669 SCCopyLastError(void)
675 __SCThreadSpecificDataRef tsd
;
676 CFMutableDictionaryRef userInfo
= NULL
;
678 tsd
= __SCGetThreadSpecificData();
679 code
=tsd
->_sc_error
;
681 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
682 if (sc_errmsgs
[i
].status
== code
) {
685 domain
= kCFErrorDomainSystemConfiguration
;
686 userInfo
= CFDictionaryCreateMutable(NULL
,
688 &kCFCopyStringDictionaryKeyCallBacks
,
689 &kCFTypeDictionaryValueCallBacks
);
690 str
= CFStringCreateWithCString(NULL
,
691 sc_errmsgs
[i
].message
,
692 kCFStringEncodingASCII
);
693 CFDictionarySetValue(userInfo
, kCFErrorDescriptionKey
, str
);
699 if ((code
> 0) && (code
<= ELAST
)) {
700 domain
= kCFErrorDomainPOSIX
;
704 domain
= kCFErrorDomainMach
;
708 error
= CFErrorCreate(NULL
, domain
, code
, userInfo
);
709 if (userInfo
!= NULL
) CFRelease(userInfo
);
717 __SCThreadSpecificDataRef tsd
;
719 tsd
= __SCGetThreadSpecificData();
720 return tsd
->_sc_error
;
725 SCErrorString(int status
)
729 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
730 if (sc_errmsgs
[i
].status
== status
) {
731 return sc_errmsgs
[i
].message
;
735 if ((status
> 0) && (status
<= ELAST
)) {
736 return strerror(status
);
739 if ((status
>= BOOTSTRAP_SUCCESS
) && (status
<= BOOTSTRAP_NO_MEMORY
)) {
740 return bootstrap_strerror(status
);
743 return mach_error_string(status
);