1/* 2 * Copyright (c) 2000-2008, 2010-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 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 11 * file. 12 * 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. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * June 1, 2001 Allan Nathanson <ajn@apple.com> 28 * - public API conversion 29 * 30 * March 24, 2000 Allan Nathanson <ajn@apple.com> 31 * - initial revision 32 */ 33 34#include <mach/mach.h> 35#include <mach/mach_error.h> 36#include <servers/bootstrap.h> 37#include <asl.h> 38#include <pthread.h> 39#include <sys/time.h> 40 41#include <SystemConfiguration/SystemConfiguration.h> 42#include <SystemConfiguration/SCPrivate.h> 43#include "SCD.h" 44#include "SCDynamicStoreInternal.h" 45#include "config.h" /* MiG generated file */ 46 47// LIBASL SPI 48extern asl_object_t _asl_server_control_query(void); 49 50 51/* framework variables */ 52int _sc_debug = FALSE; /* non-zero if debugging enabled */ 53int _sc_verbose = FALSE; /* non-zero if verbose logging enabled */ 54int _sc_log = TRUE; /* 0 if SC messages should be written to stdout/stderr, 55 1 if SC messages should be logged w/asl(3), 56 2 if SC messages should be written to stdout/stderr AND logged */ 57 58 59#pragma mark - 60#pragma mark Thread specific data 61 62 63static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT; 64static pthread_key_t tsDataKey; 65 66 67static void 68__SCThreadSpecificDataFinalize(void *arg) 69{ 70 __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg; 71 72 if (tsd != NULL) { 73 if (tsd->_asl != NULL) asl_release(tsd->_asl); 74 if (tsd->_sc_store != NULL) CFRelease(tsd->_sc_store); 75 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd); 76 } 77 return; 78} 79 80 81static void 82__SCThreadSpecificKeyInitialize() 83{ 84 pthread_key_create(&tsDataKey, __SCThreadSpecificDataFinalize); 85 return; 86} 87 88 89__private_extern__ 90__SCThreadSpecificDataRef 91__SCGetThreadSpecificData() 92{ 93 __SCThreadSpecificDataRef tsd; 94 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize); 95 96 tsd = pthread_getspecific(tsDataKey); 97 if (tsd == NULL) { 98 tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0); 99 tsd->_asl = NULL; 100 tsd->_sc_error = kSCStatusOK; 101 tsd->_sc_store = NULL; 102 pthread_setspecific(tsDataKey, tsd); 103 } 104 105 return tsd; 106} 107 108 109#pragma mark - 110#pragma mark Logging 111 112 113#define kASLModule "ASLModule" 114#define kASLOption "ASLOption" 115#define kLoggerID "LoggerID" 116 117#define ENABLE_SC_FORMATTING 118#ifdef ENABLE_SC_FORMATTING 119// from <CoreFoundation/ForFoundationOnly.h> 120extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(CFTypeRef, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments); 121#endif /* ENABLE_SC_FORMATTING */ 122 123 124CFStringRef 125_SCCopyDescription(CFTypeRef cf, CFDictionaryRef formatOptions) 126{ 127#ifdef ENABLE_SC_FORMATTING 128 CFMutableDictionaryRef nFormatOptions; 129 CFStringRef prefix1; 130 CFStringRef prefix2; 131 CFTypeID type = CFGetTypeID(cf); 132 133 if (!formatOptions || 134 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) { 135 prefix1 = CFSTR(""); 136 } 137 138 if (type == CFStringGetTypeID()) { 139 return CFStringCreateWithFormat(NULL, 140 formatOptions, 141 CFSTR("%@%@"), 142 prefix1, 143 cf); 144 } 145 146 if (type == CFBooleanGetTypeID()) { 147 return CFStringCreateWithFormat(NULL, 148 formatOptions, 149 CFSTR("%@%s"), 150 prefix1, 151 CFBooleanGetValue(cf) ? "TRUE" : "FALSE"); 152 } 153 154 if (type == CFDataGetTypeID()) { 155 const uint8_t *data; 156 CFIndex dataLen; 157 CFIndex i; 158 CFMutableStringRef str; 159 160 str = CFStringCreateMutable(NULL, 0); 161 CFStringAppendFormat(str, formatOptions, CFSTR("%@<data> 0x"), prefix1); 162 163 data = CFDataGetBytePtr(cf); 164 dataLen = CFDataGetLength(cf); 165 for (i = 0; i < dataLen; i++) { 166 CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]); 167 } 168 169 return str; 170 } 171 172 if (type == CFNumberGetTypeID()) { 173 return CFStringCreateWithFormat(NULL, 174 formatOptions, 175 CFSTR("%@%@"), 176 prefix1, 177 cf); 178 } 179 180 if (type == CFDateGetTypeID()) { 181 CFCalendarRef calendar; 182 CFStringRef str; 183 CFTimeZoneRef tz; 184 int MM, DD, YYYY, hh, mm, ss; 185 186 calendar = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar); 187 tz = CFTimeZoneCopySystem(); 188 CFCalendarSetTimeZone(calendar, tz); 189 CFRelease(tz); 190 CFCalendarDecomposeAbsoluteTime(calendar, 191 CFDateGetAbsoluteTime(cf), 192 "MdyHms", 193 &MM, &DD, &YYYY, &hh, &mm, &ss); 194 CFRelease(calendar); 195 196 str = CFStringCreateWithFormat(NULL, 197 formatOptions, 198 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"), 199 prefix1, 200 MM, DD, YYYY, hh, mm, ss); 201 return str; 202 } 203 204 if ((formatOptions == NULL) || 205 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) { 206 prefix2 = prefix1; 207 } 208 209 if (formatOptions != NULL) { 210 nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions); 211 } else { 212 nFormatOptions = CFDictionaryCreateMutable(NULL, 213 0, 214 &kCFTypeDictionaryKeyCallBacks, 215 &kCFTypeDictionaryValueCallBacks); 216 } 217 assert(nFormatOptions != NULL); 218 219#define N_QUICK 32 220 221 if (type == CFArrayGetTypeID()) { 222 const void * elements_q[N_QUICK]; 223 const void ** elements = elements_q; 224 CFIndex i; 225 CFIndex nElements; 226 CFMutableStringRef str; 227 228 str = CFStringCreateMutable(NULL, 0); 229 CFStringAppendFormat(str, formatOptions, CFSTR("%@<array> {"), prefix1); 230 231 nElements = CFArrayGetCount(cf); 232 if (nElements > 0) { 233 if (nElements > (CFIndex)(sizeof(elements_q)/sizeof(CFTypeRef))) 234 elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); 235 CFArrayGetValues(cf, CFRangeMake(0, nElements), elements); 236 for (i = 0; i < nElements; i++) { 237 CFMutableStringRef nPrefix1; 238 CFMutableStringRef nPrefix2; 239 CFStringRef nStr; 240 CFStringRef vStr; 241 242 nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"), i); 243 244 nPrefix1 = CFStringCreateMutable(NULL, 0); 245 CFStringAppendFormat(nPrefix1, 246 formatOptions, 247 CFSTR("%@ %@ : "), 248 prefix2, 249 nStr); 250 nPrefix2 = CFStringCreateMutable(NULL, 0); 251 CFStringAppendFormat(nPrefix2, 252 formatOptions, 253 CFSTR("%@ "), 254 prefix2); 255 256 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1); 257 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2); 258 CFRelease(nPrefix1); 259 CFRelease(nPrefix2); 260 CFRelease(nStr); 261 262 vStr = _SCCopyDescription((CFTypeRef)elements[i], nFormatOptions); 263 CFStringAppendFormat(str, 264 formatOptions, 265 CFSTR("\n%@"), 266 vStr); 267 CFRelease(vStr); 268 } 269 if (elements != elements_q) CFAllocatorDeallocate(NULL, elements); 270 } 271 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2); 272 273 CFRelease(nFormatOptions); 274 return str; 275 } 276 277 if (type == CFDictionaryGetTypeID()) { 278 const void * keys_q[N_QUICK]; 279 const void ** keys = keys_q; 280 CFIndex i; 281 CFIndex nElements; 282 CFMutableStringRef nPrefix1; 283 CFMutableStringRef nPrefix2; 284 CFMutableStringRef str; 285 286 str = CFStringCreateMutable(NULL, 0); 287 CFStringAppendFormat(str, formatOptions, CFSTR("%@<dictionary> {"), prefix1); 288 289 nElements = CFDictionaryGetCount(cf); 290 if (nElements > 0) { 291 CFComparatorFunction compFunc = NULL; 292 CFMutableArrayRef sortedKeys; 293 294 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { 295 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); 296 } 297 CFDictionaryGetKeysAndValues(cf, keys, NULL); 298 299 sortedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 300 for (i = 0; i < nElements; i++) { 301 CFArrayAppendValue(sortedKeys, (CFStringRef)keys[i]); 302 } 303 304 if (isA_CFString(keys[0])) { 305 compFunc = (CFComparatorFunction)CFStringCompare; 306 } 307 else if (isA_CFNumber(keys[0])) { 308 compFunc = (CFComparatorFunction)CFNumberCompare; 309 } 310 else if (isA_CFDate(keys[0])) { 311 compFunc = (CFComparatorFunction)CFDateCompare; 312 } 313 314 if (compFunc != NULL) { 315 CFArraySortValues(sortedKeys, 316 CFRangeMake(0, nElements), 317 compFunc, 318 NULL); 319 } 320 321 for (i = 0; i < nElements; i++) { 322 CFStringRef key; 323 CFStringRef kStr; 324 CFTypeRef val; 325 CFStringRef vStr; 326 327 key = CFArrayGetValueAtIndex(sortedKeys, i); 328 kStr = _SCCopyDescription((CFTypeRef)key, NULL); 329 330 nPrefix1 = CFStringCreateMutable(NULL, 0); 331 CFStringAppendFormat(nPrefix1, 332 formatOptions, 333 CFSTR("%@ %@ : "), 334 prefix2, 335 kStr); 336 nPrefix2 = CFStringCreateMutable(NULL, 0); 337 CFStringAppendFormat(nPrefix2, 338 formatOptions, 339 CFSTR("%@ "), 340 prefix2); 341 342 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1); 343 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2); 344 CFRelease(nPrefix1); 345 CFRelease(nPrefix2); 346 CFRelease(kStr); 347 348 val = CFDictionaryGetValue(cf, key); 349 vStr = _SCCopyDescription((CFTypeRef)val, nFormatOptions); 350 CFStringAppendFormat(str, 351 formatOptions, 352 CFSTR("\n%@"), 353 vStr); 354 CFRelease(vStr); 355 } 356 357 CFRelease(sortedKeys); 358 359 if (keys != keys_q) { 360 CFAllocatorDeallocate(NULL, keys); 361 } 362 } 363 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2); 364 365 CFRelease(nFormatOptions); 366 return str; 367 } 368 369 CFRelease(nFormatOptions); 370#endif /* ENABLE_SC_FORMATTING */ 371 372 return CFStringCreateWithFormat(NULL, 373 formatOptions, 374 CFSTR("%@%@"), 375 prefix1, 376 cf); 377} 378 379 380static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 381 382__private_extern__ Boolean 383is_install_environment() { 384 static dispatch_once_t once; 385 static Boolean is_install; 386 387 dispatch_once(&once, ^{ 388 is_install = (getenv(INSTALL_ENVIRONMENT) != NULL); 389 }); 390 391 return is_install; 392} 393 394static void 395__SCLog(asl_object_t asl, asl_object_t msg, int level, CFStringRef formatString, va_list formatArguments) 396{ 397 CFDataRef line; 398 CFArrayRef lines; 399 CFStringRef str; 400 401 if (asl == NULL) { 402 __SCThreadSpecificDataRef tsd; 403 404 tsd = __SCGetThreadSpecificData(); 405 if (tsd->_asl == NULL) { 406 tsd->_asl = asl_open(NULL, (is_install_environment() ? INSTALL_FACILITY : NULL), 0); 407 asl_set_filter(tsd->_asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); 408 } 409 asl = tsd->_asl; 410 } 411 412#ifdef ENABLE_SC_FORMATTING 413 str = _CFStringCreateWithFormatAndArgumentsAux(NULL, 414 _SCCopyDescription, 415 NULL, 416 formatString, 417 formatArguments); 418#else /* ENABLE_SC_FORMATTING */ 419 str = CFStringCreateWithFormatAndArguments (NULL, 420 NULL, 421 formatString, 422 formatArguments); 423#endif /* !ENABLE_SC_FORMATTING */ 424 425 if (level >= 0) { 426 lines = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR("\n")); 427 if (lines != NULL) { 428 CFIndex i; 429 CFIndex n = CFArrayGetCount(lines); 430 431 for (i = 0; i < n; i++) { 432 line = CFStringCreateExternalRepresentation(NULL, 433 CFArrayGetValueAtIndex(lines, i), 434 kCFStringEncodingUTF8, 435 (UInt8)'?'); 436 if (line) { 437 asl_log(asl, msg, level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line)); 438 CFRelease(line); 439 } 440 } 441 CFRelease(lines); 442 } 443 } else { 444 line = CFStringCreateExternalRepresentation(NULL, 445 str, 446 kCFStringEncodingUTF8, 447 (UInt8)'?'); 448 if (line) { 449 asl_log(asl, msg, ~level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line)); 450 CFRelease(line); 451 } 452 } 453 CFRelease(str); 454 return; 455} 456 457 458static void 459__SCPrint(FILE *stream, CFStringRef formatString, va_list formatArguments, Boolean trace, Boolean addNL) 460{ 461 CFDataRef line; 462 CFStringRef str; 463 464#ifdef ENABLE_SC_FORMATTING 465 str = _CFStringCreateWithFormatAndArgumentsAux(NULL, 466 _SCCopyDescription, 467 NULL, 468 formatString, 469 formatArguments); 470#else /* ENABLE_SC_FORMATTING */ 471 str = CFStringCreateWithFormatAndArguments (NULL, 472 NULL, 473 formatString, 474 formatArguments); 475#endif /* !ENABLE_SC_FORMATTING */ 476 477 line = CFStringCreateExternalRepresentation(NULL, 478 str, 479 kCFStringEncodingUTF8, 480 (UInt8)'?'); 481 CFRelease(str); 482 if (!line) { 483 return; 484 } 485 486 pthread_mutex_lock(&lock); 487 if (trace) { 488 struct tm tm_now; 489 struct timeval tv_now; 490 491 (void)gettimeofday(&tv_now, NULL); 492 (void)localtime_r(&tv_now.tv_sec, &tm_now); 493 (void)fprintf(stream, "%2d:%02d:%02d.%03d ", 494 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000); 495 } 496 (void)fwrite((const void *)CFDataGetBytePtr(line), (size_t)CFDataGetLength(line), 1, stream); 497 if (addNL) { 498 (void)fputc('\n', stream); 499 } 500 fflush (stream); 501 pthread_mutex_unlock(&lock); 502 CFRelease(line); 503 504 return; 505} 506 507 508void 509SCLog(Boolean condition, int level, CFStringRef formatString, ...) 510{ 511 va_list formatArguments; 512 va_list formatArguments_print; 513 Boolean log = FALSE; 514 Boolean print = FALSE; 515 516 if (!condition) { 517 return; 518 } 519 520 /* 521 * Note: The following are the expected values for _sc_log 522 * 523 * 0 if SC messages should be written to stdout/stderr 524 * 1 if SC messages should be logged w/asl(3) 525 * 2 if SC messages should be written to stdout/stderr AND logged 526 */ 527 528 if (_sc_log > 0) { 529 log = TRUE; // log requested 530 va_start(formatArguments, formatString); 531 532 if (_sc_log > 1) { 533 print = TRUE; // log AND print requested 534 va_copy(formatArguments_print, formatArguments); 535 } 536 } else { 537 print = TRUE; // print requested 538 va_start(formatArguments_print, formatString); 539 } 540 541 if (log) { 542 __SCLog(NULL, NULL, level, formatString, formatArguments); 543 va_end(formatArguments); 544 } 545 546 if (print) { 547 __SCPrint((LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout, 548 formatString, 549 formatArguments_print, 550 (_sc_log > 0), // trace 551 TRUE); // add newline 552 va_end(formatArguments_print); 553 } 554 555 return; 556} 557 558 559void 560SCLOG(asl_object_t asl, asl_object_t msg, int level, CFStringRef formatString, ...) 561{ 562 va_list formatArguments; 563 va_list formatArguments_print; 564 Boolean log = FALSE; 565 Boolean print = FALSE; 566 567 /* 568 * Note: The following are the expected values for _sc_log 569 * 570 * 0 if SC messages should be written to stdout/stderr 571 * 1 if SC messages should be logged w/asl(3) 572 * 2 if SC messages should be written to stdout/stderr AND logged 573 */ 574 575 if (_sc_log > 0) { 576 log = TRUE; // log requested 577 va_start(formatArguments, formatString); 578 579 if (_sc_log > 1) { 580 print = TRUE; // log AND print requested 581 va_copy(formatArguments_print, formatArguments); 582 } 583 } else { 584 print = TRUE; // print requested 585 va_start(formatArguments_print, formatString); 586 } 587 588 if (log) { 589 __SCLog(asl, msg, level, formatString, formatArguments); 590 va_end(formatArguments); 591 } 592 593 if (print) { 594 if (level < 0) { 595 level = ~level; 596 } 597 __SCPrint((level > ASL_LEVEL_NOTICE) ? stderr : stdout, 598 formatString, 599 formatArguments_print, 600 (_sc_log > 0), // trace 601 TRUE); // add newline 602 va_end(formatArguments_print); 603 } 604 605 return; 606} 607 608 609void 610SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...) 611{ 612 va_list formatArguments; 613 614 if (!condition) { 615 return; 616 } 617 618 va_start(formatArguments, formatString); 619 __SCPrint(stream, formatString, formatArguments, FALSE, FALSE); 620 va_end(formatArguments); 621 622 return; 623} 624 625 626void 627SCTrace(Boolean condition, FILE *stream, CFStringRef formatString, ...) 628{ 629 va_list formatArguments; 630 631 if (!condition) { 632 return; 633 } 634 635 va_start(formatArguments, formatString); 636 __SCPrint(stream, formatString, formatArguments, TRUE, FALSE); 637 va_end(formatArguments); 638 639 return; 640} 641 642 643#pragma mark - 644#pragma mark ASL Functions 645 646 647static CFTypeID __kSCLoggerTypeID = _kCFRuntimeNotATypeID; 648 649typedef enum { 650 kModuleStatusEnabled, 651 kModuleStatusDisabled, 652 kModuleStatusDoesNotExist 653} ModuleStatus; 654 655struct SCLogger 656{ 657 CFRuntimeBase cf_base; 658 659 char * loggerID; // LoggerID 660 SCLoggerFlags flags; 661 asl_object_t aslc; 662 asl_object_t aslm; 663 ModuleStatus module_status; 664 pthread_mutex_t lock; 665}; 666 667 668static void __SCLoggerDeallocate(CFTypeRef cf); 669static const CFRuntimeClass __SCLoggerClass = { 670 0, /* version */ 671 "SCLogger", /* className */ 672 NULL, /* init */ 673 NULL, /* copy */ 674 __SCLoggerDeallocate, /* deallocate */ 675 NULL, /* equal */ 676 NULL, /* hash */ 677 NULL, /* copyFormattingDesc */ 678 NULL /* copyDebugDesc */ 679}; 680 681 682#define DATETIMEBUFFERSIZE 32 683 684 685static pthread_once_t registerLoggerOnce = PTHREAD_ONCE_INIT; 686static pthread_once_t defaultLoggerOnce = PTHREAD_ONCE_INIT; 687 688typedef enum { 689 kLoggerASLControlEnableModule, 690 kLoggerASLControlDisableModule, 691 kLoggerASLControlLogFileCheckpoint 692} LoggerASLControl; 693 694static SCLoggerRef defaultLogger = NULL; 695static SCLoggerRef __SCLoggerCreate(void); 696static void __SCLoggerDefaultLoggerInit(); 697static SCLoggerRef SCLoggerGetDefaultLogger(); 698static void SCLoggerSetLoggerID(SCLoggerRef logger, CFStringRef loggerID); 699static void SCLoggerSendMessageToModuleOnly(SCLoggerRef logger, Boolean isPrivate); 700static void SCLoggerSendASLControl(SCLoggerRef logger, LoggerASLControl control); 701static ModuleStatus GetModuleStatus(const char * loggerID); 702 703static void 704__SCLoggerRegisterClass(void) 705{ 706 if (__kSCLoggerTypeID == _kCFRuntimeNotATypeID) { 707 __kSCLoggerTypeID = _CFRuntimeRegisterClass(&__SCLoggerClass); 708 } 709 return; 710} 711 712static SCLoggerRef 713__SCLoggerAllocate(CFAllocatorRef allocator) 714{ 715 SCLoggerRef state; 716 int size; 717 718 pthread_once(®isterLoggerOnce, __SCLoggerRegisterClass); 719 720 size = sizeof(*state) - sizeof(CFRuntimeBase); 721 state = (SCLoggerRef) _CFRuntimeCreateInstance(allocator, 722 __kSCLoggerTypeID, 723 size, 724 NULL); 725 bzero((void*)state + sizeof(CFRuntimeBase), size); 726 return (state); 727} 728 729static void 730__SCLoggerDeallocate(CFTypeRef cf) 731{ 732 SCLoggerRef logger = (SCLoggerRef)cf; 733 734 if (logger != NULL) { 735 // Rotate on close behavior 736 if (logger->module_status != kModuleStatusDoesNotExist) { 737 SCLoggerSendASLControl(logger, 738 kLoggerASLControlLogFileCheckpoint); 739 } 740 if (logger->loggerID != NULL) { 741 CFAllocatorDeallocate(NULL, logger->loggerID); 742 logger->loggerID = NULL; 743 } 744 if (logger->aslm != NULL) { 745 asl_release(logger->aslm); 746 logger->aslm = NULL; 747 } 748 if (logger->aslc != NULL) { 749 asl_release(logger->aslc); 750 logger->aslc = NULL; 751 } 752 } 753} 754 755static SCLoggerRef 756__SCLoggerCreate(void) 757{ 758 SCLoggerRef tempLogger = NULL; 759 760 tempLogger = __SCLoggerAllocate(kCFAllocatorDefault); 761 tempLogger->loggerID = NULL; 762 tempLogger->flags = kSCLoggerFlagsDefault; 763 tempLogger->aslc = asl_open(NULL, (is_install_environment() ? INSTALL_FACILITY : NULL), ASL_OPT_NO_DELAY); 764 tempLogger->aslm = asl_new(ASL_TYPE_MSG); 765 pthread_mutex_init(&(tempLogger->lock), NULL); 766 tempLogger->module_status = kModuleStatusDoesNotExist; 767 768 return tempLogger; 769} 770 771SCLoggerFlags 772SCLoggerGetFlags(SCLoggerRef logger) 773{ 774 return logger->flags; 775} 776 777void 778SCLoggerSetFlags(SCLoggerRef logger, SCLoggerFlags flags) 779{ 780 if (logger == defaultLogger) { 781 return; 782 } 783 pthread_mutex_lock(&(logger->lock)); 784 if (flags != kSCLoggerFlagsNone) { 785 logger->module_status = GetModuleStatus(logger->loggerID); 786 if (logger->module_status == kModuleStatusDoesNotExist) { 787 goto done; 788 } 789 if ((flags & kSCLoggerFlagsFile) != 0) { 790 if ((logger->flags & kSCLoggerFlagsFile) == 0) { 791 // Enable the module if disabled 792 if (logger->module_status == kModuleStatusDisabled) { 793 SCLoggerSendASLControl(logger, kLoggerASLControlEnableModule); 794 } 795 // Setting ASL Filter level to debug 796 asl_set_filter(logger->aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); 797 if (logger->loggerID != NULL) { 798 asl_set(logger->aslm, kLoggerID, 799 logger->loggerID); 800 } 801 } 802 } 803 else if ((logger->flags & kSCLoggerFlagsFile) != 0) { 804 asl_unset(logger->aslm, kLoggerID); 805 asl_set_filter(logger->aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE)); 806 SCLoggerSendMessageToModuleOnly(logger, false); 807 } 808 if ((flags & kSCLoggerFlagsDefault) != 0) { 809 if ((logger->flags & kSCLoggerFlagsDefault) == 0) { 810 SCLoggerSendMessageToModuleOnly(logger, false); 811 } 812 } 813 else if ((logger->flags & kSCLoggerFlagsDefault) != 0) { 814 SCLoggerSendMessageToModuleOnly(logger, true); 815 } 816 } 817 logger->flags = flags; 818 done: 819 pthread_mutex_unlock(&(logger->lock)); 820} 821 822 823static void 824SCLoggerSetLoggerID(SCLoggerRef logger, CFStringRef loggerID) 825{ 826 logger->loggerID 827 = _SC_cfstring_to_cstring(loggerID, NULL, 0, 828 kCFStringEncodingUTF8); 829 // Enable the module if disabled 830 logger->module_status = GetModuleStatus(logger->loggerID); 831 if (logger->module_status == kModuleStatusDisabled) { 832 SCLoggerSendASLControl(logger, kLoggerASLControlEnableModule); 833 } 834} 835 836static ModuleStatus 837GetModuleStatus(const char * loggerID) 838{ 839 ModuleStatus moduleStatus = kModuleStatusDoesNotExist; 840 asl_object_t response = NULL; 841 const char* value = NULL; 842 843 if (loggerID != NULL) { 844 response = _asl_server_control_query(); 845 if (response == NULL) { 846 goto done; 847 } 848 value = asl_get(response, loggerID); 849 if (value == NULL) { 850 moduleStatus = kModuleStatusDoesNotExist; 851 goto done; 852 } 853 854 if (strcmp(value, "enabled") == 0) { 855 moduleStatus = kModuleStatusEnabled; 856 } 857 else { 858 moduleStatus = kModuleStatusDisabled; 859 } 860 } 861done: 862 asl_release(response); 863 864 return moduleStatus; 865} 866 867static void 868SCLoggerSendMessageToModuleOnly(SCLoggerRef logger, Boolean isPrivate) 869{ 870 if (isPrivate) { 871 asl_set(logger->aslm, kASLModule, logger->loggerID); 872 } 873 else { 874 if (asl_get(logger->aslm, kASLModule) != NULL) { 875 asl_unset(logger->aslm, kASLModule); 876 } 877 } 878} 879 880static void 881SCLoggerSendASLControl(SCLoggerRef logger, LoggerASLControl control) 882{ 883 SCLoggerRef defLogger = SCLoggerGetDefaultLogger(); 884 pthread_mutex_lock(&(defLogger->lock)); 885 886 // this next line turns the asl_log()'s that follow into control messages 887 asl_set(defLogger->aslm, kASLOption, "control"); 888 889 switch (control) { 890 case kLoggerASLControlEnableModule: 891 asl_log(defLogger->aslc, defLogger->aslm, 892 ASL_LEVEL_NOTICE, "@ %s enable 1", 893 logger->loggerID); 894 break; 895 case kLoggerASLControlDisableModule: 896 asl_log(defLogger->aslc, defLogger->aslm, 897 ASL_LEVEL_NOTICE, "@ %s enable 0", 898 logger->loggerID); 899 break; 900 case kLoggerASLControlLogFileCheckpoint: 901 asl_log(defLogger->aslc, defLogger->aslm, 902 ASL_LEVEL_NOTICE, "@ %s checkpoint", 903 logger->loggerID); 904 break; 905 default: 906 break; 907 } 908 909 // turn off control mode 910 asl_unset(defLogger->aslm, kASLOption); 911 pthread_mutex_unlock(&defLogger->lock); 912 return; 913} 914 915SCLoggerRef 916SCLoggerCreate(CFStringRef loggerID) 917{ 918 SCLoggerRef logger = NULL; 919 920 logger = __SCLoggerCreate(); 921 if (loggerID != NULL) { 922 SCLoggerSetLoggerID(logger, loggerID); 923 } 924 SCLoggerSetFlags(logger, kSCLoggerFlagsDefault); 925 return logger; 926} 927 928static void 929__SCLoggerDefaultLoggerInit() 930{ 931 if (defaultLogger == NULL) { 932 defaultLogger = __SCLoggerCreate(); 933 defaultLogger->flags = kSCLoggerFlagsDefault; 934 } 935} 936 937static SCLoggerRef 938SCLoggerGetDefaultLogger() 939{ 940 pthread_once(&defaultLoggerOnce, __SCLoggerDefaultLoggerInit); 941 return defaultLogger; 942} 943 944void 945SCLoggerVLog(SCLoggerRef logger, int loglevel, CFStringRef formatString, 946 va_list args) 947{ 948 asl_object_t aslc; 949 asl_object_t aslm; 950 951 if (logger == NULL 952 || logger->module_status == kModuleStatusDoesNotExist) { 953 logger = SCLoggerGetDefaultLogger(); 954 } 955 pthread_mutex_lock(&(logger->lock)); 956 if (logger->flags == kSCLoggerFlagsNone) { 957 pthread_mutex_unlock(&(logger->lock)); 958 return; 959 } 960 aslc = logger->aslc; 961 aslm = logger->aslm; 962 __SCLog(aslc, aslm, loglevel, formatString, args); 963 pthread_mutex_unlock(&(logger->lock)); 964 return; 965} 966 967void 968SCLoggerLog(SCLoggerRef logger, int loglevel, CFStringRef formatString, ...) 969{ 970 va_list args; 971 972 va_start(args, formatString); 973 SCLoggerVLog(logger, loglevel, formatString, args); 974 va_end(args); 975 976 return; 977} 978 979 980#pragma mark - 981#pragma mark SC error handling / logging 982 983 984const CFStringRef kCFErrorDomainSystemConfiguration = CFSTR("com.apple.SystemConfiguration"); 985 986 987static const struct sc_errmsg { 988 int status; 989 char *message; 990} sc_errmsgs[] = { 991 { kSCStatusAccessError, "Permission denied" }, 992 { kSCStatusConnectionIgnore, "Network connection information not available at this time" }, 993 { kSCStatusConnectionNoService, "Network service for connection not available" }, 994 { kSCStatusFailed, "Failed!" }, 995 { kSCStatusInvalidArgument, "Invalid argument" }, 996 { kSCStatusKeyExists, "Key already defined" }, 997 { kSCStatusLocked, "Lock already held" }, 998 { kSCStatusMaxLink, "Maximum link count exceeded" }, 999 { kSCStatusNeedLock, "Lock required for this operation" }, 1000 { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" }, 1001 { kSCStatusNoStoreSession, "Configuration daemon session not active" }, 1002 { kSCStatusNoConfigFile, "Configuration file not found" }, 1003 { kSCStatusNoKey, "No such key" }, 1004 { kSCStatusNoLink, "No such link" }, 1005 { kSCStatusNoPrefsSession, "Preference session not active" }, 1006 { kSCStatusNotifierActive, "Notifier is currently active" }, 1007 { kSCStatusOK, "Success!" }, 1008 { kSCStatusPrefsBusy, "Preferences update currently in progress" }, 1009 { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" }, 1010 { kSCStatusStale, "Write attempted on stale version of object" }, 1011}; 1012#define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg)) 1013 1014void 1015_SCErrorSet(int error) 1016{ 1017 __SCThreadSpecificDataRef tsd; 1018 1019 tsd = __SCGetThreadSpecificData(); 1020 tsd->_sc_error = error; 1021 return; 1022} 1023 1024 1025CFErrorRef 1026SCCopyLastError(void) 1027{ 1028 CFStringRef domain; 1029 CFErrorRef error; 1030 int i; 1031 int code; 1032 __SCThreadSpecificDataRef tsd; 1033 CFMutableDictionaryRef userInfo = NULL; 1034 1035 tsd = __SCGetThreadSpecificData(); 1036 code =tsd->_sc_error; 1037 1038 for (i = 0; i < (int)nSC_ERRMSGS; i++) { 1039 if (sc_errmsgs[i].status == code) { 1040 CFStringRef str; 1041 1042 domain = kCFErrorDomainSystemConfiguration; 1043 userInfo = CFDictionaryCreateMutable(NULL, 1044 0, 1045 &kCFCopyStringDictionaryKeyCallBacks, 1046 &kCFTypeDictionaryValueCallBacks); 1047 str = CFStringCreateWithCString(NULL, 1048 sc_errmsgs[i].message, 1049 kCFStringEncodingASCII); 1050 CFDictionarySetValue(userInfo, kCFErrorDescriptionKey, str); 1051 CFRelease(str); 1052 goto done; 1053 } 1054 } 1055 1056 if ((code > 0) && (code <= ELAST)) { 1057 domain = kCFErrorDomainPOSIX; 1058 goto done; 1059 } 1060 1061 domain = kCFErrorDomainMach; 1062 1063 done : 1064 1065 error = CFErrorCreate(NULL, domain, code, userInfo); 1066 if (userInfo != NULL) CFRelease(userInfo); 1067 return error; 1068} 1069 1070 1071int 1072SCError(void) 1073{ 1074 __SCThreadSpecificDataRef tsd; 1075 1076 tsd = __SCGetThreadSpecificData(); 1077 return tsd->_sc_error; 1078} 1079 1080 1081const char * 1082SCErrorString(int status) 1083{ 1084 int i; 1085 1086 for (i = 0; i < (int)nSC_ERRMSGS; i++) { 1087 if (sc_errmsgs[i].status == status) { 1088 return sc_errmsgs[i].message; 1089 } 1090 } 1091 1092 if ((status > 0) && (status <= ELAST)) { 1093 return strerror(status); 1094 } 1095 1096 if ((status >= BOOTSTRAP_SUCCESS) && (status <= BOOTSTRAP_NO_MEMORY)) { 1097 return bootstrap_strerror(status); 1098 } 1099 1100 return mach_error_string(status); 1101} 1102