2 * Copyright (c) 2000-2008 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
;
278 const void * values_q
[N_QUICK
];
279 const void ** values
= values_q
;
281 str
= CFStringCreateMutable(NULL
, 0);
282 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
284 nElements
= CFDictionaryGetCount(cf
);
286 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
287 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
288 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
290 CFDictionaryGetKeysAndValues(cf
, keys
, values
);
291 for (i
= 0; i
< nElements
; i
++) {
295 kStr
= _SCCopyDescription((CFTypeRef
)keys
[i
], NULL
);
297 nPrefix1
= CFStringCreateMutable(NULL
, 0);
298 CFStringAppendFormat(nPrefix1
,
303 nPrefix2
= CFStringCreateMutable(NULL
, 0);
304 CFStringAppendFormat(nPrefix2
,
309 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
310 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
315 vStr
= _SCCopyDescription((CFTypeRef
)values
[i
], nFormatOptions
);
316 CFStringAppendFormat(str
,
322 if (keys
!= keys_q
) {
323 CFAllocatorDeallocate(NULL
, keys
);
324 CFAllocatorDeallocate(NULL
, values
);
327 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
329 CFRelease(nFormatOptions
);
333 CFRelease(nFormatOptions
);
334 #endif /* ENABLE_SC_FORMATTING */
336 return CFStringCreateWithFormat(NULL
,
344 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
348 __SCLog(aslclient asl
, aslmsg msg
, int level
, CFStringRef formatString
, va_list formatArguments
)
355 __SCThreadSpecificDataRef tsd
;
357 tsd
= __SCGetThreadSpecificData();
361 #ifdef ENABLE_SC_FORMATTING
362 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
367 #else /* ENABLE_SC_FORMATTING */
368 str
= CFStringCreateWithFormatAndArguments (NULL
,
372 #endif /* !ENABLE_SC_FORMATTING */
375 lines
= CFStringCreateArrayBySeparatingStrings(NULL
, str
, CFSTR("\n"));
378 int n
= CFArrayGetCount(lines
);
380 for (i
= 0; i
< n
; i
++) {
381 line
= CFStringCreateExternalRepresentation(NULL
,
382 CFArrayGetValueAtIndex(lines
, i
),
383 kCFStringEncodingUTF8
,
386 asl_log(asl
, msg
, level
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
393 line
= CFStringCreateExternalRepresentation(NULL
,
395 kCFStringEncodingUTF8
,
398 asl_log(asl
, msg
, ~level
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
409 __SCPrint(FILE *stream
, CFStringRef formatString
, va_list formatArguments
, Boolean trace
, Boolean addNL
)
414 #ifdef ENABLE_SC_FORMATTING
415 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
420 #else /* ENABLE_SC_FORMATTING */
421 str
= CFStringCreateWithFormatAndArguments (NULL
,
425 #endif /* !ENABLE_SC_FORMATTING */
427 line
= CFStringCreateExternalRepresentation(NULL
,
429 kCFStringEncodingUTF8
,
436 pthread_mutex_lock(&lock
);
439 struct timeval tv_now
;
441 (void)gettimeofday(&tv_now
, NULL
);
442 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
443 (void)fprintf(stream
, "%2d:%02d:%02d.%03d ",
444 tm_now
.tm_hour
, tm_now
.tm_min
, tm_now
.tm_sec
, tv_now
.tv_usec
/ 1000);
446 (void)fwrite((const void *)CFDataGetBytePtr(line
), (size_t)CFDataGetLength(line
), 1, stream
);
448 (void)fputc('\n', stream
);
451 pthread_mutex_unlock(&lock
);
459 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
461 va_list formatArguments
;
467 va_start(formatArguments
, formatString
);
469 __SCLog(NULL
, NULL
, level
, formatString
, formatArguments
);
472 __SCPrint((LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
,
475 (_sc_log
> 0), // trace
476 TRUE
); // add newline
478 va_end(formatArguments
);
485 SCLOG(aslclient asl
, aslmsg msg
, int level
, CFStringRef formatString
, ...)
487 va_list formatArguments
;
489 va_start(formatArguments
, formatString
);
491 __SCLog(asl
, msg
, level
, formatString
, formatArguments
);
497 __SCPrint((level
> ASL_LEVEL_NOTICE
) ? stderr
: stdout
,
500 (_sc_log
> 0), // trace
501 TRUE
); // add newline
503 va_end(formatArguments
);
510 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
512 va_list formatArguments
;
518 va_start(formatArguments
, formatString
);
519 __SCPrint(stream
, formatString
, formatArguments
, FALSE
, FALSE
);
520 va_end(formatArguments
);
527 SCTrace(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
529 va_list formatArguments
;
535 va_start(formatArguments
, formatString
);
536 __SCPrint(stream
, formatString
, formatArguments
, TRUE
, FALSE
);
537 va_end(formatArguments
);
544 #pragma mark SC error handling / logging
547 const CFStringRef kCFErrorDomainSystemConfiguration
= CFSTR("com.apple.SystemConfiguration");
550 static const struct sc_errmsg
{
554 { kSCStatusAccessError
, "Permission denied" },
555 { kSCStatusConnectionNoService
, "Network service for connection not available" },
556 { kSCStatusFailed
, "Failed!" },
557 { kSCStatusInvalidArgument
, "Invalid argument" },
558 { kSCStatusKeyExists
, "Key already defined" },
559 { kSCStatusLocked
, "Lock already held" },
560 { kSCStatusMaxLink
, "Maximum link count exceeded" },
561 { kSCStatusNeedLock
, "Lock required for this operation" },
562 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
563 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
564 { kSCStatusNoConfigFile
, "Configuration file not found" },
565 { kSCStatusNoKey
, "No such key" },
566 { kSCStatusNoLink
, "No such link" },
567 { kSCStatusNoPrefsSession
, "Preference session not active" },
568 { kSCStatusNotifierActive
, "Notifier is currently active" },
569 { kSCStatusOK
, "Success!" },
570 { kSCStatusPrefsBusy
, "Preferences update currently in progress" },
571 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
572 { kSCStatusStale
, "Write attempted on stale version of object" },
574 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
578 _SCErrorSet(int error
)
580 __SCThreadSpecificDataRef tsd
;
582 tsd
= __SCGetThreadSpecificData();
583 tsd
->_sc_error
= error
;
589 SCCopyLastError(void)
595 __SCThreadSpecificDataRef tsd
;
596 CFMutableDictionaryRef userInfo
= NULL
;
598 tsd
= __SCGetThreadSpecificData();
599 code
=tsd
->_sc_error
;
601 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
602 if (sc_errmsgs
[i
].status
== code
) {
605 domain
= kCFErrorDomainSystemConfiguration
;
606 userInfo
= CFDictionaryCreateMutable(NULL
,
608 &kCFCopyStringDictionaryKeyCallBacks
,
609 &kCFTypeDictionaryValueCallBacks
);
610 str
= CFStringCreateWithCString(NULL
,
611 sc_errmsgs
[i
].message
,
612 kCFStringEncodingASCII
);
613 CFDictionarySetValue(userInfo
, kCFErrorDescriptionKey
, str
);
619 if ((code
> 0) && (code
<= ELAST
)) {
620 domain
= kCFErrorDomainPOSIX
;
624 domain
= kCFErrorDomainMach
;
628 error
= CFErrorCreate(NULL
, domain
, code
, userInfo
);
629 if (userInfo
!= NULL
) CFRelease(userInfo
);
637 __SCThreadSpecificDataRef tsd
;
639 tsd
= __SCGetThreadSpecificData();
640 return tsd
->_sc_error
;
645 SCErrorString(int status
)
649 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
650 if (sc_errmsgs
[i
].status
== status
) {
651 return sc_errmsgs
[i
].message
;
655 if ((status
> 0) && (status
<= ELAST
)) {
656 return strerror(status
);
659 if ((status
>= BOOTSTRAP_SUCCESS
) && (status
<= BOOTSTRAP_NO_MEMORY
)) {
660 return bootstrap_strerror(status
);
663 return mach_error_string(status
);