]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCD.c
configd-963.270.3.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCD.c
1 /*
2 * Copyright (c) 2000-2008, 2010-2017 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 <pthread.h>
38 #include <sys/time.h>
39 #include <os/log.h>
40 #include <os/log_private.h>
41
42 #include "SCDynamicStoreInternal.h"
43 #include "SCD.h"
44 #include "config.h" /* MiG generated file */
45
46 #define INSTALL_ENVIRONMENT "__OSINSTALL_ENVIRONMENT"
47
48 /* framework variables */
49 int _sc_debug = FALSE; /* non-zero if debugging enabled */
50 int _sc_verbose = FALSE; /* non-zero if verbose logging enabled */
51 int _sc_log = TRUE; /* 0 if SC messages should be written to stdout/stderr,
52 1 if SC messages should be logged w/os_log(3),
53 2 if SC messages should be written to stdout/stderr AND logged */
54
55
56 #pragma mark -
57 #pragma mark Thread specific data
58
59
60 static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT;
61 static pthread_key_t tsDataKey;
62
63
64 static void
65 __SCThreadSpecificDataFinalize(void *arg)
66 {
67 __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg;
68
69 if (tsd != NULL) {
70 if (tsd->_sc_store != NULL) CFRelease(tsd->_sc_store);
71 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
72 }
73 return;
74 }
75
76
77 static void
78 __SCThreadSpecificKeyInitialize()
79 {
80 pthread_key_create(&tsDataKey, __SCThreadSpecificDataFinalize);
81 return;
82 }
83
84
85 __private_extern__
86 __SCThreadSpecificDataRef
87 __SCGetThreadSpecificData()
88 {
89 __SCThreadSpecificDataRef tsd;
90 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
91
92 tsd = pthread_getspecific(tsDataKey);
93 if (tsd == NULL) {
94 tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0);
95 tsd->_sc_error = kSCStatusOK;
96 tsd->_sc_store = NULL;
97 pthread_setspecific(tsDataKey, tsd);
98 }
99
100 return tsd;
101 }
102
103
104 #pragma mark -
105 #pragma mark Logging
106
107
108 #define kASLModule "ASLModule"
109 #define kASLOption "ASLOption"
110 #define kLoggerID "LoggerID"
111
112 #define ENABLE_SC_FORMATTING
113 #ifdef ENABLE_SC_FORMATTING
114 // from <CoreFoundation/ForFoundationOnly.h>
115 extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(CFTypeRef, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments);
116 #endif /* ENABLE_SC_FORMATTING */
117
118
119 CFStringRef
120 _SCCopyDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
121 {
122 #ifdef ENABLE_SC_FORMATTING
123 CFMutableDictionaryRef nFormatOptions;
124 CFStringRef prefix1;
125 CFStringRef prefix2;
126 CFTypeID type = CFGetTypeID(cf);
127
128 if (!formatOptions ||
129 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) {
130 prefix1 = CFSTR("");
131 }
132
133 if (type == CFStringGetTypeID()) {
134 return CFStringCreateWithFormat(NULL,
135 formatOptions,
136 CFSTR("%@%@"),
137 prefix1,
138 cf);
139 }
140
141 if (type == CFBooleanGetTypeID()) {
142 return CFStringCreateWithFormat(NULL,
143 formatOptions,
144 CFSTR("%@%s"),
145 prefix1,
146 CFBooleanGetValue(cf) ? "TRUE" : "FALSE");
147 }
148
149 if (type == CFDataGetTypeID()) {
150 const uint8_t *data;
151 CFIndex dataLen;
152 CFIndex i;
153 CFMutableStringRef str;
154
155 str = CFStringCreateMutable(NULL, 0);
156 CFStringAppendFormat(str, formatOptions, CFSTR("%@<data> 0x"), prefix1);
157
158 data = CFDataGetBytePtr(cf);
159 dataLen = CFDataGetLength(cf);
160 for (i = 0; i < dataLen; i++) {
161 CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]);
162 }
163
164 return str;
165 }
166
167 if (type == CFNumberGetTypeID()) {
168 return CFStringCreateWithFormat(NULL,
169 formatOptions,
170 CFSTR("%@%@"),
171 prefix1,
172 cf);
173 }
174
175 if (type == CFDateGetTypeID()) {
176 CFCalendarRef calendar;
177 CFStringRef str;
178 CFTimeZoneRef tz;
179 int MM, DD, YYYY, hh, mm, ss;
180
181 calendar = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
182 tz = CFTimeZoneCopySystem();
183 CFCalendarSetTimeZone(calendar, tz);
184 CFRelease(tz);
185 CFCalendarDecomposeAbsoluteTime(calendar,
186 CFDateGetAbsoluteTime(cf),
187 "MdyHms",
188 &MM, &DD, &YYYY, &hh, &mm, &ss);
189 CFRelease(calendar);
190
191 str = CFStringCreateWithFormat(NULL,
192 formatOptions,
193 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02d"),
194 prefix1,
195 MM, DD, YYYY, hh, mm, ss);
196 return str;
197 }
198
199 if ((formatOptions == NULL) ||
200 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) {
201 prefix2 = prefix1;
202 }
203
204 if (formatOptions != NULL) {
205 nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions);
206 } else {
207 nFormatOptions = CFDictionaryCreateMutable(NULL,
208 0,
209 &kCFTypeDictionaryKeyCallBacks,
210 &kCFTypeDictionaryValueCallBacks);
211 }
212 assert(nFormatOptions != NULL);
213
214 #define N_QUICK 32
215
216 if (type == CFArrayGetTypeID()) {
217 const void * elements_q[N_QUICK];
218 const void ** elements = elements_q;
219 CFIndex i;
220 CFIndex nElements;
221 CFMutableStringRef str;
222
223 str = CFStringCreateMutable(NULL, 0);
224 CFStringAppendFormat(str, formatOptions, CFSTR("%@<array> {"), prefix1);
225
226 nElements = CFArrayGetCount(cf);
227 if (nElements > 0) {
228 if (nElements > (CFIndex)(sizeof(elements_q)/sizeof(CFTypeRef)))
229 elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
230 CFArrayGetValues(cf, CFRangeMake(0, nElements), elements);
231 for (i = 0; i < nElements; i++) {
232 CFMutableStringRef nPrefix1;
233 CFMutableStringRef nPrefix2;
234 CFStringRef nStr;
235 CFStringRef vStr;
236
237 nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%ld"), i);
238
239 nPrefix1 = CFStringCreateMutable(NULL, 0);
240 CFStringAppendFormat(nPrefix1,
241 formatOptions,
242 CFSTR("%@ %@ : "),
243 prefix2,
244 nStr);
245 nPrefix2 = CFStringCreateMutable(NULL, 0);
246 CFStringAppendFormat(nPrefix2,
247 formatOptions,
248 CFSTR("%@ "),
249 prefix2);
250
251 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
252 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
253 CFRelease(nPrefix1);
254 CFRelease(nPrefix2);
255 CFRelease(nStr);
256
257 vStr = _SCCopyDescription((CFTypeRef)elements[i], nFormatOptions);
258 CFStringAppendFormat(str,
259 formatOptions,
260 CFSTR("\n%@"),
261 vStr);
262 CFRelease(vStr);
263 }
264 if (elements != elements_q) CFAllocatorDeallocate(NULL, elements);
265 }
266 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
267
268 CFRelease(nFormatOptions);
269 return str;
270 }
271
272 if (type == CFDictionaryGetTypeID()) {
273 const void * keys_q[N_QUICK];
274 const void ** keys = keys_q;
275 CFIndex i;
276 CFIndex nElements;
277 CFMutableStringRef nPrefix1;
278 CFMutableStringRef nPrefix2;
279 CFMutableStringRef str;
280
281 str = CFStringCreateMutable(NULL, 0);
282 CFStringAppendFormat(str, formatOptions, CFSTR("%@<dictionary> {"), prefix1);
283
284 nElements = CFDictionaryGetCount(cf);
285 if (nElements > 0) {
286 CFComparatorFunction compFunc = NULL;
287 CFMutableArrayRef sortedKeys;
288
289 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
290 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
291 }
292 CFDictionaryGetKeysAndValues(cf, keys, NULL);
293
294 sortedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
295 for (i = 0; i < nElements; i++) {
296 CFArrayAppendValue(sortedKeys, (CFStringRef)keys[i]);
297 }
298
299 if (isA_CFString(keys[0])) {
300 compFunc = (CFComparatorFunction)CFStringCompare;
301 }
302 else if (isA_CFNumber(keys[0])) {
303 compFunc = (CFComparatorFunction)CFNumberCompare;
304 }
305 else if (isA_CFDate(keys[0])) {
306 compFunc = (CFComparatorFunction)CFDateCompare;
307 }
308
309 if (compFunc != NULL) {
310 CFArraySortValues(sortedKeys,
311 CFRangeMake(0, nElements),
312 compFunc,
313 NULL);
314 }
315
316 for (i = 0; i < nElements; i++) {
317 CFStringRef key;
318 CFStringRef kStr;
319 CFTypeRef val;
320 CFStringRef vStr;
321
322 key = CFArrayGetValueAtIndex(sortedKeys, i);
323 kStr = _SCCopyDescription((CFTypeRef)key, NULL);
324
325 nPrefix1 = CFStringCreateMutable(NULL, 0);
326 CFStringAppendFormat(nPrefix1,
327 formatOptions,
328 CFSTR("%@ %@ : "),
329 prefix2,
330 kStr);
331 nPrefix2 = CFStringCreateMutable(NULL, 0);
332 CFStringAppendFormat(nPrefix2,
333 formatOptions,
334 CFSTR("%@ "),
335 prefix2);
336
337 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
338 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
339 CFRelease(nPrefix1);
340 CFRelease(nPrefix2);
341 CFRelease(kStr);
342
343 val = CFDictionaryGetValue(cf, key);
344 vStr = _SCCopyDescription((CFTypeRef)val, nFormatOptions);
345 CFStringAppendFormat(str,
346 formatOptions,
347 CFSTR("\n%@"),
348 vStr);
349 CFRelease(vStr);
350 }
351
352 CFRelease(sortedKeys);
353
354 if (keys != keys_q) {
355 CFAllocatorDeallocate(NULL, keys);
356 }
357 }
358 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
359
360 CFRelease(nFormatOptions);
361 return str;
362 }
363
364 CFRelease(nFormatOptions);
365 #endif /* ENABLE_SC_FORMATTING */
366
367 return CFStringCreateWithFormat(NULL,
368 formatOptions,
369 CFSTR("%@%@"),
370 prefix1,
371 cf);
372 }
373
374
375 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
376
377 Boolean
378 _SC_isInstallEnvironment() {
379 static dispatch_once_t once;
380 static Boolean is_install;
381
382 dispatch_once(&once, ^{
383 is_install = (getenv(INSTALL_ENVIRONMENT) != NULL);
384 });
385
386 return is_install;
387 }
388
389
390 os_log_t
391 _SC_LOG_DEFAULT(void)
392 {
393 static os_log_t log = NULL;
394
395 if (log == NULL) {
396 log = os_log_create("com.apple.SystemConfiguration", "");
397 }
398
399 return log;
400 }
401
402
403 os_log_type_t
404 _SC_syslog_os_log_mapping(int level)
405 {
406 if (level < 0) {
407 level = ~level;
408 }
409
410 switch (level) {
411 case LOG_EMERG :
412 case LOG_ALERT :
413 case LOG_CRIT :
414 return OS_LOG_TYPE_ERROR;
415
416 case LOG_ERR :
417 case LOG_WARNING :
418 case LOG_NOTICE :
419 return OS_LOG_TYPE_DEFAULT;
420
421 case LOG_INFO :
422 return OS_LOG_TYPE_INFO;
423
424 case LOG_DEBUG :
425 return OS_LOG_TYPE_DEBUG;
426 }
427
428 return OS_LOG_TYPE_DEFAULT;
429 };
430
431 static void
432 __SCLog(void *ret_addr, os_log_type_t type, const char *formatString, va_list formatArguments)
433 {
434 os_log_with_args(_SC_LOG_DEFAULT(),
435 type,
436 formatString,
437 formatArguments,
438 ret_addr);
439 return;
440 }
441
442
443 static void
444 __SCPrint(FILE *stream, CFStringRef formatString, va_list formatArguments, Boolean trace, Boolean addNL)
445 {
446 char *line;
447 CFStringRef str;
448 CFIndex usedBufLen;
449
450 #ifdef ENABLE_SC_FORMATTING
451 str = _CFStringCreateWithFormatAndArgumentsAux(NULL,
452 _SCCopyDescription,
453 NULL,
454 formatString,
455 formatArguments);
456 #else /* ENABLE_SC_FORMATTING */
457 str = CFStringCreateWithFormatAndArguments (NULL,
458 NULL,
459 formatString,
460 formatArguments);
461 #endif /* !ENABLE_SC_FORMATTING */
462
463 line =_SC_cfstring_to_cstring_ext(str,
464 NULL,
465 0,
466 kCFStringEncodingUTF8,
467 (UInt8)'?',
468 &usedBufLen);
469 CFRelease(str);
470 if (!line) {
471 return;
472 }
473
474 pthread_mutex_lock(&lock);
475 if (trace) {
476 struct tm tm_now;
477 struct timeval tv_now;
478
479 (void)gettimeofday(&tv_now, NULL);
480 (void)localtime_r(&tv_now.tv_sec, &tm_now);
481 (void)fprintf(stream, "%2d:%02d:%02d.%03d ",
482 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000);
483 }
484 (void)fwrite((const void *)line, usedBufLen, 1, stream);
485 if (addNL) {
486 (void)fputc('\n', stream);
487 }
488 fflush (stream);
489 pthread_mutex_unlock(&lock);
490 CFAllocatorDeallocate(NULL, line);
491
492 return;
493 }
494
495
496 void
497 __SC_Log(int level, CFStringRef format_CF, os_log_t log, os_log_type_t type, const char *format, ...)
498 {
499 #pragma unused(level)
500 Boolean do_log = FALSE;
501 Boolean do_print = FALSE;
502 va_list args_log;
503 va_list args_print;
504
505 /*
506 * Note: The following are the expected values for _sc_log
507 *
508 * 0 if SC messages should be written to stdout/stderr
509 * 1 if SC messages should be logged w/os_log(3)
510 * 2 if SC messages should be written to stdout/stderr AND logged
511 */
512
513 if (_sc_log > 0) {
514 do_log = TRUE; // log requested
515 va_start(args_log, format);
516
517 if (_sc_log > 1) {
518 do_print = TRUE; // log AND print requested
519 va_copy(args_print, args_log);
520 }
521 } else {
522 do_print = TRUE; // print requested
523 va_start(args_print, format);
524 }
525
526 if (do_log) {
527 os_log_with_args(log,
528 type,
529 format,
530 args_log,
531 __builtin_return_address(0));
532 va_end(args_log);
533 }
534
535 if (do_print) {
536 __SCPrint(stdout,
537 format_CF,
538 args_print,
539 (_sc_log > 0), // trace
540 TRUE); // add newline
541 va_end(args_print);
542 }
543
544 return;
545 }
546
547
548 void
549 SCLog(Boolean condition, int level, CFStringRef formatString, ...)
550 {
551 va_list formatArguments;
552 va_list formatArguments_print;
553 Boolean log = FALSE;
554 Boolean print = FALSE;
555
556 if (!condition) {
557 return;
558 }
559
560 /*
561 * Note: The following are the expected values for _sc_log
562 *
563 * 0 if SC messages should be written to stdout/stderr
564 * 1 if SC messages should be logged w/os_log(3)
565 * 2 if SC messages should be written to stdout/stderr AND logged
566 */
567
568 if (_sc_log > 0) {
569 log = TRUE; // log requested
570 va_start(formatArguments, formatString);
571
572 if (_sc_log > 1) {
573 print = TRUE; // log AND print requested
574 va_copy(formatArguments_print, formatArguments);
575 }
576 } else {
577 print = TRUE; // print requested
578 va_start(formatArguments_print, formatString);
579 }
580
581 if (log) {
582 const char *__format;
583
584 __format = CFStringGetCStringPtr(formatString, kCFStringEncodingUTF8);
585 if (__format != NULL) {
586 os_log_type_t __type;
587
588 __type = _SC_syslog_os_log_mapping(level);
589 __SCLog(__builtin_return_address(0), __type, __format, formatArguments);
590 }
591 va_end(formatArguments);
592 }
593
594 if (print) {
595 __SCPrint((LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout,
596 formatString,
597 formatArguments_print,
598 (_sc_log > 0), // trace
599 TRUE); // add newline
600 va_end(formatArguments_print);
601 }
602
603 return;
604 }
605
606
607 void
608 SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...)
609 {
610 va_list formatArguments;
611
612 if (!condition) {
613 return;
614 }
615
616 va_start(formatArguments, formatString);
617 __SCPrint(stream, formatString, formatArguments, FALSE, FALSE);
618 va_end(formatArguments);
619
620 return;
621 }
622
623
624 #pragma mark -
625 #pragma mark SC error handling / logging
626
627
628 const CFStringRef kCFErrorDomainSystemConfiguration = CFSTR("com.apple.SystemConfiguration");
629
630
631 static const struct sc_errmsg {
632 int status;
633 char *message;
634 } sc_errmsgs[] = {
635 { kSCStatusAccessError, "Permission denied" },
636 { kSCStatusConnectionIgnore, "Network connection information not available at this time" },
637 { kSCStatusConnectionNoService, "Network service for connection not available" },
638 { kSCStatusFailed, "Failed!" },
639 { kSCStatusInvalidArgument, "Invalid argument" },
640 { kSCStatusKeyExists, "Key already defined" },
641 { kSCStatusLocked, "Lock already held" },
642 { kSCStatusMaxLink, "Maximum link count exceeded" },
643 { kSCStatusNeedLock, "Lock required for this operation" },
644 { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" },
645 { kSCStatusNoStoreSession, "Configuration daemon session not active" },
646 { kSCStatusNoConfigFile, "Configuration file not found" },
647 { kSCStatusNoKey, "No such key" },
648 { kSCStatusNoLink, "No such link" },
649 { kSCStatusNoPrefsSession, "Preference session not active" },
650 { kSCStatusNotifierActive, "Notifier is currently active" },
651 { kSCStatusOK, "Success!" },
652 { kSCStatusPrefsBusy, "Preferences update currently in progress" },
653 { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" },
654 { kSCStatusStale, "Write attempted on stale version of object" },
655 };
656 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
657
658 void
659 _SCErrorSet(int error)
660 {
661 __SCThreadSpecificDataRef tsd;
662
663 tsd = __SCGetThreadSpecificData();
664 tsd->_sc_error = error;
665 return;
666 }
667
668
669 CFErrorRef
670 SCCopyLastError(void)
671 {
672 CFStringRef domain;
673 CFErrorRef error;
674 int i;
675 int code;
676 __SCThreadSpecificDataRef tsd;
677 CFMutableDictionaryRef userInfo = NULL;
678
679 tsd = __SCGetThreadSpecificData();
680 code =tsd->_sc_error;
681
682 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
683 if (sc_errmsgs[i].status == code) {
684 CFStringRef str;
685
686 domain = kCFErrorDomainSystemConfiguration;
687 userInfo = CFDictionaryCreateMutable(NULL,
688 0,
689 &kCFCopyStringDictionaryKeyCallBacks,
690 &kCFTypeDictionaryValueCallBacks);
691 str = CFStringCreateWithCString(NULL,
692 sc_errmsgs[i].message,
693 kCFStringEncodingASCII);
694 CFDictionarySetValue(userInfo, kCFErrorDescriptionKey, str);
695 CFRelease(str);
696 goto done;
697 }
698 }
699
700 if ((code > 0) && (code <= ELAST)) {
701 domain = kCFErrorDomainPOSIX;
702 goto done;
703 }
704
705 domain = kCFErrorDomainMach;
706
707 done :
708
709 error = CFErrorCreate(NULL, domain, code, userInfo);
710 if (userInfo != NULL) CFRelease(userInfo);
711 return error;
712 }
713
714
715 int
716 SCError(void)
717 {
718 __SCThreadSpecificDataRef tsd;
719
720 tsd = __SCGetThreadSpecificData();
721 return tsd->_sc_error;
722 }
723
724
725 const char *
726 SCErrorString(int status)
727 {
728 int i;
729
730 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
731 if (sc_errmsgs[i].status == status) {
732 return sc_errmsgs[i].message;
733 }
734 }
735
736 if ((status > 0) && (status <= ELAST)) {
737 return strerror(status);
738 }
739
740 if ((status >= BOOTSTRAP_SUCCESS) && (status <= BOOTSTRAP_NO_MEMORY)) {
741 return bootstrap_strerror(status);
742 }
743
744 return mach_error_string(status);
745 }