2 * Copyright (c) 2000-2007 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 */
45 /* framework variables */
46 Boolean _sc_debug
= FALSE
; /* TRUE if debugging enabled */
47 Boolean _sc_verbose
= FALSE
; /* TRUE if verbose logging enabled */
48 Boolean _sc_log
= TRUE
; /* TRUE if SCLog() output goes to syslog */
50 static const struct sc_errmsg
{
54 { kSCStatusAccessError
, "Permission denied" },
55 { kSCStatusFailed
, "Failed!" },
56 { kSCStatusInvalidArgument
, "Invalid argument" },
57 { kSCStatusKeyExists
, "Key already defined" },
58 { kSCStatusLocked
, "Lock already held" },
59 { kSCStatusMaxLink
, "Maximum link count exceeded" },
60 { kSCStatusNeedLock
, "Lock required for this operation" },
61 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
62 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
63 { kSCStatusNoConfigFile
, "Configuration file not found" },
64 { kSCStatusNoKey
, "No such key" },
65 { kSCStatusNoLink
, "No such link" },
66 { kSCStatusNoPrefsSession
, "Preference session not active" },
67 { kSCStatusNotifierActive
, "Notifier is currently active" },
68 { kSCStatusOK
, "Success!" },
69 { kSCStatusPrefsBusy
, "Preferences update currently in progress" },
70 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
71 { kSCStatusStale
, "Write attempted on stale version of object" },
73 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
76 #define USE_SCCOPYDESCRIPTION
77 #ifdef USE_SCCOPYDESCRIPTION
79 // from <CoreFoundation/CFVeryPrivate.h>
80 extern CFStringRef
_CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc
, CFStringRef (*copyDescFunc
)(void *, CFDictionaryRef
), CFDictionaryRef formatOptions
, CFStringRef format
, va_list arguments
);
85 _SCCopyDescription(void *info
, CFDictionaryRef formatOptions
)
87 CFMutableDictionaryRef nFormatOptions
;
90 CFTypeID type
= CFGetTypeID(info
);
93 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX1"), (const void **)&prefix1
)) {
97 if (type
== CFStringGetTypeID()) {
98 return CFStringCreateWithFormat(NULL
,
105 if (type
== CFBooleanGetTypeID()) {
106 return CFStringCreateWithFormat(NULL
,
110 CFBooleanGetValue(info
) ? "TRUE" : "FALSE");
113 if (type
== CFDataGetTypeID()) {
117 CFMutableStringRef str
;
119 str
= CFStringCreateMutable(NULL
, 0);
120 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<data> 0x"), prefix1
);
122 data
= CFDataGetBytePtr(info
);
123 dataLen
= CFDataGetLength(info
);
124 for (i
= 0; i
< dataLen
; i
++) {
125 CFStringAppendFormat(str
, NULL
, CFSTR("%02x"), data
[i
]);
131 if (type
== CFNumberGetTypeID()) {
132 return CFStringCreateWithFormat(NULL
,
139 if (type
== CFDateGetTypeID()) {
140 CFGregorianDate gDate
;
144 tZone
= CFTimeZoneCopySystem();
145 gDate
= CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(info
), tZone
);
146 str
= CFStringCreateWithFormat(NULL
,
148 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
156 CFTimeZoneGetName(tZone
));
161 if (!formatOptions
||
162 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX2"), (const void **)&prefix2
)) {
163 prefix2
= CFStringCreateCopy(NULL
, prefix1
);
167 nFormatOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, formatOptions
);
169 nFormatOptions
= CFDictionaryCreateMutable(NULL
,
171 &kCFTypeDictionaryKeyCallBacks
,
172 &kCFTypeDictionaryValueCallBacks
);
175 if (type
== CFArrayGetTypeID()) {
176 const void * elements_q
[32];
177 const void ** elements
= elements_q
;
180 CFMutableStringRef str
;
182 str
= CFStringCreateMutable(NULL
, 0);
183 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<array> {"), prefix1
);
185 nElements
= CFArrayGetCount(info
);
187 if (nElements
> (CFIndex
)(sizeof(elements_q
)/sizeof(CFTypeRef
)))
188 elements
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
189 CFArrayGetValues(info
, CFRangeMake(0, nElements
), elements
);
190 for (i
= 0; i
< nElements
; i
++) {
191 CFMutableStringRef nPrefix1
;
192 CFMutableStringRef nPrefix2
;
196 nStr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%u"), i
);
198 nPrefix1
= CFStringCreateMutable(NULL
, 0);
199 CFStringAppendFormat(nPrefix1
,
204 nPrefix2
= CFStringCreateMutable(NULL
, 0);
205 CFStringAppendFormat(nPrefix2
,
210 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
211 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
216 vStr
= _SCCopyDescription((void *)elements
[i
], nFormatOptions
);
217 CFStringAppendFormat(str
,
223 if (elements
!= elements_q
) CFAllocatorDeallocate(NULL
, elements
);
225 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
227 CFRelease(nFormatOptions
);
231 if (type
== CFDictionaryGetTypeID()) {
232 const void * keys_q
[N_QUICK
];
233 const void ** keys
= keys_q
;
236 CFMutableStringRef nPrefix1
;
237 CFMutableStringRef nPrefix2
;
238 CFMutableStringRef str
;
239 const void * values_q
[N_QUICK
];
240 const void ** values
= values_q
;
242 str
= CFStringCreateMutable(NULL
, 0);
243 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
245 nElements
= CFDictionaryGetCount(info
);
247 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
248 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
249 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
251 CFDictionaryGetKeysAndValues(info
, keys
, values
);
252 for (i
= 0; i
< nElements
; i
++) {
256 kStr
= _SCCopyDescription((void *)keys
[i
], NULL
);
258 nPrefix1
= CFStringCreateMutable(NULL
, 0);
259 CFStringAppendFormat(nPrefix1
,
264 nPrefix2
= CFStringCreateMutable(NULL
, 0);
265 CFStringAppendFormat(nPrefix2
,
270 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
271 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
276 vStr
= _SCCopyDescription((void *)values
[i
], nFormatOptions
);
277 CFStringAppendFormat(str
,
283 if (keys
!= keys_q
) {
284 CFAllocatorDeallocate(NULL
, keys
);
285 CFAllocatorDeallocate(NULL
, values
);
288 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
290 CFRelease(nFormatOptions
);
294 CFRelease(nFormatOptions
);
300 cfStr
= CFCopyDescription(info
);
301 str
= CFStringCreateWithFormat(NULL
,
311 #endif /* USE_SCCOPYDESCRIPTION */
314 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
318 __SCLog(int level
, CFStringRef formatString
, va_list formatArguments
)
323 #ifdef USE_SCCOPYDESCRIPTION
324 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
329 #else /* USE_SCCOPYDESCRIPTION */
330 str
= CFStringCreateWithFormatAndArguments (NULL
,
334 #endif /* !USE_SCCOPYDESCRIPTION */
336 lines
= CFStringCreateArrayBySeparatingStrings(NULL
, str
, CFSTR("\n"));
341 int n
= CFArrayGetCount(lines
);
343 pthread_mutex_lock(&lock
);
344 for (i
= 0; i
< n
; i
++) {
347 line
= CFStringCreateExternalRepresentation(NULL
,
348 CFArrayGetValueAtIndex(lines
, i
),
349 kCFStringEncodingUTF8
,
352 syslog (level
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
356 pthread_mutex_unlock(&lock
);
365 __SCPrint(FILE *stream
, CFStringRef formatString
, va_list formatArguments
, Boolean trace
, Boolean addNL
)
370 #ifdef USE_SCCOPYDESCRIPTION
371 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
376 #else /* USE_SCCOPYDESCRIPTION */
377 str
= CFStringCreateWithFormatAndArguments (NULL
,
381 #endif /* !USE_SCCOPYDESCRIPTION */
383 line
= CFStringCreateExternalRepresentation(NULL
,
385 kCFStringEncodingUTF8
,
392 pthread_mutex_lock(&lock
);
395 struct timeval tv_now
;
397 (void)gettimeofday(&tv_now
, NULL
);
398 (void)localtime_r(&tv_now
.tv_sec
, &tm_now
);
399 (void)fprintf(stream
, "%2d:%02d:%02d.%03d ",
400 tm_now
.tm_hour
, tm_now
.tm_min
, tm_now
.tm_sec
, tv_now
.tv_usec
/ 1000);
402 (void)fwrite((const void *)CFDataGetBytePtr(line
), (size_t)CFDataGetLength(line
), 1, stream
);
404 (void)fputc('\n', stream
);
407 pthread_mutex_unlock(&lock
);
415 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
417 va_list formatArguments
;
423 va_start(formatArguments
, formatString
);
425 __SCLog(level
, formatString
, formatArguments
);
428 __SCPrint((LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
,
431 (_sc_log
> 0), // trace
432 TRUE
); // add newline
434 va_end(formatArguments
);
441 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
443 va_list formatArguments
;
449 va_start(formatArguments
, formatString
);
450 __SCPrint(stream
, formatString
, formatArguments
, FALSE
, FALSE
);
451 va_end(formatArguments
);
458 SCTrace(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
460 va_list formatArguments
;
466 va_start(formatArguments
, formatString
);
467 __SCPrint(stream
, formatString
, formatArguments
, TRUE
, FALSE
);
468 va_end(formatArguments
);
476 } __SCThreadSpecificData
, *__SCThreadSpecificDataRef
;
479 static pthread_once_t tsKeyInitialized
= PTHREAD_ONCE_INIT
;
480 static pthread_key_t tsDataKey
;
484 __SCThreadSpecificDataFinalize(void *arg
)
486 __SCThreadSpecificDataRef tsd
= (__SCThreadSpecificDataRef
)arg
;
490 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
496 __SCThreadSpecificKeyInitialize()
498 pthread_key_create(&tsDataKey
, __SCThreadSpecificDataFinalize
);
503 const CFStringRef kCFErrorDomainSystemConfiguration
= CFSTR("com.apple.SystemConfiguration");
507 _SCErrorSet(int error
)
509 __SCThreadSpecificDataRef tsd
;
511 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
513 tsd
= pthread_getspecific(tsDataKey
);
515 tsd
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__SCThreadSpecificData
), 0);
516 bzero(tsd
, sizeof(__SCThreadSpecificData
));
517 pthread_setspecific(tsDataKey
, tsd
);
520 tsd
->_sc_error
= error
;
526 SCCopyLastError(void)
532 __SCThreadSpecificDataRef tsd
;
533 CFMutableDictionaryRef userInfo
= NULL
;
535 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
537 tsd
= pthread_getspecific(tsDataKey
);
538 code
= tsd
? tsd
->_sc_error
: kSCStatusOK
;
540 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
541 if (sc_errmsgs
[i
].status
== code
) {
544 domain
= kCFErrorDomainSystemConfiguration
;
545 userInfo
= CFDictionaryCreateMutable(NULL
,
547 &kCFCopyStringDictionaryKeyCallBacks
,
548 &kCFTypeDictionaryValueCallBacks
);
549 str
= CFStringCreateWithCString(NULL
,
550 sc_errmsgs
[i
].message
,
551 kCFStringEncodingASCII
);
552 CFDictionarySetValue(userInfo
, kCFErrorDescriptionKey
, str
);
558 if ((code
> 0) && (code
<= ELAST
)) {
559 domain
= kCFErrorDomainPOSIX
;
563 domain
= kCFErrorDomainMach
;
567 error
= CFErrorCreate(NULL
, domain
, code
, userInfo
);
568 if (userInfo
!= NULL
) CFRelease(userInfo
);
576 __SCThreadSpecificDataRef tsd
;
578 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
580 tsd
= pthread_getspecific(tsDataKey
);
581 return tsd
? tsd
->_sc_error
: kSCStatusOK
;
586 SCErrorString(int status
)
590 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
591 if (sc_errmsgs
[i
].status
== status
) {
592 return sc_errmsgs
[i
].message
;
596 if ((status
> 0) && (status
<= ELAST
)) {
597 return strerror(status
);
600 if ((status
>= BOOTSTRAP_SUCCESS
) && (status
<= BOOTSTRAP_NO_MEMORY
)) {
601 return bootstrap_strerror(status
);
604 return mach_error_string(status
);