#include <mach/mach.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
#include <asl_msg.h>
#include <asl_core.h>
#include <pthread.h>
#include <sys/time.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include "SCD.h"
#include "SCDynamicStoreInternal.h"
#include "config.h"
int _sc_debug = FALSE;
int _sc_verbose = FALSE;
int _sc_log = TRUE;
#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_close(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
extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(CFTypeRef, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments);
#endif
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("%@<data> 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()) {
CFGregorianDate gDate;
CFStringRef str;
CFTimeZoneRef tZone;
tZone = CFTimeZoneCopySystem();
gDate = CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(cf), tZone);
str = CFStringCreateWithFormat(NULL,
formatOptions,
CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
prefix1,
gDate.month,
gDate.day,
(int)gDate.year,
gDate.hour,
gDate.minute,
gDate.second,
CFTimeZoneGetName(tZone));
CFRelease(tZone);
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("%@<array> {"), 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("%@<dictionary> {"), prefix1);
nElements = CFDictionaryGetCount(cf);
if (nElements > 0) {
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]);
}
CFArraySortValues(sortedKeys,
CFRangeMake(0, nElements),
(CFComparatorFunction)CFStringCompare,
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
return CFStringCreateWithFormat(NULL,
formatOptions,
CFSTR("%@%@"),
prefix1,
cf);
}
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static void
__SCLog(aslclient asl, aslmsg 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, 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
str = CFStringCreateWithFormatAndArguments (NULL,
NULL,
formatString,
formatArguments);
#endif
if (level >= 0) {
lines = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR("\n"));
if (lines != NULL) {
int i;
int 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
str = CFStringCreateWithFormatAndArguments (NULL,
NULL,
formatString,
formatArguments);
#endif
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;
}
if (_sc_log > 0) {
log = TRUE; va_start(formatArguments, formatString);
if (_sc_log > 1) {
print = TRUE; va_copy(formatArguments_print, formatArguments);
}
} else {
print = TRUE; 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), TRUE); va_end(formatArguments_print);
}
return;
}
void
SCLOG(aslclient asl, aslmsg msg, int level, CFStringRef formatString, ...)
{
va_list formatArguments;
va_list formatArguments_print;
Boolean log = FALSE;
Boolean print = FALSE;
if (_sc_log > 0) {
log = TRUE; va_start(formatArguments, formatString);
if (_sc_log > 1) {
print = TRUE; va_copy(formatArguments_print, formatArguments);
}
} else {
print = TRUE; 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), TRUE); 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
#if ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 60000))
extern kern_return_t _asl_server_query(mach_port_t server,
caddr_t request,
mach_msg_type_number_t requestCnt,
uint64_t startid,
int count,
int flags,
caddr_t *reply,
mach_msg_type_number_t *replyCnt,
uint64_t *lastid,
int *status,
security_token_t *token);
#define ASL_SERVICE_NAME "com.apple.system.logger"
static aslresponse
_asl_control_query(aslmsg a)
{
asl_search_result_t *out;
char *qstr, *str, *res;
uint32_t len, reslen, status;
uint64_t cmax, qmin;
kern_return_t kstatus;
caddr_t vmstr;
mach_port_t server_port;
security_token_t sec;
bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &server_port);
if (server_port == MACH_PORT_NULL) return NULL;
len = 0;
qstr = asl_msg_to_string((asl_msg_t *)a, &len);
str = NULL;
if (qstr == NULL)
{
asprintf(&str, "1\nQ [= ASLOption control]\n");
len = 27;
}
else
{
asprintf(&str, "1\n%s [= ASLOption control]\n", qstr);
len += 26;
free(qstr);
}
if (str == NULL) return NULL;
out = NULL;
qmin = 0;
cmax = 0;
sec.val[0] = -1;
sec.val[1] = -1;
res = NULL;
reslen = 0;
status = ASL_STATUS_OK;
kstatus = vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE);
if (kstatus != KERN_SUCCESS) return NULL;
memmove(vmstr, str, len);
free(str);
status = 0;
kstatus = _asl_server_query(server_port, vmstr, len, qmin, 1, 0, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
if (kstatus != KERN_SUCCESS) return NULL;
if (res == NULL) return NULL;
out = asl_list_from_string(res);
vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
return out;
}
static CFTypeID __kSCLoggerTypeID = _kCFRuntimeNotATypeID;
typedef enum {
kModuleStatusEnabled,
kModuleStatusDisabled,
kModuleStatusDoesNotExist
} ModuleStatus;
struct SCLogger
{
CFRuntimeBase cf_base;
char * loggerID; SCLoggerFlags flags;
aslclient aslc;
aslmsg aslm;
ModuleStatus module_status;
pthread_mutex_t lock;
};
static void __SCLoggerDeallocate(CFTypeRef cf);
static const CFRuntimeClass __SCLoggerClass = {
0,
"SCLogger",
NULL,
NULL,
__SCLoggerDeallocate,
NULL,
NULL,
NULL,
NULL
};
#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) {
if (logger->module_status != kModuleStatusDoesNotExist) {
SCLoggerSendASLControl(logger,
kLoggerASLControlLogFileCheckpoint);
}
if (logger->loggerID != NULL) {
CFAllocatorDeallocate(NULL, logger->loggerID);
logger->loggerID = NULL;
}
if (logger->aslm != NULL) {
asl_free(logger->aslm);
logger->aslm = NULL;
}
if (logger->aslc != NULL) {
asl_close(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, 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) {
if (logger->module_status == kModuleStatusDisabled) {
SCLoggerSendASLControl(logger, kLoggerASLControlEnableModule);
}
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);
logger->module_status = GetModuleStatus(logger->loggerID);
if (logger->module_status == kModuleStatusDisabled) {
SCLoggerSendASLControl(logger, kLoggerASLControlEnableModule);
}
}
static ModuleStatus
GetModuleStatus(const char * loggerID)
{
aslresponse response = NULL;
aslmsg responseMessage = NULL;
ModuleStatus moduleStatus = kModuleStatusDoesNotExist;
const char* value = NULL;
if (loggerID != NULL) {
response = _asl_control_query(NULL);
if (response == NULL) {
goto done;
}
responseMessage = aslresponse_next(response);
if (responseMessage == NULL) {
goto done;
}
value = asl_get(responseMessage, loggerID);
if (value == NULL) {
moduleStatus = kModuleStatusDoesNotExist;
goto done;
}
if (strcmp(value, "enabled") == 0) {
moduleStatus = kModuleStatusEnabled;
}
else {
moduleStatus = kModuleStatusDisabled;
}
}
done:
if (response != NULL) {
aslresponse_free(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));
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;
}
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)
{
aslclient aslc;
aslmsg 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;
}
#endif // ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 60000))
#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);
}