/* * Copyright (c) 2000-2008, 2010-2014 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Modification History * * June 1, 2001 Allan Nathanson * - public API conversion * * March 24, 2000 Allan Nathanson * - initial revision */ #include #include #include #include #include #include #include #include #include "SCD.h" #include "SCDynamicStoreInternal.h" #include "config.h" /* MiG generated file */ // LIBASL SPI extern asl_object_t _asl_server_control_query(void); /* framework variables */ int _sc_debug = FALSE; /* non-zero if debugging enabled */ int _sc_verbose = FALSE; /* non-zero if verbose logging enabled */ int _sc_log = TRUE; /* 0 if SC messages should be written to stdout/stderr, 1 if SC messages should be logged w/asl(3), 2 if SC messages should be written to stdout/stderr AND logged */ #pragma mark - #pragma mark Thread specific data static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT; static pthread_key_t tsDataKey; static void __SCThreadSpecificDataFinalize(void *arg) { __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg; if (tsd != NULL) { if (tsd->_asl != NULL) asl_release(tsd->_asl); if (tsd->_sc_store != NULL) CFRelease(tsd->_sc_store); CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd); } return; } static void __SCThreadSpecificKeyInitialize() { pthread_key_create(&tsDataKey, __SCThreadSpecificDataFinalize); return; } __private_extern__ __SCThreadSpecificDataRef __SCGetThreadSpecificData() { __SCThreadSpecificDataRef tsd; pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize); tsd = pthread_getspecific(tsDataKey); if (tsd == NULL) { tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0); tsd->_asl = NULL; tsd->_sc_error = kSCStatusOK; tsd->_sc_store = NULL; pthread_setspecific(tsDataKey, tsd); } return tsd; } #pragma mark - #pragma mark Logging #define kASLModule "ASLModule" #define kASLOption "ASLOption" #define kLoggerID "LoggerID" #define ENABLE_SC_FORMATTING #ifdef ENABLE_SC_FORMATTING // from extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(CFTypeRef, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments); #endif /* ENABLE_SC_FORMATTING */ CFStringRef _SCCopyDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { #ifdef ENABLE_SC_FORMATTING CFMutableDictionaryRef nFormatOptions; CFStringRef prefix1; CFStringRef prefix2; CFTypeID type = CFGetTypeID(cf); if (!formatOptions || !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) { prefix1 = CFSTR(""); } if (type == CFStringGetTypeID()) { return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%@"), prefix1, cf); } if (type == CFBooleanGetTypeID()) { return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%s"), prefix1, CFBooleanGetValue(cf) ? "TRUE" : "FALSE"); } if (type == CFDataGetTypeID()) { const uint8_t *data; CFIndex dataLen; CFIndex i; CFMutableStringRef str; str = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(str, formatOptions, CFSTR("%@ 0x"), prefix1); data = CFDataGetBytePtr(cf); dataLen = CFDataGetLength(cf); for (i = 0; i < dataLen; i++) { CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]); } return str; } if (type == CFNumberGetTypeID()) { return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%@"), prefix1, cf); } if (type == CFDateGetTypeID()) { CFCalendarRef calendar; CFStringRef str; CFTimeZoneRef tz; int MM, DD, YYYY, hh, mm, ss; calendar = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar); tz = CFTimeZoneCopySystem(); CFCalendarSetTimeZone(calendar, tz); CFRelease(tz); CFCalendarDecomposeAbsoluteTime(calendar, CFDateGetAbsoluteTime(cf), "MdyHms", &MM, &DD, &YYYY, &hh, &mm, &ss); CFRelease(calendar); str = CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"), prefix1, MM, DD, YYYY, hh, mm, ss); return str; } if ((formatOptions == NULL) || !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) { prefix2 = prefix1; } if (formatOptions != NULL) { nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions); } else { nFormatOptions = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } assert(nFormatOptions != NULL); #define N_QUICK 32 if (type == CFArrayGetTypeID()) { const void * elements_q[N_QUICK]; const void ** elements = elements_q; CFIndex i; CFIndex nElements; CFMutableStringRef str; str = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(str, formatOptions, CFSTR("%@ {"), prefix1); nElements = CFArrayGetCount(cf); if (nElements > 0) { if (nElements > (CFIndex)(sizeof(elements_q)/sizeof(CFTypeRef))) elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); CFArrayGetValues(cf, CFRangeMake(0, nElements), elements); for (i = 0; i < nElements; i++) { CFMutableStringRef nPrefix1; CFMutableStringRef nPrefix2; CFStringRef nStr; CFStringRef vStr; nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"), i); nPrefix1 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix1, formatOptions, CFSTR("%@ %@ : "), prefix2, nStr); nPrefix2 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix2, formatOptions, CFSTR("%@ "), prefix2); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2); CFRelease(nPrefix1); CFRelease(nPrefix2); CFRelease(nStr); vStr = _SCCopyDescription((CFTypeRef)elements[i], nFormatOptions); CFStringAppendFormat(str, formatOptions, CFSTR("\n%@"), vStr); CFRelease(vStr); } if (elements != elements_q) CFAllocatorDeallocate(NULL, elements); } CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2); CFRelease(nFormatOptions); return str; } if (type == CFDictionaryGetTypeID()) { const void * keys_q[N_QUICK]; const void ** keys = keys_q; CFIndex i; CFIndex nElements; CFMutableStringRef nPrefix1; CFMutableStringRef nPrefix2; CFMutableStringRef str; str = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(str, formatOptions, CFSTR("%@ {"), prefix1); nElements = CFDictionaryGetCount(cf); if (nElements > 0) { CFComparatorFunction compFunc = NULL; CFMutableArrayRef sortedKeys; if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); } CFDictionaryGetKeysAndValues(cf, keys, NULL); sortedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); for (i = 0; i < nElements; i++) { CFArrayAppendValue(sortedKeys, (CFStringRef)keys[i]); } if (isA_CFString(keys[0])) { compFunc = (CFComparatorFunction)CFStringCompare; } else if (isA_CFNumber(keys[0])) { compFunc = (CFComparatorFunction)CFNumberCompare; } else if (isA_CFDate(keys[0])) { compFunc = (CFComparatorFunction)CFDateCompare; } if (compFunc != NULL) { CFArraySortValues(sortedKeys, CFRangeMake(0, nElements), compFunc, NULL); } for (i = 0; i < nElements; i++) { CFStringRef key; CFStringRef kStr; CFTypeRef val; CFStringRef vStr; key = CFArrayGetValueAtIndex(sortedKeys, i); kStr = _SCCopyDescription((CFTypeRef)key, NULL); nPrefix1 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix1, formatOptions, CFSTR("%@ %@ : "), prefix2, kStr); nPrefix2 = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(nPrefix2, formatOptions, CFSTR("%@ "), prefix2); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1); CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2); CFRelease(nPrefix1); CFRelease(nPrefix2); CFRelease(kStr); val = CFDictionaryGetValue(cf, key); vStr = _SCCopyDescription((CFTypeRef)val, nFormatOptions); CFStringAppendFormat(str, formatOptions, CFSTR("\n%@"), vStr); CFRelease(vStr); } CFRelease(sortedKeys); if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); } } CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2); CFRelease(nFormatOptions); return str; } CFRelease(nFormatOptions); #endif /* ENABLE_SC_FORMATTING */ return CFStringCreateWithFormat(NULL, formatOptions, CFSTR("%@%@"), prefix1, cf); } static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; __private_extern__ Boolean is_install_environment() { static dispatch_once_t once; static Boolean is_install; dispatch_once(&once, ^{ is_install = (getenv(INSTALL_ENVIRONMENT) != NULL); }); return is_install; } static void __SCLog(asl_object_t asl, asl_object_t msg, int level, CFStringRef formatString, va_list formatArguments) { CFDataRef line; CFArrayRef lines; CFStringRef str; if (asl == NULL) { __SCThreadSpecificDataRef tsd; tsd = __SCGetThreadSpecificData(); if (tsd->_asl == NULL) { tsd->_asl = asl_open(NULL, (is_install_environment() ? INSTALL_FACILITY : NULL), 0); asl_set_filter(tsd->_asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); } asl = tsd->_asl; } #ifdef ENABLE_SC_FORMATTING str = _CFStringCreateWithFormatAndArgumentsAux(NULL, _SCCopyDescription, NULL, formatString, formatArguments); #else /* ENABLE_SC_FORMATTING */ str = CFStringCreateWithFormatAndArguments (NULL, NULL, formatString, formatArguments); #endif /* !ENABLE_SC_FORMATTING */ if (level >= 0) { lines = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR("\n")); if (lines != NULL) { CFIndex i; CFIndex n = CFArrayGetCount(lines); for (i = 0; i < n; i++) { line = CFStringCreateExternalRepresentation(NULL, CFArrayGetValueAtIndex(lines, i), kCFStringEncodingUTF8, (UInt8)'?'); if (line) { asl_log(asl, msg, level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line)); CFRelease(line); } } CFRelease(lines); } } else { line = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, (UInt8)'?'); if (line) { asl_log(asl, msg, ~level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line)); CFRelease(line); } } CFRelease(str); return; } static void __SCPrint(FILE *stream, CFStringRef formatString, va_list formatArguments, Boolean trace, Boolean addNL) { CFDataRef line; CFStringRef str; #ifdef ENABLE_SC_FORMATTING str = _CFStringCreateWithFormatAndArgumentsAux(NULL, _SCCopyDescription, NULL, formatString, formatArguments); #else /* ENABLE_SC_FORMATTING */ str = CFStringCreateWithFormatAndArguments (NULL, NULL, formatString, formatArguments); #endif /* !ENABLE_SC_FORMATTING */ line = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, (UInt8)'?'); CFRelease(str); if (!line) { return; } pthread_mutex_lock(&lock); if (trace) { struct tm tm_now; struct timeval tv_now; (void)gettimeofday(&tv_now, NULL); (void)localtime_r(&tv_now.tv_sec, &tm_now); (void)fprintf(stream, "%2d:%02d:%02d.%03d ", tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000); } (void)fwrite((const void *)CFDataGetBytePtr(line), (size_t)CFDataGetLength(line), 1, stream); if (addNL) { (void)fputc('\n', stream); } fflush (stream); pthread_mutex_unlock(&lock); CFRelease(line); return; } void SCLog(Boolean condition, int level, CFStringRef formatString, ...) { va_list formatArguments; va_list formatArguments_print; Boolean log = FALSE; Boolean print = FALSE; if (!condition) { return; } /* * Note: The following are the expected values for _sc_log * * 0 if SC messages should be written to stdout/stderr * 1 if SC messages should be logged w/asl(3) * 2 if SC messages should be written to stdout/stderr AND logged */ if (_sc_log > 0) { log = TRUE; // log requested va_start(formatArguments, formatString); if (_sc_log > 1) { print = TRUE; // log AND print requested va_copy(formatArguments_print, formatArguments); } } else { print = TRUE; // print requested va_start(formatArguments_print, formatString); } if (log) { __SCLog(NULL, NULL, level, formatString, formatArguments); va_end(formatArguments); } if (print) { __SCPrint((LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout, formatString, formatArguments_print, (_sc_log > 0), // trace TRUE); // add newline va_end(formatArguments_print); } return; } void SCLOG(asl_object_t asl, asl_object_t msg, int level, CFStringRef formatString, ...) { va_list formatArguments; va_list formatArguments_print; Boolean log = FALSE; Boolean print = FALSE; /* * Note: The following are the expected values for _sc_log * * 0 if SC messages should be written to stdout/stderr * 1 if SC messages should be logged w/asl(3) * 2 if SC messages should be written to stdout/stderr AND logged */ if (_sc_log > 0) { log = TRUE; // log requested va_start(formatArguments, formatString); if (_sc_log > 1) { print = TRUE; // log AND print requested va_copy(formatArguments_print, formatArguments); } } else { print = TRUE; // print requested va_start(formatArguments_print, formatString); } if (log) { __SCLog(asl, msg, level, formatString, formatArguments); va_end(formatArguments); } if (print) { if (level < 0) { level = ~level; } __SCPrint((level > ASL_LEVEL_NOTICE) ? stderr : stdout, formatString, formatArguments_print, (_sc_log > 0), // trace TRUE); // add newline va_end(formatArguments_print); } return; } void SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...) { va_list formatArguments; if (!condition) { return; } va_start(formatArguments, formatString); __SCPrint(stream, formatString, formatArguments, FALSE, FALSE); va_end(formatArguments); return; } void SCTrace(Boolean condition, FILE *stream, CFStringRef formatString, ...) { va_list formatArguments; if (!condition) { return; } va_start(formatArguments, formatString); __SCPrint(stream, formatString, formatArguments, TRUE, FALSE); va_end(formatArguments); return; } #pragma mark - #pragma mark ASL Functions static CFTypeID __kSCLoggerTypeID = _kCFRuntimeNotATypeID; typedef enum { kModuleStatusEnabled, kModuleStatusDisabled, kModuleStatusDoesNotExist } ModuleStatus; struct SCLogger { CFRuntimeBase cf_base; char * loggerID; // LoggerID SCLoggerFlags flags; asl_object_t aslc; asl_object_t aslm; ModuleStatus module_status; pthread_mutex_t lock; }; static void __SCLoggerDeallocate(CFTypeRef cf); static const CFRuntimeClass __SCLoggerClass = { 0, /* version */ "SCLogger", /* className */ NULL, /* init */ NULL, /* copy */ __SCLoggerDeallocate, /* deallocate */ NULL, /* equal */ NULL, /* hash */ NULL, /* copyFormattingDesc */ NULL /* copyDebugDesc */ }; #define DATETIMEBUFFERSIZE 32 static pthread_once_t registerLoggerOnce = PTHREAD_ONCE_INIT; static pthread_once_t defaultLoggerOnce = PTHREAD_ONCE_INIT; typedef enum { kLoggerASLControlEnableModule, kLoggerASLControlDisableModule, kLoggerASLControlLogFileCheckpoint } LoggerASLControl; static SCLoggerRef defaultLogger = NULL; static SCLoggerRef __SCLoggerCreate(void); static void __SCLoggerDefaultLoggerInit(); static SCLoggerRef SCLoggerGetDefaultLogger(); static void SCLoggerSetLoggerID(SCLoggerRef logger, CFStringRef loggerID); static void SCLoggerSendMessageToModuleOnly(SCLoggerRef logger, Boolean isPrivate); static void SCLoggerSendASLControl(SCLoggerRef logger, LoggerASLControl control); static ModuleStatus GetModuleStatus(const char * loggerID); static void __SCLoggerRegisterClass(void) { if (__kSCLoggerTypeID == _kCFRuntimeNotATypeID) { __kSCLoggerTypeID = _CFRuntimeRegisterClass(&__SCLoggerClass); } return; } static SCLoggerRef __SCLoggerAllocate(CFAllocatorRef allocator) { SCLoggerRef state; int size; pthread_once(®isterLoggerOnce, __SCLoggerRegisterClass); size = sizeof(*state) - sizeof(CFRuntimeBase); state = (SCLoggerRef) _CFRuntimeCreateInstance(allocator, __kSCLoggerTypeID, size, NULL); bzero((void*)state + sizeof(CFRuntimeBase), size); return (state); } static void __SCLoggerDeallocate(CFTypeRef cf) { SCLoggerRef logger = (SCLoggerRef)cf; if (logger != NULL) { // Rotate on close behavior if (logger->module_status != kModuleStatusDoesNotExist) { SCLoggerSendASLControl(logger, kLoggerASLControlLogFileCheckpoint); } if (logger->loggerID != NULL) { CFAllocatorDeallocate(NULL, logger->loggerID); logger->loggerID = NULL; } if (logger->aslm != NULL) { asl_release(logger->aslm); logger->aslm = NULL; } if (logger->aslc != NULL) { asl_release(logger->aslc); logger->aslc = NULL; } } } static SCLoggerRef __SCLoggerCreate(void) { SCLoggerRef tempLogger = NULL; tempLogger = __SCLoggerAllocate(kCFAllocatorDefault); tempLogger->loggerID = NULL; tempLogger->flags = kSCLoggerFlagsDefault; tempLogger->aslc = asl_open(NULL, (is_install_environment() ? INSTALL_FACILITY : NULL), ASL_OPT_NO_DELAY); tempLogger->aslm = asl_new(ASL_TYPE_MSG); pthread_mutex_init(&(tempLogger->lock), NULL); tempLogger->module_status = kModuleStatusDoesNotExist; return tempLogger; } SCLoggerFlags SCLoggerGetFlags(SCLoggerRef logger) { return logger->flags; } void SCLoggerSetFlags(SCLoggerRef logger, SCLoggerFlags flags) { if (logger == defaultLogger) { return; } pthread_mutex_lock(&(logger->lock)); if (flags != kSCLoggerFlagsNone) { logger->module_status = GetModuleStatus(logger->loggerID); if (logger->module_status == kModuleStatusDoesNotExist) { goto done; } if ((flags & kSCLoggerFlagsFile) != 0) { if ((logger->flags & kSCLoggerFlagsFile) == 0) { // Enable the module if disabled if (logger->module_status == kModuleStatusDisabled) { SCLoggerSendASLControl(logger, kLoggerASLControlEnableModule); } // Setting ASL Filter level to debug asl_set_filter(logger->aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); if (logger->loggerID != NULL) { asl_set(logger->aslm, kLoggerID, logger->loggerID); } } } else if ((logger->flags & kSCLoggerFlagsFile) != 0) { asl_unset(logger->aslm, kLoggerID); asl_set_filter(logger->aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE)); SCLoggerSendMessageToModuleOnly(logger, false); } if ((flags & kSCLoggerFlagsDefault) != 0) { if ((logger->flags & kSCLoggerFlagsDefault) == 0) { SCLoggerSendMessageToModuleOnly(logger, false); } } else if ((logger->flags & kSCLoggerFlagsDefault) != 0) { SCLoggerSendMessageToModuleOnly(logger, true); } } logger->flags = flags; done: pthread_mutex_unlock(&(logger->lock)); } static void SCLoggerSetLoggerID(SCLoggerRef logger, CFStringRef loggerID) { logger->loggerID = _SC_cfstring_to_cstring(loggerID, NULL, 0, kCFStringEncodingUTF8); // Enable the module if disabled logger->module_status = GetModuleStatus(logger->loggerID); if (logger->module_status == kModuleStatusDisabled) { SCLoggerSendASLControl(logger, kLoggerASLControlEnableModule); } } static ModuleStatus GetModuleStatus(const char * loggerID) { ModuleStatus moduleStatus = kModuleStatusDoesNotExist; asl_object_t response = NULL; const char* value = NULL; if (loggerID != NULL) { response = _asl_server_control_query(); if (response == NULL) { goto done; } value = asl_get(response, loggerID); if (value == NULL) { moduleStatus = kModuleStatusDoesNotExist; goto done; } if (strcmp(value, "enabled") == 0) { moduleStatus = kModuleStatusEnabled; } else { moduleStatus = kModuleStatusDisabled; } } done: asl_release(response); return moduleStatus; } static void SCLoggerSendMessageToModuleOnly(SCLoggerRef logger, Boolean isPrivate) { if (isPrivate) { asl_set(logger->aslm, kASLModule, logger->loggerID); } else { if (asl_get(logger->aslm, kASLModule) != NULL) { asl_unset(logger->aslm, kASLModule); } } } static void SCLoggerSendASLControl(SCLoggerRef logger, LoggerASLControl control) { SCLoggerRef defLogger = SCLoggerGetDefaultLogger(); pthread_mutex_lock(&(defLogger->lock)); // this next line turns the asl_log()'s that follow into control messages asl_set(defLogger->aslm, kASLOption, "control"); switch (control) { case kLoggerASLControlEnableModule: asl_log(defLogger->aslc, defLogger->aslm, ASL_LEVEL_NOTICE, "@ %s enable 1", logger->loggerID); break; case kLoggerASLControlDisableModule: asl_log(defLogger->aslc, defLogger->aslm, ASL_LEVEL_NOTICE, "@ %s enable 0", logger->loggerID); break; case kLoggerASLControlLogFileCheckpoint: asl_log(defLogger->aslc, defLogger->aslm, ASL_LEVEL_NOTICE, "@ %s checkpoint", logger->loggerID); break; default: break; } // turn off control mode asl_unset(defLogger->aslm, kASLOption); pthread_mutex_unlock(&defLogger->lock); return; } SCLoggerRef SCLoggerCreate(CFStringRef loggerID) { SCLoggerRef logger = NULL; logger = __SCLoggerCreate(); if (loggerID != NULL) { SCLoggerSetLoggerID(logger, loggerID); } SCLoggerSetFlags(logger, kSCLoggerFlagsDefault); return logger; } static void __SCLoggerDefaultLoggerInit() { if (defaultLogger == NULL) { defaultLogger = __SCLoggerCreate(); defaultLogger->flags = kSCLoggerFlagsDefault; } } static SCLoggerRef SCLoggerGetDefaultLogger() { pthread_once(&defaultLoggerOnce, __SCLoggerDefaultLoggerInit); return defaultLogger; } void SCLoggerVLog(SCLoggerRef logger, int loglevel, CFStringRef formatString, va_list args) { asl_object_t aslc; asl_object_t aslm; if (logger == NULL || logger->module_status == kModuleStatusDoesNotExist) { logger = SCLoggerGetDefaultLogger(); } pthread_mutex_lock(&(logger->lock)); if (logger->flags == kSCLoggerFlagsNone) { pthread_mutex_unlock(&(logger->lock)); return; } aslc = logger->aslc; aslm = logger->aslm; __SCLog(aslc, aslm, loglevel, formatString, args); pthread_mutex_unlock(&(logger->lock)); return; } void SCLoggerLog(SCLoggerRef logger, int loglevel, CFStringRef formatString, ...) { va_list args; va_start(args, formatString); SCLoggerVLog(logger, loglevel, formatString, args); va_end(args); return; } #pragma mark - #pragma mark SC error handling / logging const CFStringRef kCFErrorDomainSystemConfiguration = CFSTR("com.apple.SystemConfiguration"); static const struct sc_errmsg { int status; char *message; } sc_errmsgs[] = { { kSCStatusAccessError, "Permission denied" }, { kSCStatusConnectionIgnore, "Network connection information not available at this time" }, { kSCStatusConnectionNoService, "Network service for connection not available" }, { kSCStatusFailed, "Failed!" }, { kSCStatusInvalidArgument, "Invalid argument" }, { kSCStatusKeyExists, "Key already defined" }, { kSCStatusLocked, "Lock already held" }, { kSCStatusMaxLink, "Maximum link count exceeded" }, { kSCStatusNeedLock, "Lock required for this operation" }, { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" }, { kSCStatusNoStoreSession, "Configuration daemon session not active" }, { kSCStatusNoConfigFile, "Configuration file not found" }, { kSCStatusNoKey, "No such key" }, { kSCStatusNoLink, "No such link" }, { kSCStatusNoPrefsSession, "Preference session not active" }, { kSCStatusNotifierActive, "Notifier is currently active" }, { kSCStatusOK, "Success!" }, { kSCStatusPrefsBusy, "Preferences update currently in progress" }, { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" }, { kSCStatusStale, "Write attempted on stale version of object" }, }; #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg)) void _SCErrorSet(int error) { __SCThreadSpecificDataRef tsd; tsd = __SCGetThreadSpecificData(); tsd->_sc_error = error; return; } CFErrorRef SCCopyLastError(void) { CFStringRef domain; CFErrorRef error; int i; int code; __SCThreadSpecificDataRef tsd; CFMutableDictionaryRef userInfo = NULL; tsd = __SCGetThreadSpecificData(); code =tsd->_sc_error; for (i = 0; i < (int)nSC_ERRMSGS; i++) { if (sc_errmsgs[i].status == code) { CFStringRef str; domain = kCFErrorDomainSystemConfiguration; userInfo = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); str = CFStringCreateWithCString(NULL, sc_errmsgs[i].message, kCFStringEncodingASCII); CFDictionarySetValue(userInfo, kCFErrorDescriptionKey, str); CFRelease(str); goto done; } } if ((code > 0) && (code <= ELAST)) { domain = kCFErrorDomainPOSIX; goto done; } domain = kCFErrorDomainMach; done : error = CFErrorCreate(NULL, domain, code, userInfo); if (userInfo != NULL) CFRelease(userInfo); return error; } int SCError(void) { __SCThreadSpecificDataRef tsd; tsd = __SCGetThreadSpecificData(); return tsd->_sc_error; } const char * SCErrorString(int status) { int i; for (i = 0; i < (int)nSC_ERRMSGS; i++) { if (sc_errmsgs[i].status == status) { return sc_errmsgs[i].message; } } if ((status > 0) && (status <= ELAST)) { return strerror(status); } if ((status >= BOOTSTRAP_SUCCESS) && (status <= BOOTSTRAP_NO_MEMORY)) { return bootstrap_strerror(status); } return mach_error_string(status); }