2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * June 1, 2001 Allan Nathanson <ajn@apple.com>
27 * - public API conversion
29 * March 24, 2000 Allan Nathanson <ajn@apple.com>
33 #include <mach/mach.h>
34 #include <mach/mach_error.h>
37 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCPrivate.h>
39 #include "SCDynamicStoreInternal.h"
40 #include "config.h" /* MiG generated file */
42 /* framework variables */
43 Boolean _sc_debug
= FALSE
; /* TRUE if debugging enabled */
44 Boolean _sc_verbose
= FALSE
; /* TRUE if verbose logging enabled */
45 Boolean _sc_log
= TRUE
; /* TRUE if SCLog() output goes to syslog */
47 static const struct sc_errmsg
{
51 { kSCStatusAccessError
, "Permission denied" },
52 { kSCStatusFailed
, "Failed!" },
53 { kSCStatusInvalidArgument
, "Invalid argument" },
54 { kSCStatusKeyExists
, "Key already defined" },
55 { kSCStatusLocked
, "Lock already held" },
56 { kSCStatusNeedLock
, "Lock required for this operation" },
57 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
58 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
59 { kSCStatusNoConfigFile
, "Configuration file not found" },
60 { kSCStatusNoKey
, "No such key" },
61 { kSCStatusNoLink
, "No such link" },
62 { kSCStatusNoPrefsSession
, "Preference session not active" },
63 { kSCStatusNotifierActive
, "Notifier is currently active" },
64 { kSCStatusOK
, "Success!" },
65 { kSCStatusPrefsBusy
, "Configuration daemon busy" },
66 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
67 { kSCStatusStale
, "Write attempted on stale version of object" },
69 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
72 #define USE_SCCOPYDESCRIPTION
73 #ifdef USE_SCCOPYDESCRIPTION
75 // from <CoreFoundation/CFVeryPrivate.h>
76 extern CFStringRef
_CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc
, CFStringRef (*copyDescFunc
)(void *, CFDictionaryRef
), CFDictionaryRef formatOptions
, CFStringRef format
, va_list arguments
);
79 _SCCopyDescription(void *info
, CFDictionaryRef formatOptions
)
81 CFMutableDictionaryRef nFormatOptions
;
84 CFTypeID type
= CFGetTypeID(info
);
87 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX1"), (void **)&prefix1
)) {
91 if (type
== CFStringGetTypeID()) {
92 return CFStringCreateWithFormat(NULL
,
99 if (type
== CFBooleanGetTypeID()) {
100 return CFStringCreateWithFormat(NULL
,
104 CFBooleanGetValue(info
) ? "TRUE" : "FALSE");
107 if (type
== CFDataGetTypeID()) {
108 const u_int8_t
*data
;
111 CFMutableStringRef str
;
113 str
= CFStringCreateMutable(NULL
, 0);
114 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<data> 0x"), prefix1
);
116 data
= CFDataGetBytePtr(info
);
117 dataLen
= CFDataGetLength(info
);
118 for (i
= 0; i
< dataLen
; i
++) {
119 CFStringAppendFormat(str
, NULL
, CFSTR("%02x"), data
[i
]);
125 if (type
== CFNumberGetTypeID()) {
126 return CFStringCreateWithFormat(NULL
,
133 if (type
== CFDateGetTypeID()) {
134 CFGregorianDate gDate
;
138 tZone
= CFTimeZoneCopySystem();
139 gDate
= CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(info
), tZone
);
140 str
= CFStringCreateWithFormat(NULL
,
142 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
150 CFTimeZoneGetName(tZone
));
155 if (!formatOptions
||
156 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX2"), (void **)&prefix2
)) {
157 prefix2
= CFStringCreateCopy(NULL
, prefix1
);
161 nFormatOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, formatOptions
);
163 nFormatOptions
= CFDictionaryCreateMutable(NULL
,
165 &kCFTypeDictionaryKeyCallBacks
,
166 &kCFTypeDictionaryValueCallBacks
);
169 if (type
== CFArrayGetTypeID()) {
173 CFMutableStringRef str
;
175 str
= CFStringCreateMutable(NULL
, 0);
176 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<array> {"), prefix1
);
178 nElements
= CFArrayGetCount(info
);
179 elements
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
180 CFArrayGetValues(info
, CFRangeMake(0, nElements
), elements
);
181 for (i
=0; i
<nElements
; i
++) {
182 CFMutableStringRef nPrefix1
;
183 CFMutableStringRef nPrefix2
;
187 nStr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%u"), i
);
189 nPrefix1
= CFStringCreateMutable(NULL
, 0);
190 CFStringAppendFormat(nPrefix1
,
195 nPrefix2
= CFStringCreateMutable(NULL
, 0);
196 CFStringAppendFormat(nPrefix2
,
201 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
202 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
207 vStr
= _SCCopyDescription(elements
[i
], nFormatOptions
);
208 CFStringAppendFormat(str
,
214 CFAllocatorDeallocate(NULL
, elements
);
215 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
217 CFRelease(nFormatOptions
);
221 if (type
== CFDictionaryGetTypeID()) {
225 CFMutableStringRef nPrefix1
;
226 CFMutableStringRef nPrefix2
;
227 CFMutableStringRef str
;
230 str
= CFStringCreateMutable(NULL
, 0);
231 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
233 nElements
= CFDictionaryGetCount(info
);
234 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
235 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
236 CFDictionaryGetKeysAndValues(info
, keys
, values
);
237 for (i
=0; i
<nElements
; i
++) {
241 kStr
= _SCCopyDescription(keys
[i
], NULL
);
243 nPrefix1
= CFStringCreateMutable(NULL
, 0);
244 CFStringAppendFormat(nPrefix1
,
249 nPrefix2
= CFStringCreateMutable(NULL
, 0);
250 CFStringAppendFormat(nPrefix2
,
255 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
256 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
261 vStr
= _SCCopyDescription(values
[i
], nFormatOptions
);
262 CFStringAppendFormat(str
,
268 CFAllocatorDeallocate(NULL
, keys
);
269 CFAllocatorDeallocate(NULL
, values
);
270 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
272 CFRelease(nFormatOptions
);
280 cfStr
= CFCopyDescription(info
);
281 str
= CFStringCreateWithFormat(NULL
,
291 #endif /* USE_SCCOPYDESCRIPTION */
294 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
297 __private_extern__
void
298 __SCLog(int level
, CFStringRef str
)
302 lines
= CFStringCreateArrayBySeparatingStrings(NULL
, str
, CFSTR("\n"));
306 pthread_mutex_lock(&lock
);
307 for (i
=0; i
<CFArrayGetCount(lines
); i
++) {
310 line
= CFStringCreateExternalRepresentation(NULL
,
311 CFArrayGetValueAtIndex(lines
, i
),
312 kCFStringEncodingMacRoman
,
315 syslog (level
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
319 pthread_mutex_unlock(&lock
);
327 __private_extern__
void
328 __SCPrint(FILE *stream
, CFStringRef str
)
332 line
= CFStringCreateExternalRepresentation(NULL
,
334 kCFStringEncodingMacRoman
,
337 pthread_mutex_lock(&lock
);
338 fprintf(stream
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
340 pthread_mutex_unlock(&lock
);
349 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
352 CFStringRef resultString
;
358 va_start(argList
, formatString
);
359 #ifdef USE_SCCOPYDESCRIPTION
360 resultString
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
365 #else /* USE_SCCOPYDESCRIPTION */
366 resultString
= CFStringCreateWithFormatAndArguments(NULL
, NULL
, formatString
, argList
);
367 #endif /* !USE_SCCOPYDESCRIPTION */
371 __SCLog(level
, resultString
);
373 FILE *f
= (LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
;
374 CFStringRef newString
;
377 newString
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@\n"), resultString
);
378 __SCPrint(f
, newString
);
379 CFRelease(newString
);
381 CFRelease(resultString
);
387 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
390 CFStringRef resultString
;
396 va_start(argList
, formatString
);
397 #ifdef USE_SCCOPYDESCRIPTION
398 resultString
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
403 #else /* USE_SCCOPYDESCRIPTION */
404 resultString
= CFStringCreateWithFormatAndArguments(NULL
, NULL
, formatString
, argList
);
405 #endif /* !USE_SCCOPYDESCRIPTION */
408 __SCPrint(stream
, resultString
);
409 CFRelease(resultString
);
416 } __SCThreadSpecificData
, *__SCThreadSpecificDataRef
;
419 static pthread_once_t tsKeyInitialized
= PTHREAD_ONCE_INIT
;
420 static pthread_key_t tsDataKey
= NULL
;
424 __SCThreadSpecificDataFinalize(void *arg
)
426 __SCThreadSpecificDataRef tsd
= (__SCThreadSpecificDataRef
)arg
;
430 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
436 __SCThreadSpecificKeyInitialize()
438 pthread_key_create(&tsDataKey
, __SCThreadSpecificDataFinalize
);
444 _SCErrorSet(int error
)
446 __SCThreadSpecificDataRef tsd
;
448 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
450 tsd
= pthread_getspecific(tsDataKey
);
452 tsd
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__SCThreadSpecificData
), 0);
453 bzero(tsd
, sizeof(__SCThreadSpecificData
));
454 pthread_setspecific(tsDataKey
, tsd
);
457 tsd
->_sc_error
= error
;
465 __SCThreadSpecificDataRef tsd
;
467 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
469 tsd
= pthread_getspecific(tsDataKey
);
470 return tsd
? tsd
->_sc_error
: kSCStatusOK
;
475 SCErrorString(int status
)
479 for (i
= 0; i
< nSC_ERRMSGS
; i
++) {
480 if (sc_errmsgs
[i
].status
== status
) {
481 return sc_errmsgs
[i
].message
;
485 if ((status
> 0) && (status
<= ELAST
)) {
486 return strerror(status
);
489 return mach_error_string(status
);