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
);