2 * Copyright (c) 2000-2008, 2010 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 <SystemConfiguration/SystemConfiguration.h>
41 #include <SystemConfiguration/SCPrivate.h>
42 #include "SCDynamicStoreInternal.h"
43 #include "config.h" /* MiG generated file */
46 /* framework variables */
47 int _sc_debug
= FALSE
; /* non-zero if debugging enabled */
48 int _sc_verbose
= FALSE
; /* non-zero if verbose logging enabled */
49 int _sc_log
= TRUE
; /* 0 if SC messages should be written to stdout/stderr,
50 1 if SC messages should be logged w/asl(3),
51 2 if SC messages should be written to stdout/stderr AND logged */
55 #pragma mark Thread specific data
61 } __SCThreadSpecificData
, *__SCThreadSpecificDataRef
;
64 static pthread_once_t tsKeyInitialized
= PTHREAD_ONCE_INIT
;
65 static pthread_key_t tsDataKey
;
69 __SCThreadSpecificDataFinalize(void *arg
)
71 __SCThreadSpecificDataRef tsd
= (__SCThreadSpecificDataRef
)arg
;
74 if (tsd
->_asl
!= NULL
) asl_close(tsd
->_asl
);
75 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
82 __SCThreadSpecificKeyInitialize()
84 pthread_key_create(&tsDataKey
, __SCThreadSpecificDataFinalize
);
89 static __SCThreadSpecificDataRef
90 __SCGetThreadSpecificData()
92 __SCThreadSpecificDataRef tsd
;
94 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
96 tsd
= pthread_getspecific(tsDataKey
);
98 tsd
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__SCThreadSpecificData
), 0);
99 tsd
->_asl
= asl_open(NULL
, NULL
, 0);
100 asl_set_filter(tsd
->_asl
, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG
));
101 tsd
->_sc_error
= kSCStatusOK
;
102 pthread_setspecific(tsDataKey
, tsd
);
113 #define ENABLE_SC_FORMATTING
114 #ifdef ENABLE_SC_FORMATTING
115 // from <CoreFoundation/ForFoundationOnly.h>
116 extern CFStringRef
_CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc
, CFStringRef (*copyDescFunc
)(CFTypeRef
, CFDictionaryRef
), CFDictionaryRef formatOptions
, CFStringRef format
, va_list arguments
);
117 #endif /* ENABLE_SC_FORMATTING */
121 _SCCopyDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
123 #ifdef ENABLE_SC_FORMATTING
124 CFMutableDictionaryRef nFormatOptions
;
127 CFTypeID type
= CFGetTypeID(cf
);
129 if (!formatOptions
||
130 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX1"), (const void **)&prefix1
)) {
134 if (type
== CFStringGetTypeID()) {
135 return CFStringCreateWithFormat(NULL
,
142 if (type
== CFBooleanGetTypeID()) {
143 return CFStringCreateWithFormat(NULL
,
147 CFBooleanGetValue(cf
) ? "TRUE" : "FALSE");
150 if (type
== CFDataGetTypeID()) {
154 CFMutableStringRef str
;
156 str
= CFStringCreateMutable(NULL
, 0);
157 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<data> 0x"), prefix1
);
159 data
= CFDataGetBytePtr(cf
);
160 dataLen
= CFDataGetLength(cf
);
161 for (i
= 0; i
< dataLen
; i
++) {
162 CFStringAppendFormat(str
, NULL
, CFSTR("%02x"), data
[i
]);
168 if (type
== CFNumberGetTypeID()) {
169 return CFStringCreateWithFormat(NULL
,
176 if (type
== CFDateGetTypeID()) {
177 CFGregorianDate gDate
;
181 tZone
= CFTimeZoneCopySystem();
182 gDate
= CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(cf
), tZone
);
183 str
= CFStringCreateWithFormat(NULL
,
185 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
193 CFTimeZoneGetName(tZone
));
198 if (!formatOptions
||
199 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX2"), (const void **)&prefix2
)) {
204 nFormatOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, formatOptions
);
206 nFormatOptions
= CFDictionaryCreateMutable(NULL
,
208 &kCFTypeDictionaryKeyCallBacks
,
209 &kCFTypeDictionaryValueCallBacks
);
214 if (type
== CFArrayGetTypeID()) {
215 const void * elements_q
[N_QUICK
];
216 const void ** elements
= elements_q
;
219 CFMutableStringRef str
;
221 str
= CFStringCreateMutable(NULL
, 0);
222 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<array> {"), prefix1
);
224 nElements
= CFArrayGetCount(cf
);
226 if (nElements
> (CFIndex
)(sizeof(elements_q
)/sizeof(CFTypeRef
)))
227 elements
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
228 CFArrayGetValues(cf
, CFRangeMake(0, nElements
), elements
);
229 for (i
= 0; i
< nElements
; i
++) {
230 CFMutableStringRef nPrefix1
;
231 CFMutableStringRef nPrefix2
;
235 nStr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%u"), i
);
237 nPrefix1
= CFStringCreateMutable(NULL
, 0);
238 CFStringAppendFormat(nPrefix1
,
243 nPrefix2
= CFStringCreateMutable(NULL
, 0);
244 CFStringAppendFormat(nPrefix2
,
249 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
250 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
255 vStr
= _SCCopyDescription((CFTypeRef
)elements
[i
], nFormatOptions
);
256 CFStringAppendFormat(str
,
262 if (elements
!= elements_q
) CFAllocatorDeallocate(NULL
, elements
);
264 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
266 CFRelease(nFormatOptions
);
270 if (type
== CFDictionaryGetTypeID()) {
271 const void * keys_q
[N_QUICK
];
272 const void ** keys
= keys_q
;
275 CFMutableStringRef nPrefix1
;
276 CFMutableStringRef nPrefix2
;
277 CFMutableStringRef str
;
279 str
= CFStringCreateMutable(NULL
, 0);
280 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
282 nElements
= CFDictionaryGetCount(cf
);
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
]);
295 CFArraySortValues(sortedKeys
,
296 CFRangeMake(0, nElements
),
297 (CFComparatorFunction
)CFStringCompare
,
300 for (i
= 0; i
< nElements
; i
++) {
306 key
= CFArrayGetValueAtIndex(sortedKeys
, i
);
307 kStr
= _SCCopyDescription((CFTypeRef
)key
, NULL
);
309 nPrefix1
= CFStringCreateMutable(NULL
, 0);
310 CFStringAppendFormat(nPrefix1
,
315 nPrefix2
= CFStringCreateMutable(NULL
, 0);
316 CFStringAppendFormat(nPrefix2
,
321 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
322 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
327 val
= CFDictionaryGetValue(cf
, key
);
328 vStr
= _SCCopyDescription((CFTypeRef
)val
, nFormatOptions
);
329 CFStringAppendFormat(str
,
336 CFRelease(sortedKeys
);
338 if (keys
!= keys_q
) {
339 CFAllocatorDeallocate(NULL
, keys
);
342 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
344 CFRelease(nFormatOptions
);
348 CFRelease(nFormatOptions
);
349 #endif /* ENABLE_SC_FORMATTING */
351 return CFStringCreateWithFormat(NULL
,
359 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
363 __SCLog(aslclient asl
, aslmsg msg
, int level
, CFStringRef formatString
, va_list formatArguments
)
370 __SCThreadSpecificDataRef tsd
;
372 tsd
= __SCGetThreadSpecificData();
376 #ifdef ENABLE_SC_FORMATTING
377 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
382 #else /* ENABLE_SC_FORMATTING */
383 str
= CFStringCreateWithFormatAndArguments (NULL
,
387 #endif /* !ENABLE_SC_FORMATTING */
390 lines
= CFStringCreateArrayBySeparatingStrings(NULL
, str
, CFSTR("\n"));
393 int n
= CFArrayGetCount(lines
);
395 for (i
= 0; i
< n
; i
++) {
396 line
= CFStringCreateExternalRepresentation(NULL
,
397 CFArrayGetValueAtIndex(lines
, i
),
398 kCFStringEncodingUTF8
,
401 asl_log(asl
, msg
, level
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
408 line
= CFStringCreateExternalRepresentation(NULL
,
410 kCFStringEncodingUTF8
,
413 asl_log(asl
, msg
, ~level
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
424 __SCPrint(FILE *stream
, CFStringRef formatString
, va_list formatArguments
, Boolean trace
, Boolean addNL
)
429 #ifdef ENABLE_SC_FORMATTING
430 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
435 #else /* ENABLE_SC_FORMATTING */
436 str
= CFStringCreateWithFormatAndArguments (NULL
,
440 #endif /* !ENABLE_SC_FORMATTING */
442 line
= CFStringCreateExternalRepresentation(NULL
,
444 kCFStringEncodingUTF8
,
451 pthread_mutex_lock(&lock
);
454 struct timeval tv_now
;
456 (void)gettimeofday(&tv_now
, NULL
);
457 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
458 (void)fprintf(stream
, "%2d:%02d:%02d.%03d ",
459 tm_now
.tm_hour
, tm_now
.tm_min
, tm_now
.tm_sec
, tv_now
.tv_usec
/ 1000);
461 (void)fwrite((const void *)CFDataGetBytePtr(line
), (size_t)CFDataGetLength(line
), 1, stream
);
463 (void)fputc('\n', stream
);
466 pthread_mutex_unlock(&lock
);
474 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
476 va_list formatArguments
;
477 va_list formatArguments_print
;
479 Boolean print
= FALSE
;
486 * Note: The following are the expected values for _sc_log
488 * 0 if SC messages should be written to stdout/stderr
489 * 1 if SC messages should be logged w/asl(3)
490 * 2 if SC messages should be written to stdout/stderr AND logged
494 log
= TRUE
; // log requested
495 va_start(formatArguments
, formatString
);
498 print
= TRUE
; // log AND print requested
499 va_copy(formatArguments_print
, formatArguments
);
502 print
= TRUE
; // print requested
503 va_start(formatArguments_print
, formatString
);
507 __SCLog(NULL
, NULL
, level
, formatString
, formatArguments
);
508 va_end(formatArguments
);
512 __SCPrint((LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
,
514 formatArguments_print
,
515 (_sc_log
> 0), // trace
516 TRUE
); // add newline
517 va_end(formatArguments_print
);
525 SCLOG(aslclient asl
, aslmsg msg
, int level
, CFStringRef formatString
, ...)
527 va_list formatArguments
;
528 va_list formatArguments_print
;
530 Boolean print
= FALSE
;
533 * Note: The following are the expected values for _sc_log
535 * 0 if SC messages should be written to stdout/stderr
536 * 1 if SC messages should be logged w/asl(3)
537 * 2 if SC messages should be written to stdout/stderr AND logged
541 log
= TRUE
; // log requested
542 va_start(formatArguments
, formatString
);
545 print
= TRUE
; // log AND print requested
546 va_copy(formatArguments_print
, formatArguments
);
549 print
= TRUE
; // print requested
550 va_start(formatArguments_print
, formatString
);
554 __SCLog(asl
, msg
, level
, formatString
, formatArguments
);
555 va_end(formatArguments
);
562 __SCPrint((level
> ASL_LEVEL_NOTICE
) ? stderr
: stdout
,
564 formatArguments_print
,
565 (_sc_log
> 0), // trace
566 TRUE
); // add newline
567 va_end(formatArguments_print
);
575 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
577 va_list formatArguments
;
583 va_start(formatArguments
, formatString
);
584 __SCPrint(stream
, formatString
, formatArguments
, FALSE
, FALSE
);
585 va_end(formatArguments
);
592 SCTrace(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
594 va_list formatArguments
;
600 va_start(formatArguments
, formatString
);
601 __SCPrint(stream
, formatString
, formatArguments
, TRUE
, FALSE
);
602 va_end(formatArguments
);
609 #pragma mark SC error handling / logging
612 const CFStringRef kCFErrorDomainSystemConfiguration
= CFSTR("com.apple.SystemConfiguration");
615 static const struct sc_errmsg
{
619 { kSCStatusAccessError
, "Permission denied" },
620 { kSCStatusConnectionNoService
, "Network service for connection not available" },
621 { kSCStatusFailed
, "Failed!" },
622 { kSCStatusInvalidArgument
, "Invalid argument" },
623 { kSCStatusKeyExists
, "Key already defined" },
624 { kSCStatusLocked
, "Lock already held" },
625 { kSCStatusMaxLink
, "Maximum link count exceeded" },
626 { kSCStatusNeedLock
, "Lock required for this operation" },
627 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
628 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
629 { kSCStatusNoConfigFile
, "Configuration file not found" },
630 { kSCStatusNoKey
, "No such key" },
631 { kSCStatusNoLink
, "No such link" },
632 { kSCStatusNoPrefsSession
, "Preference session not active" },
633 { kSCStatusNotifierActive
, "Notifier is currently active" },
634 { kSCStatusOK
, "Success!" },
635 { kSCStatusPrefsBusy
, "Preferences update currently in progress" },
636 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
637 { kSCStatusStale
, "Write attempted on stale version of object" },
639 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
643 _SCErrorSet(int error
)
645 __SCThreadSpecificDataRef tsd
;
647 tsd
= __SCGetThreadSpecificData();
648 tsd
->_sc_error
= error
;
654 SCCopyLastError(void)
660 __SCThreadSpecificDataRef tsd
;
661 CFMutableDictionaryRef userInfo
= NULL
;
663 tsd
= __SCGetThreadSpecificData();
664 code
=tsd
->_sc_error
;
666 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
667 if (sc_errmsgs
[i
].status
== code
) {
670 domain
= kCFErrorDomainSystemConfiguration
;
671 userInfo
= CFDictionaryCreateMutable(NULL
,
673 &kCFCopyStringDictionaryKeyCallBacks
,
674 &kCFTypeDictionaryValueCallBacks
);
675 str
= CFStringCreateWithCString(NULL
,
676 sc_errmsgs
[i
].message
,
677 kCFStringEncodingASCII
);
678 CFDictionarySetValue(userInfo
, kCFErrorDescriptionKey
, str
);
684 if ((code
> 0) && (code
<= ELAST
)) {
685 domain
= kCFErrorDomainPOSIX
;
689 domain
= kCFErrorDomainMach
;
693 error
= CFErrorCreate(NULL
, domain
, code
, userInfo
);
694 if (userInfo
!= NULL
) CFRelease(userInfo
);
702 __SCThreadSpecificDataRef tsd
;
704 tsd
= __SCGetThreadSpecificData();
705 return tsd
->_sc_error
;
710 SCErrorString(int status
)
714 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
715 if (sc_errmsgs
[i
].status
== status
) {
716 return sc_errmsgs
[i
].message
;
720 if ((status
> 0) && (status
<= ELAST
)) {
721 return strerror(status
);
724 if ((status
>= BOOTSTRAP_SUCCESS
) && (status
<= BOOTSTRAP_NO_MEMORY
)) {
725 return bootstrap_strerror(status
);
728 return mach_error_string(status
);