2 * Copyright (c) 2000-2003 Apple Computer, 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>
38 #include <SystemConfiguration/SystemConfiguration.h>
39 #include <SystemConfiguration/SCPrivate.h>
40 #include "SCDynamicStoreInternal.h"
41 #include "config.h" /* MiG generated file */
43 /* framework variables */
44 Boolean _sc_debug
= FALSE
; /* TRUE if debugging enabled */
45 Boolean _sc_verbose
= FALSE
; /* TRUE if verbose logging enabled */
46 Boolean _sc_log
= TRUE
; /* TRUE if SCLog() output goes to syslog */
48 static const struct sc_errmsg
{
52 { kSCStatusAccessError
, "Permission denied" },
53 { kSCStatusFailed
, "Failed!" },
54 { kSCStatusInvalidArgument
, "Invalid argument" },
55 { kSCStatusKeyExists
, "Key already defined" },
56 { kSCStatusLocked
, "Lock already held" },
57 { kSCStatusMaxLink
, "Maximum link count exceeded" },
58 { kSCStatusNeedLock
, "Lock required for this operation" },
59 { kSCStatusNoStoreServer
, "Configuration daemon not (no longer) available" },
60 { kSCStatusNoStoreSession
, "Configuration daemon session not active" },
61 { kSCStatusNoConfigFile
, "Configuration file not found" },
62 { kSCStatusNoKey
, "No such key" },
63 { kSCStatusNoLink
, "No such link" },
64 { kSCStatusNoPrefsSession
, "Preference session not active" },
65 { kSCStatusNotifierActive
, "Notifier is currently active" },
66 { kSCStatusOK
, "Success!" },
67 { kSCStatusPrefsBusy
, "Configuration daemon busy" },
68 { kSCStatusReachabilityUnknown
, "Network reachability cannot be determined" },
69 { kSCStatusStale
, "Write attempted on stale version of object" },
71 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
74 #define USE_SCCOPYDESCRIPTION
75 #ifdef USE_SCCOPYDESCRIPTION
77 // from <CoreFoundation/CFVeryPrivate.h>
78 extern CFStringRef
_CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc
, CFStringRef (*copyDescFunc
)(void *, CFDictionaryRef
), CFDictionaryRef formatOptions
, CFStringRef format
, va_list arguments
);
83 _SCCopyDescription(void *info
, CFDictionaryRef formatOptions
)
85 CFMutableDictionaryRef nFormatOptions
;
88 CFTypeID type
= CFGetTypeID(info
);
91 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX1"), (const void **)&prefix1
)) {
95 if (type
== CFStringGetTypeID()) {
96 return CFStringCreateWithFormat(NULL
,
103 if (type
== CFBooleanGetTypeID()) {
104 return CFStringCreateWithFormat(NULL
,
108 CFBooleanGetValue(info
) ? "TRUE" : "FALSE");
111 if (type
== CFDataGetTypeID()) {
115 CFMutableStringRef str
;
117 str
= CFStringCreateMutable(NULL
, 0);
118 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<data> 0x"), prefix1
);
120 data
= CFDataGetBytePtr(info
);
121 dataLen
= CFDataGetLength(info
);
122 for (i
= 0; i
< dataLen
; i
++) {
123 CFStringAppendFormat(str
, NULL
, CFSTR("%02x"), data
[i
]);
129 if (type
== CFNumberGetTypeID()) {
130 return CFStringCreateWithFormat(NULL
,
137 if (type
== CFDateGetTypeID()) {
138 CFGregorianDate gDate
;
142 tZone
= CFTimeZoneCopySystem();
143 gDate
= CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(info
), tZone
);
144 str
= CFStringCreateWithFormat(NULL
,
146 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
154 CFTimeZoneGetName(tZone
));
159 if (!formatOptions
||
160 !CFDictionaryGetValueIfPresent(formatOptions
, CFSTR("PREFIX2"), (const void **)&prefix2
)) {
161 prefix2
= CFStringCreateCopy(NULL
, prefix1
);
165 nFormatOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, formatOptions
);
167 nFormatOptions
= CFDictionaryCreateMutable(NULL
,
169 &kCFTypeDictionaryKeyCallBacks
,
170 &kCFTypeDictionaryValueCallBacks
);
173 if (type
== CFArrayGetTypeID()) {
174 const void * elements_q
[32];
175 const void ** elements
= elements_q
;
178 CFMutableStringRef str
;
180 str
= CFStringCreateMutable(NULL
, 0);
181 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<array> {"), prefix1
);
183 nElements
= CFArrayGetCount(info
);
185 if (nElements
> (CFIndex
)(sizeof(elements_q
)/sizeof(CFTypeRef
)))
186 elements
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
187 CFArrayGetValues(info
, CFRangeMake(0, nElements
), elements
);
188 for (i
= 0; i
< nElements
; i
++) {
189 CFMutableStringRef nPrefix1
;
190 CFMutableStringRef nPrefix2
;
194 nStr
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%u"), i
);
196 nPrefix1
= CFStringCreateMutable(NULL
, 0);
197 CFStringAppendFormat(nPrefix1
,
202 nPrefix2
= CFStringCreateMutable(NULL
, 0);
203 CFStringAppendFormat(nPrefix2
,
208 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
209 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
214 vStr
= _SCCopyDescription((void *)elements
[i
], nFormatOptions
);
215 CFStringAppendFormat(str
,
221 if (elements
!= elements_q
) CFAllocatorDeallocate(NULL
, elements
);
223 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
225 CFRelease(nFormatOptions
);
229 if (type
== CFDictionaryGetTypeID()) {
230 const void * keys_q
[N_QUICK
];
231 const void ** keys
= keys_q
;
234 CFMutableStringRef nPrefix1
;
235 CFMutableStringRef nPrefix2
;
236 CFMutableStringRef str
;
237 const void * values_q
[N_QUICK
];
238 const void ** values
= values_q
;
240 str
= CFStringCreateMutable(NULL
, 0);
241 CFStringAppendFormat(str
, formatOptions
, CFSTR("%@<dictionary> {"), prefix1
);
243 nElements
= CFDictionaryGetCount(info
);
245 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
246 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
247 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
249 CFDictionaryGetKeysAndValues(info
, keys
, values
);
250 for (i
= 0; i
< nElements
; i
++) {
254 kStr
= _SCCopyDescription((void *)keys
[i
], NULL
);
256 nPrefix1
= CFStringCreateMutable(NULL
, 0);
257 CFStringAppendFormat(nPrefix1
,
262 nPrefix2
= CFStringCreateMutable(NULL
, 0);
263 CFStringAppendFormat(nPrefix2
,
268 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX1"), nPrefix1
);
269 CFDictionarySetValue(nFormatOptions
, CFSTR("PREFIX2"), nPrefix2
);
274 vStr
= _SCCopyDescription((void *)values
[i
], nFormatOptions
);
275 CFStringAppendFormat(str
,
281 if (keys
!= keys_q
) {
282 CFAllocatorDeallocate(NULL
, keys
);
283 CFAllocatorDeallocate(NULL
, values
);
286 CFStringAppendFormat(str
, formatOptions
, CFSTR("\n%@}"), prefix2
);
288 CFRelease(nFormatOptions
);
292 CFRelease(nFormatOptions
);
298 cfStr
= CFCopyDescription(info
);
299 str
= CFStringCreateWithFormat(NULL
,
309 #endif /* USE_SCCOPYDESCRIPTION */
312 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
316 __SCLog(int level
, CFStringRef formatString
, va_list formatArguments
)
321 #ifdef USE_SCCOPYDESCRIPTION
322 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
327 #else /* USE_SCCOPYDESCRIPTION */
328 str
= CFStringCreateWithFormatAndArguments (NULL
,
332 #endif /* !USE_SCCOPYDESCRIPTION */
334 lines
= CFStringCreateArrayBySeparatingStrings(NULL
, str
, CFSTR("\n"));
339 int n
= CFArrayGetCount(lines
);
341 pthread_mutex_lock(&lock
);
342 for (i
= 0; i
< n
; i
++) {
345 line
= CFStringCreateExternalRepresentation(NULL
,
346 CFArrayGetValueAtIndex(lines
, i
),
347 kCFStringEncodingMacRoman
,
350 syslog (level
, "%.*s", (int)CFDataGetLength(line
), CFDataGetBytePtr(line
));
354 pthread_mutex_unlock(&lock
);
363 __SCPrint(FILE *stream
, CFStringRef formatString
, va_list formatArguments
, Boolean trace
, Boolean addNL
)
368 #ifdef USE_SCCOPYDESCRIPTION
369 str
= _CFStringCreateWithFormatAndArgumentsAux(NULL
,
374 #else /* USE_SCCOPYDESCRIPTION */
375 str
= CFStringCreateWithFormatAndArguments (NULL
,
379 #endif /* !USE_SCCOPYDESCRIPTION */
381 line
= CFStringCreateExternalRepresentation(NULL
,
383 kCFStringEncodingMacRoman
,
390 pthread_mutex_lock(&lock
);
392 time_t now
= time(NULL
);
395 (void)localtime_r(&now
, &tm
);
396 fprintf(stream
, "%2d:%02d:%02d %.*s%s",
397 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
,
398 (int)CFDataGetLength(line
), CFDataGetBytePtr(line
),
401 fprintf(stream
, "%.*s%s",
402 (int)CFDataGetLength(line
), CFDataGetBytePtr(line
),
406 pthread_mutex_unlock(&lock
);
414 SCLog(Boolean condition
, int level
, CFStringRef formatString
, ...)
416 va_list formatArguments
;
422 va_start(formatArguments
, formatString
);
424 __SCLog(level
, formatString
, formatArguments
);
426 __SCPrint((LOG_PRI(level
) > LOG_NOTICE
) ? stderr
: stdout
,
430 TRUE
); // add newline
432 va_end(formatArguments
);
439 SCPrint(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
441 va_list formatArguments
;
447 va_start(formatArguments
, formatString
);
448 __SCPrint(stream
, formatString
, formatArguments
, FALSE
, FALSE
);
449 va_end(formatArguments
);
456 SCTrace(Boolean condition
, FILE *stream
, CFStringRef formatString
, ...)
458 va_list formatArguments
;
464 va_start(formatArguments
, formatString
);
465 __SCPrint(stream
, formatString
, formatArguments
, TRUE
, FALSE
);
466 va_end(formatArguments
);
474 } __SCThreadSpecificData
, *__SCThreadSpecificDataRef
;
477 static pthread_once_t tsKeyInitialized
= PTHREAD_ONCE_INIT
;
478 static pthread_key_t tsDataKey
;
482 __SCThreadSpecificDataFinalize(void *arg
)
484 __SCThreadSpecificDataRef tsd
= (__SCThreadSpecificDataRef
)arg
;
488 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
494 __SCThreadSpecificKeyInitialize()
496 pthread_key_create(&tsDataKey
, __SCThreadSpecificDataFinalize
);
502 _SCErrorSet(int error
)
504 __SCThreadSpecificDataRef tsd
;
506 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
508 tsd
= pthread_getspecific(tsDataKey
);
510 tsd
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__SCThreadSpecificData
), 0);
511 bzero(tsd
, sizeof(__SCThreadSpecificData
));
512 pthread_setspecific(tsDataKey
, tsd
);
515 tsd
->_sc_error
= error
;
523 __SCThreadSpecificDataRef tsd
;
525 pthread_once(&tsKeyInitialized
, __SCThreadSpecificKeyInitialize
);
527 tsd
= pthread_getspecific(tsDataKey
);
528 return tsd
? tsd
->_sc_error
: kSCStatusOK
;
533 SCErrorString(int status
)
537 for (i
= 0; i
< (int)nSC_ERRMSGS
; i
++) {
538 if (sc_errmsgs
[i
].status
== status
) {
539 return sc_errmsgs
[i
].message
;
543 if ((status
> 0) && (status
<= ELAST
)) {
544 return strerror(status
);
547 return mach_error_string(status
);