2 * Copyright (c) 2000-2008, 2010-2019 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
= TRUE
; /* 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 written to stdout/stderr AND logged */
57 #pragma mark Thread specific data
60 static pthread_once_t tsKeyInitialized
= PTHREAD_ONCE_INIT
;
61 static pthread_key_t tsDataKey
;
65 __SCThreadSpecificDataFinalize(void *arg
)
67 __SCThreadSpecificDataRef tsd
= (__SCThreadSpecificDataRef
)arg
;
70 if (tsd
->_sc_store
!= NULL
) CFRelease(tsd
->_sc_store
);
71 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
78 __SCThreadSpecificKeyInitialize()
80 pthread_key_create(&tsDataKey
, __SCThreadSpecificDataFinalize
);
86 __SCThreadSpecificDataRef
87 __SCGetThreadSpecificData()
89 __SCThreadSpecificDataRef tsd
;
90 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
92 tsd
= pthread_getspecific(tsDataKey
);
94 tsd
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__SCThreadSpecificData
), 0);
95 tsd
->_sc_error
= kSCStatusOK
;
96 tsd
->_sc_store
= NULL
;
97 pthread_setspecific(tsDataKey
, tsd
);
108 #define ENABLE_SC_FORMATTING
109 #ifdef ENABLE_SC_FORMATTING
110 // from <CoreFoundation/ForFoundationOnly.h>
111 extern CFStringRef
_CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc
, CFStringRef (*copyDescFunc
)(CFTypeRef
, CFDictionaryRef
), CFDictionaryRef formatOptions
, CFStringRef format
, va_list arguments
);
112 #endif /* ENABLE_SC_FORMATTING */
116 _SCCopyDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
118 #ifdef ENABLE_SC_FORMATTING
119 CFMutableDictionaryRef nFormatOptions
;
122 CFTypeID type
= CFGetTypeID(cf
);
124 if (!formatOptions
||
125 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX1"), (const void **)&prefix1
)) {
129 if (type
== CFStringGetTypeID()) {
130 return CFStringCreateWithFormat(NULL
,
137 if (type
== CFBooleanGetTypeID()) {
138 return CFStringCreateWithFormat(NULL
,
142 CFBooleanGetValue(cf
) ? "TRUE" : "FALSE");
145 if (type
== CFDataGetTypeID()) {
149 CFMutableStringRef str
;
151 str
= CFStringCreateMutable(NULL
, 0);
152 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<data> 0x"), prefix1
);
154 data
= CFDataGetBytePtr(cf
);
155 dataLen
= CFDataGetLength(cf
);
156 for (i
= 0; i
< dataLen
; i
++) {
157 CFStringAppendFormat(str
, NULL
, CFSTR("%02x"), data
[i
]);
163 if (type
== CFNumberGetTypeID()) {
164 return CFStringCreateWithFormat(NULL
,
171 if (type
== CFDateGetTypeID()) {
172 CFCalendarRef calendar
;
175 int MM
, DD
, YYYY
, hh
, mm
, ss
;
177 calendar
= CFCalendarCreateWithIdentifier(NULL
, kCFGregorianCalendar
);
178 tz
= CFTimeZoneCopySystem();
179 CFCalendarSetTimeZone(calendar
, tz
);
181 CFCalendarDecomposeAbsoluteTime(calendar
,
182 CFDateGetAbsoluteTime(cf
),
184 &MM
, &DD
, &YYYY
, &hh
, &mm
, &ss
);
187 str
= CFStringCreateWithFormat(NULL
,
189 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"),
191 MM
, DD
, YYYY
, hh
, mm
, ss
);
195 if ((formatOptions
== NULL
) ||
196 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX2"), (const void **)&prefix2
)) {
200 if (formatOptions
!= NULL
) {
201 nFormatOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, formatOptions
);
203 nFormatOptions
= CFDictionaryCreateMutable(NULL
,
205 &kCFTypeDictionaryKeyCallBacks
,
206 &kCFTypeDictionaryValueCallBacks
);
208 assert(nFormatOptions
!= NULL
);
212 if (type
== CFArrayGetTypeID()) {
213 const void * elements_q
[N_QUICK
];
214 const void ** elements
= elements_q
;
217 CFMutableStringRef str
;
219 str
= CFStringCreateMutable(NULL
, 0);
220 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<array> {"), prefix1
);
222 nElements
= CFArrayGetCount(cf
);
224 if (nElements
> (CFIndex
)(sizeof(elements_q
)/sizeof(CFTypeRef
)))
225 elements
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
226 CFArrayGetValues(cf
, CFRangeMake(0, nElements
), elements
);
227 for (i
= 0; i
< nElements
; i
++) {
228 CFMutableStringRef nPrefix1
;
229 CFMutableStringRef nPrefix2
;
233 nStr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%ld"), i
);
235 nPrefix1
= CFStringCreateMutable(NULL
, 0);
236 CFStringAppendFormat(nPrefix1
,
241 nPrefix2
= CFStringCreateMutable(NULL
, 0);
242 CFStringAppendFormat(nPrefix2
,
247 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
248 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
253 vStr
= _SCCopyDescription((CFTypeRef
)elements
[i
], nFormatOptions
);
254 CFStringAppendFormat(str
,
260 if (elements
!= elements_q
) CFAllocatorDeallocate(NULL
, elements
);
262 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
264 CFRelease(nFormatOptions
);
268 if (type
== CFDictionaryGetTypeID()) {
269 const void * keys_q
[N_QUICK
];
270 const void ** keys
= keys_q
;
273 CFMutableStringRef nPrefix1
;
274 CFMutableStringRef nPrefix2
;
275 CFMutableStringRef str
;
277 str
= CFStringCreateMutable(NULL
, 0);
278 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
280 nElements
= CFDictionaryGetCount(cf
);
282 CFComparatorFunction compFunc
= NULL
;
283 CFMutableArrayRef sortedKeys
;
285 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
286 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
288 CFDictionaryGetKeysAndValues(cf
, keys
, NULL
);
290 sortedKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
291 for (i
= 0; i
< nElements
; i
++) {
292 CFArrayAppendValue(sortedKeys
, (CFStringRef
)keys
[i
]);
295 if (isA_CFString(keys
[0])) {
296 compFunc
= (CFComparatorFunction
)CFStringCompare
;
298 else if (isA_CFNumber(keys
[0])) {
299 compFunc
= (CFComparatorFunction
)CFNumberCompare
;
301 else if (isA_CFDate(keys
[0])) {
302 compFunc
= (CFComparatorFunction
)CFDateCompare
;
305 if (compFunc
!= NULL
) {
306 CFArraySortValues(sortedKeys
,
307 CFRangeMake(0, nElements
),
312 for (i
= 0; i
< nElements
; i
++) {
318 key
= CFArrayGetValueAtIndex(sortedKeys
, i
);
319 kStr
= _SCCopyDescription((CFTypeRef
)key
, NULL
);
321 nPrefix1
= CFStringCreateMutable(NULL
, 0);
322 CFStringAppendFormat(nPrefix1
,
327 nPrefix2
= CFStringCreateMutable(NULL
, 0);
328 CFStringAppendFormat(nPrefix2
,
333 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
334 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
339 val
= CFDictionaryGetValue(cf
, key
);
340 vStr
= _SCCopyDescription((CFTypeRef
)val
, nFormatOptions
);
341 CFStringAppendFormat(str
,
348 CFRelease(sortedKeys
);
350 if (keys
!= keys_q
) {
351 CFAllocatorDeallocate(NULL
, keys
);
354 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
356 CFRelease(nFormatOptions
);
360 CFRelease(nFormatOptions
);
361 #endif /* ENABLE_SC_FORMATTING */
363 return CFStringCreateWithFormat(NULL
,
371 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
374 _SC_isInstallEnvironment() {
375 static dispatch_once_t once
;
376 static Boolean is_install
;
378 dispatch_once(&once
, ^{
379 is_install
= (getenv(INSTALL_ENVIRONMENT
) != NULL
);
387 _SC_LOG_DEFAULT(void)
389 static os_log_t log
= NULL
;
392 log
= os_log_create("com.apple.SystemConfiguration", "");
400 _SC_syslog_os_log_mapping(int level
)
410 return OS_LOG_TYPE_ERROR
;
415 return OS_LOG_TYPE_DEFAULT
;
418 return OS_LOG_TYPE_INFO
;
421 return OS_LOG_TYPE_DEBUG
;
424 return OS_LOG_TYPE_DEFAULT
;
428 __SCLog(void *ret_addr
, os_log_type_t type
, const char *formatString
, va_list formatArguments
)
430 os_log_with_args(_SC_LOG_DEFAULT(),
440 __SCPrint(FILE *stream
, CFStringRef formatString
, va_list formatArguments
, Boolean trace
, Boolean addNL
)
446 #ifdef ENABLE_SC_FORMATTING
447 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
452 #else /* ENABLE_SC_FORMATTING */
453 str
= CFStringCreateWithFormatAndArguments (NULL
,
457 #endif /* !ENABLE_SC_FORMATTING */
459 line
=_SC_cfstring_to_cstring_ext(str
,
462 kCFStringEncodingUTF8
,
470 pthread_mutex_lock(&lock
);
473 struct timeval tv_now
;
475 (void)gettimeofday(&tv_now
, NULL
);
476 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
477 (void)fprintf(stream
, "%2d:%02d:%02d.%03d ",
478 tm_now
.tm_hour
, tm_now
.tm_min
, tm_now
.tm_sec
, tv_now
.tv_usec
/ 1000);
480 (void)fwrite((const void *)line
, usedBufLen
, 1, stream
);
482 (void)fputc('\n', stream
);
485 pthread_mutex_unlock(&lock
);
486 CFAllocatorDeallocate(NULL
, line
);
493 __SC_Log(int level
, CFStringRef format_CF
, os_log_t log
, os_log_type_t type
, const char *format
, ...)
495 #pragma unused(level)
496 Boolean do_log
= FALSE
;
497 Boolean do_print
= FALSE
;
502 * Note: The following are the expected values for _sc_log
504 * 0 if SC messages should be written to stdout/stderr
505 * 1 if SC messages should be logged w/os_log(3)
506 * 2 if SC messages should be written to stdout/stderr AND logged
510 do_log
= TRUE
; // log requested
511 va_start(args_log
, format
);
514 do_print
= TRUE
; // log AND print requested
515 va_copy(args_print
, args_log
);
518 do_print
= TRUE
; // print requested
519 va_start(args_print
, format
);
523 os_log_with_args(log
,
527 __builtin_return_address(0));
535 (_sc_log
> 0), // trace
536 TRUE
); // add newline
545 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
547 va_list formatArguments
;
548 va_list formatArguments_print
;
550 Boolean print
= FALSE
;
557 * Note: The following are the expected values for _sc_log
559 * 0 if SC messages should be written to stdout/stderr
560 * 1 if SC messages should be logged w/os_log(3)
561 * 2 if SC messages should be written to stdout/stderr AND logged
565 log
= TRUE
; // log requested
566 va_start(formatArguments
, formatString
);
569 print
= TRUE
; // log AND print requested
570 va_copy(formatArguments_print
, formatArguments
);
573 print
= TRUE
; // print requested
574 va_start(formatArguments_print
, formatString
);
578 const char *__format
;
580 __format
= CFStringGetCStringPtr(formatString
, kCFStringEncodingUTF8
);
581 if (__format
!= NULL
) {
582 os_log_type_t __type
;
584 __type
= _SC_syslog_os_log_mapping(level
);
585 __SCLog(__builtin_return_address(0), __type
, __format
, formatArguments
);
587 va_end(formatArguments
);
591 __SCPrint((LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
,
593 formatArguments_print
,
594 (_sc_log
> 0), // trace
595 TRUE
); // add newline
596 va_end(formatArguments_print
);
604 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
606 va_list formatArguments
;
612 va_start(formatArguments
, formatString
);
613 __SCPrint(stream
, formatString
, formatArguments
, FALSE
, FALSE
);
614 va_end(formatArguments
);
621 #pragma mark SC error handling / logging
624 const CFStringRef kCFErrorDomainSystemConfiguration
= CFSTR("com.apple.SystemConfiguration");
627 static const struct sc_errmsg
{
631 { kSCStatusAccessError
, "Permission denied" },
632 { kSCStatusConnectionIgnore
, "Network connection information not available at this time" },
633 { kSCStatusConnectionNoService
, "Network service for connection not available" },
634 { kSCStatusFailed
, "Failed!" },
635 { kSCStatusInvalidArgument
, "Invalid argument" },
636 { kSCStatusKeyExists
, "Key already defined" },
637 { kSCStatusLocked
, "Lock already held" },
638 { kSCStatusMaxLink
, "Maximum link count exceeded" },
639 { kSCStatusNeedLock
, "Lock required for this operation" },
640 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
641 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
642 { kSCStatusNoConfigFile
, "Configuration file not found" },
643 { kSCStatusNoKey
, "No such key" },
644 { kSCStatusNoLink
, "No such link" },
645 { kSCStatusNoPrefsSession
, "Preference session not active" },
646 { kSCStatusNotifierActive
, "Notifier is currently active" },
647 { kSCStatusOK
, "Success!" },
648 { kSCStatusPrefsBusy
, "Preferences update currently in progress" },
649 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
650 { kSCStatusStale
, "Write attempted on stale version of object" },
652 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
655 _SCErrorSet(int error
)
657 __SCThreadSpecificDataRef tsd
;
659 tsd
= __SCGetThreadSpecificData();
660 tsd
->_sc_error
= error
;
666 SCCopyLastError(void)
672 __SCThreadSpecificDataRef tsd
;
673 CFMutableDictionaryRef userInfo
= NULL
;
675 tsd
= __SCGetThreadSpecificData();
676 code
=tsd
->_sc_error
;
678 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
679 if (sc_errmsgs
[i
].status
== code
) {
682 domain
= kCFErrorDomainSystemConfiguration
;
683 userInfo
= CFDictionaryCreateMutable(NULL
,
685 &kCFCopyStringDictionaryKeyCallBacks
,
686 &kCFTypeDictionaryValueCallBacks
);
687 str
= CFStringCreateWithCString(NULL
,
688 sc_errmsgs
[i
].message
,
689 kCFStringEncodingASCII
);
690 CFDictionarySetValue(userInfo
, kCFErrorDescriptionKey
, str
);
696 if ((code
> 0) && (code
<= ELAST
)) {
697 domain
= kCFErrorDomainPOSIX
;
701 domain
= kCFErrorDomainMach
;
705 error
= CFErrorCreate(NULL
, domain
, code
, userInfo
);
706 if (userInfo
!= NULL
) CFRelease(userInfo
);
714 __SCThreadSpecificDataRef tsd
;
716 tsd
= __SCGetThreadSpecificData();
717 return tsd
->_sc_error
;
722 SCErrorString(int status
)
726 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
727 if (sc_errmsgs
[i
].status
== status
) {
728 return sc_errmsgs
[i
].message
;
732 if ((status
> 0) && (status
<= ELAST
)) {
733 return strerror(status
);
736 if ((status
>= BOOTSTRAP_SUCCESS
) && (status
<= BOOTSTRAP_NO_MEMORY
)) {
737 return bootstrap_strerror(status
);
740 return mach_error_string(status
);