2 * Copyright (c) 2000-2008, 2010-2017 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 kASLModule "ASLModule"
109 #define kASLOption "ASLOption"
110 #define kLoggerID "LoggerID"
112 #define ENABLE_SC_FORMATTING
113 #ifdef ENABLE_SC_FORMATTING
114 // from <CoreFoundation/ForFoundationOnly.h>
115 extern CFStringRef
_CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc
, CFStringRef (*copyDescFunc
)(CFTypeRef
, CFDictionaryRef
), CFDictionaryRef formatOptions
, CFStringRef format
, va_list arguments
);
116 #endif /* ENABLE_SC_FORMATTING */
120 _SCCopyDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
122 #ifdef ENABLE_SC_FORMATTING
123 CFMutableDictionaryRef nFormatOptions
;
126 CFTypeID type
= CFGetTypeID(cf
);
128 if (!formatOptions
||
129 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX1"), (const void **)&prefix1
)) {
133 if (type
== CFStringGetTypeID()) {
134 return CFStringCreateWithFormat(NULL
,
141 if (type
== CFBooleanGetTypeID()) {
142 return CFStringCreateWithFormat(NULL
,
146 CFBooleanGetValue(cf
) ? "TRUE" : "FALSE");
149 if (type
== CFDataGetTypeID()) {
153 CFMutableStringRef str
;
155 str
= CFStringCreateMutable(NULL
, 0);
156 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<data> 0x"), prefix1
);
158 data
= CFDataGetBytePtr(cf
);
159 dataLen
= CFDataGetLength(cf
);
160 for (i
= 0; i
< dataLen
; i
++) {
161 CFStringAppendFormat(str
, NULL
, CFSTR("%02x"), data
[i
]);
167 if (type
== CFNumberGetTypeID()) {
168 return CFStringCreateWithFormat(NULL
,
175 if (type
== CFDateGetTypeID()) {
176 CFCalendarRef calendar
;
179 int MM
, DD
, YYYY
, hh
, mm
, ss
;
181 calendar
= CFCalendarCreateWithIdentifier(NULL
, kCFGregorianCalendar
);
182 tz
= CFTimeZoneCopySystem();
183 CFCalendarSetTimeZone(calendar
, tz
);
185 CFCalendarDecomposeAbsoluteTime(calendar
,
186 CFDateGetAbsoluteTime(cf
),
188 &MM
, &DD
, &YYYY
, &hh
, &mm
, &ss
);
191 str
= CFStringCreateWithFormat(NULL
,
193 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"),
195 MM
, DD
, YYYY
, hh
, mm
, ss
);
199 if ((formatOptions
== NULL
) ||
200 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX2"), (const void **)&prefix2
)) {
204 if (formatOptions
!= NULL
) {
205 nFormatOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, formatOptions
);
207 nFormatOptions
= CFDictionaryCreateMutable(NULL
,
209 &kCFTypeDictionaryKeyCallBacks
,
210 &kCFTypeDictionaryValueCallBacks
);
212 assert(nFormatOptions
!= NULL
);
216 if (type
== CFArrayGetTypeID()) {
217 const void * elements_q
[N_QUICK
];
218 const void ** elements
= elements_q
;
221 CFMutableStringRef str
;
223 str
= CFStringCreateMutable(NULL
, 0);
224 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<array> {"), prefix1
);
226 nElements
= CFArrayGetCount(cf
);
228 if (nElements
> (CFIndex
)(sizeof(elements_q
)/sizeof(CFTypeRef
)))
229 elements
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
230 CFArrayGetValues(cf
, CFRangeMake(0, nElements
), elements
);
231 for (i
= 0; i
< nElements
; i
++) {
232 CFMutableStringRef nPrefix1
;
233 CFMutableStringRef nPrefix2
;
237 nStr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%ld"), i
);
239 nPrefix1
= CFStringCreateMutable(NULL
, 0);
240 CFStringAppendFormat(nPrefix1
,
245 nPrefix2
= CFStringCreateMutable(NULL
, 0);
246 CFStringAppendFormat(nPrefix2
,
251 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
252 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
257 vStr
= _SCCopyDescription((CFTypeRef
)elements
[i
], nFormatOptions
);
258 CFStringAppendFormat(str
,
264 if (elements
!= elements_q
) CFAllocatorDeallocate(NULL
, elements
);
266 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
268 CFRelease(nFormatOptions
);
272 if (type
== CFDictionaryGetTypeID()) {
273 const void * keys_q
[N_QUICK
];
274 const void ** keys
= keys_q
;
277 CFMutableStringRef nPrefix1
;
278 CFMutableStringRef nPrefix2
;
279 CFMutableStringRef str
;
281 str
= CFStringCreateMutable(NULL
, 0);
282 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
284 nElements
= CFDictionaryGetCount(cf
);
286 CFComparatorFunction compFunc
= NULL
;
287 CFMutableArrayRef sortedKeys
;
289 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
290 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
292 CFDictionaryGetKeysAndValues(cf
, keys
, NULL
);
294 sortedKeys
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
295 for (i
= 0; i
< nElements
; i
++) {
296 CFArrayAppendValue(sortedKeys
, (CFStringRef
)keys
[i
]);
299 if (isA_CFString(keys
[0])) {
300 compFunc
= (CFComparatorFunction
)CFStringCompare
;
302 else if (isA_CFNumber(keys
[0])) {
303 compFunc
= (CFComparatorFunction
)CFNumberCompare
;
305 else if (isA_CFDate(keys
[0])) {
306 compFunc
= (CFComparatorFunction
)CFDateCompare
;
309 if (compFunc
!= NULL
) {
310 CFArraySortValues(sortedKeys
,
311 CFRangeMake(0, nElements
),
316 for (i
= 0; i
< nElements
; i
++) {
322 key
= CFArrayGetValueAtIndex(sortedKeys
, i
);
323 kStr
= _SCCopyDescription((CFTypeRef
)key
, NULL
);
325 nPrefix1
= CFStringCreateMutable(NULL
, 0);
326 CFStringAppendFormat(nPrefix1
,
331 nPrefix2
= CFStringCreateMutable(NULL
, 0);
332 CFStringAppendFormat(nPrefix2
,
337 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
338 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
343 val
= CFDictionaryGetValue(cf
, key
);
344 vStr
= _SCCopyDescription((CFTypeRef
)val
, nFormatOptions
);
345 CFStringAppendFormat(str
,
352 CFRelease(sortedKeys
);
354 if (keys
!= keys_q
) {
355 CFAllocatorDeallocate(NULL
, keys
);
358 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
360 CFRelease(nFormatOptions
);
364 CFRelease(nFormatOptions
);
365 #endif /* ENABLE_SC_FORMATTING */
367 return CFStringCreateWithFormat(NULL
,
375 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
378 _SC_isInstallEnvironment() {
379 static dispatch_once_t once
;
380 static Boolean is_install
;
382 dispatch_once(&once
, ^{
383 is_install
= (getenv(INSTALL_ENVIRONMENT
) != NULL
);
391 _SC_LOG_DEFAULT(void)
393 static os_log_t log
= NULL
;
396 log
= os_log_create("com.apple.SystemConfiguration", "");
404 _SC_syslog_os_log_mapping(int level
)
414 return OS_LOG_TYPE_ERROR
;
419 return OS_LOG_TYPE_DEFAULT
;
422 return OS_LOG_TYPE_INFO
;
425 return OS_LOG_TYPE_DEBUG
;
428 return OS_LOG_TYPE_DEFAULT
;
432 __SCLog(void *ret_addr
, os_log_type_t type
, const char *formatString
, va_list formatArguments
)
434 os_log_with_args(_SC_LOG_DEFAULT(),
444 __SCPrint(FILE *stream
, CFStringRef formatString
, va_list formatArguments
, Boolean trace
, Boolean addNL
)
450 #ifdef ENABLE_SC_FORMATTING
451 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
456 #else /* ENABLE_SC_FORMATTING */
457 str
= CFStringCreateWithFormatAndArguments (NULL
,
461 #endif /* !ENABLE_SC_FORMATTING */
463 line
=_SC_cfstring_to_cstring_ext(str
,
466 kCFStringEncodingUTF8
,
474 pthread_mutex_lock(&lock
);
477 struct timeval tv_now
;
479 (void)gettimeofday(&tv_now
, NULL
);
480 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
481 (void)fprintf(stream
, "%2d:%02d:%02d.%03d ",
482 tm_now
.tm_hour
, tm_now
.tm_min
, tm_now
.tm_sec
, tv_now
.tv_usec
/ 1000);
484 (void)fwrite((const void *)line
, usedBufLen
, 1, stream
);
486 (void)fputc('\n', stream
);
489 pthread_mutex_unlock(&lock
);
490 CFAllocatorDeallocate(NULL
, line
);
497 __SC_Log(int level
, CFStringRef format_CF
, os_log_t log
, os_log_type_t type
, const char *format
, ...)
499 #pragma unused(level)
500 Boolean do_log
= FALSE
;
501 Boolean do_print
= FALSE
;
506 * Note: The following are the expected values for _sc_log
508 * 0 if SC messages should be written to stdout/stderr
509 * 1 if SC messages should be logged w/os_log(3)
510 * 2 if SC messages should be written to stdout/stderr AND logged
514 do_log
= TRUE
; // log requested
515 va_start(args_log
, format
);
518 do_print
= TRUE
; // log AND print requested
519 va_copy(args_print
, args_log
);
522 do_print
= TRUE
; // print requested
523 va_start(args_print
, format
);
527 os_log_with_args(log
,
531 __builtin_return_address(0));
539 (_sc_log
> 0), // trace
540 TRUE
); // add newline
549 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
551 va_list formatArguments
;
552 va_list formatArguments_print
;
554 Boolean print
= FALSE
;
561 * Note: The following are the expected values for _sc_log
563 * 0 if SC messages should be written to stdout/stderr
564 * 1 if SC messages should be logged w/os_log(3)
565 * 2 if SC messages should be written to stdout/stderr AND logged
569 log
= TRUE
; // log requested
570 va_start(formatArguments
, formatString
);
573 print
= TRUE
; // log AND print requested
574 va_copy(formatArguments_print
, formatArguments
);
577 print
= TRUE
; // print requested
578 va_start(formatArguments_print
, formatString
);
582 const char *__format
;
584 __format
= CFStringGetCStringPtr(formatString
, kCFStringEncodingUTF8
);
585 if (__format
!= NULL
) {
586 os_log_type_t __type
;
588 __type
= _SC_syslog_os_log_mapping(level
);
589 __SCLog(__builtin_return_address(0), __type
, __format
, formatArguments
);
591 va_end(formatArguments
);
595 __SCPrint((LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
,
597 formatArguments_print
,
598 (_sc_log
> 0), // trace
599 TRUE
); // add newline
600 va_end(formatArguments_print
);
608 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
610 va_list formatArguments
;
616 va_start(formatArguments
, formatString
);
617 __SCPrint(stream
, formatString
, formatArguments
, FALSE
, FALSE
);
618 va_end(formatArguments
);
625 #pragma mark SC error handling / logging
628 const CFStringRef kCFErrorDomainSystemConfiguration
= CFSTR("com.apple.SystemConfiguration");
631 static const struct sc_errmsg
{
635 { kSCStatusAccessError
, "Permission denied" },
636 { kSCStatusConnectionIgnore
, "Network connection information not available at this time" },
637 { kSCStatusConnectionNoService
, "Network service for connection not available" },
638 { kSCStatusFailed
, "Failed!" },
639 { kSCStatusInvalidArgument
, "Invalid argument" },
640 { kSCStatusKeyExists
, "Key already defined" },
641 { kSCStatusLocked
, "Lock already held" },
642 { kSCStatusMaxLink
, "Maximum link count exceeded" },
643 { kSCStatusNeedLock
, "Lock required for this operation" },
644 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
645 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
646 { kSCStatusNoConfigFile
, "Configuration file not found" },
647 { kSCStatusNoKey
, "No such key" },
648 { kSCStatusNoLink
, "No such link" },
649 { kSCStatusNoPrefsSession
, "Preference session not active" },
650 { kSCStatusNotifierActive
, "Notifier is currently active" },
651 { kSCStatusOK
, "Success!" },
652 { kSCStatusPrefsBusy
, "Preferences update currently in progress" },
653 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
654 { kSCStatusStale
, "Write attempted on stale version of object" },
656 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
659 _SCErrorSet(int error
)
661 __SCThreadSpecificDataRef tsd
;
663 tsd
= __SCGetThreadSpecificData();
664 tsd
->_sc_error
= error
;
670 SCCopyLastError(void)
676 __SCThreadSpecificDataRef tsd
;
677 CFMutableDictionaryRef userInfo
= NULL
;
679 tsd
= __SCGetThreadSpecificData();
680 code
=tsd
->_sc_error
;
682 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
683 if (sc_errmsgs
[i
].status
== code
) {
686 domain
= kCFErrorDomainSystemConfiguration
;
687 userInfo
= CFDictionaryCreateMutable(NULL
,
689 &kCFCopyStringDictionaryKeyCallBacks
,
690 &kCFTypeDictionaryValueCallBacks
);
691 str
= CFStringCreateWithCString(NULL
,
692 sc_errmsgs
[i
].message
,
693 kCFStringEncodingASCII
);
694 CFDictionarySetValue(userInfo
, kCFErrorDescriptionKey
, str
);
700 if ((code
> 0) && (code
<= ELAST
)) {
701 domain
= kCFErrorDomainPOSIX
;
705 domain
= kCFErrorDomainMach
;
709 error
= CFErrorCreate(NULL
, domain
, code
, userInfo
);
710 if (userInfo
!= NULL
) CFRelease(userInfo
);
718 __SCThreadSpecificDataRef tsd
;
720 tsd
= __SCGetThreadSpecificData();
721 return tsd
->_sc_error
;
726 SCErrorString(int status
)
730 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
731 if (sc_errmsgs
[i
].status
== status
) {
732 return sc_errmsgs
[i
].message
;
736 if ((status
> 0) && (status
<= ELAST
)) {
737 return strerror(status
);
740 if ((status
>= BOOTSTRAP_SUCCESS
) && (status
<= BOOTSTRAP_NO_MEMORY
)) {
741 return bootstrap_strerror(status
);
744 return mach_error_string(status
);