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