]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDPrivate.c
configd-888.1.2.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDPrivate.c
1 /*
2 * Copyright (c) 2000-2016 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 * November 9, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 //#define DO_NOT_CRASH
35 //#define DO_NOT_INFORM
36
37 #define SC_LOG_HANDLE _SC_LOG_DEFAULT()
38 #include <SystemConfiguration/SystemConfiguration.h>
39 #include <SystemConfiguration/SCValidation.h>
40 #include <SystemConfiguration/SCPrivate.h>
41
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/ioctl.h>
46 #include <net/if.h>
47 #include <net/if_dl.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50
51 #include <dispatch/dispatch.h>
52
53 #include <mach/mach.h>
54 #include <mach/notify.h>
55 #include <mach/mach_error.h>
56 #include <pthread.h>
57
58 #include <execinfo.h>
59 #include <unistd.h>
60 #include <dlfcn.h>
61
62
63 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
64 #include <CoreFoundation/CFUserNotification.h>
65 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
66
67 #define N_QUICK 32
68
69
70 #pragma mark -
71 #pragma mark Miscellaneous
72
73
74 __private_extern__ char *
75 _SC_cfstring_to_cstring_ext(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEncoding encoding, UInt8 lossByte, CFIndex *usedBufLen)
76 {
77 CFIndex converted;
78 CFIndex last = 0;
79 CFIndex len;
80
81 if (cfstr == NULL) {
82 cfstr = CFSTR("");
83 }
84 len = CFStringGetLength(cfstr);
85
86 /* how much buffer space will we really need? */
87 converted = CFStringGetBytes(cfstr,
88 CFRangeMake(0, len),
89 encoding,
90 lossByte,
91 FALSE,
92 NULL,
93 0,
94 &last);
95 if (converted < len) {
96 /* if full string could not be converted */
97 if (buf != NULL) {
98 buf[0] = '\0';
99 }
100 return NULL;
101 }
102
103 if (buf != NULL) {
104 if (bufLen < (last + 1)) {
105 /* if the size of the provided buffer is too small */
106 buf[0] = '\0';
107 return NULL;
108 }
109 } else {
110 /* allocate a buffer */
111 bufLen = last + 1;
112 buf = CFAllocatorAllocate(NULL, bufLen, 0);
113 if (buf == NULL) {
114 return NULL;
115 }
116 }
117
118 (void)CFStringGetBytes(cfstr,
119 CFRangeMake(0, len),
120 encoding,
121 lossByte,
122 FALSE,
123 (UInt8 *)buf,
124 bufLen,
125 &last);
126 buf[last] = '\0';
127
128 if (usedBufLen != NULL) {
129 *usedBufLen = last;
130 }
131
132 return buf;
133 }
134
135
136 char *
137 _SC_cfstring_to_cstring(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEncoding encoding)
138 {
139 return _SC_cfstring_to_cstring_ext(cfstr, buf, bufLen, encoding, 0, NULL);
140
141 }
142
143
144 void
145 _SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen)
146 {
147 union {
148 const struct sockaddr *sa;
149 const struct sockaddr_in *sin;
150 const struct sockaddr_in6 *sin6;
151 const struct sockaddr_dl *sdl;
152 } addr;
153
154 addr.sa = address;
155
156 bzero(buf, bufLen);
157 switch (address->sa_family) {
158 case AF_INET :
159 (void)inet_ntop(addr.sin->sin_family,
160 &addr.sin->sin_addr,
161 buf,
162 (socklen_t)bufLen);
163 break;
164 case AF_INET6 : {
165 (void)inet_ntop(addr.sin6->sin6_family,
166 &addr.sin6->sin6_addr,
167 buf,
168 (socklen_t)bufLen);
169 if (addr.sin6->sin6_scope_id != 0) {
170 size_t n;
171
172 n = strlen(buf);
173 if ((n+IF_NAMESIZE+1) <= (int)bufLen) {
174 buf[n++] = '%';
175 if_indextoname(addr.sin6->sin6_scope_id, &buf[n]);
176 }
177 }
178 break;
179 }
180 default :
181 snprintf(buf, bufLen, "unexpected address family %d", address->sa_family);
182 break;
183 }
184
185 return;
186 }
187
188
189 struct sockaddr *
190 _SC_string_to_sockaddr(const char *str, sa_family_t af, void *buf, size_t bufLen)
191 {
192 union {
193 void *buf;
194 struct sockaddr *sa;
195 struct sockaddr_in *sin;
196 struct sockaddr_in6 *sin6;
197 } addr;
198
199 if (buf == NULL) {
200 bufLen = sizeof(struct sockaddr_storage);
201 addr.buf = CFAllocatorAllocate(NULL, bufLen, 0);
202 } else {
203 addr.buf = buf;
204 }
205
206 bzero(addr.buf, bufLen);
207 if (((af == AF_UNSPEC) || (af == AF_INET)) &&
208 (bufLen >= sizeof(struct sockaddr_in)) &&
209 inet_aton(str, &addr.sin->sin_addr) == 1) {
210 // if IPv4 address
211 addr.sin->sin_len = sizeof(struct sockaddr_in);
212 addr.sin->sin_family = AF_INET;
213 } else if (((af == AF_UNSPEC) || (af == AF_INET6)) &&
214 (bufLen >= sizeof(struct sockaddr_in6)) &&
215 inet_pton(AF_INET6, str, &addr.sin6->sin6_addr) == 1) {
216 // if IPv6 address
217 char *p;
218
219 addr.sin6->sin6_len = sizeof(struct sockaddr_in6);
220 addr.sin6->sin6_family = AF_INET6;
221
222 p = strchr(str, '%');
223 if (p != NULL) {
224 addr.sin6->sin6_scope_id = if_nametoindex(p + 1);
225 }
226
227 if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6->sin6_addr) ||
228 IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6->sin6_addr)) {
229 uint16_t if_index;
230
231 if_index = ntohs(addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1]);
232 addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
233 if (addr.sin6->sin6_scope_id == 0) {
234 // use the scope id that was embedded in the [link local] IPv6 address
235 addr.sin6->sin6_scope_id = if_index;
236 }
237 }
238 } else {
239 if (addr.buf != buf) {
240 CFAllocatorDeallocate(NULL, addr.buf);
241 }
242 addr.buf = NULL;
243 }
244
245 return addr.sa;
246 }
247
248
249 void
250 _SC_sendMachMessage(mach_port_t port, mach_msg_id_t msg_id)
251 {
252 mach_msg_empty_send_t msg;
253 mach_msg_option_t options;
254 kern_return_t status;
255
256 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
257 msg.header.msgh_size = sizeof(msg);
258 msg.header.msgh_remote_port = port;
259 msg.header.msgh_local_port = MACH_PORT_NULL;
260 msg.header.msgh_id = msg_id;
261 options = MACH_SEND_TIMEOUT;
262 status = mach_msg(&msg.header, /* msg */
263 MACH_SEND_MSG|options, /* options */
264 msg.header.msgh_size, /* send_size */
265 0, /* rcv_size */
266 MACH_PORT_NULL, /* rcv_name */
267 0, /* timeout */
268 MACH_PORT_NULL); /* notify */
269 if (status != MACH_MSG_SUCCESS) {
270 mach_msg_destroy(&msg.header);
271 }
272
273 return;
274 }
275
276
277 CFStringRef
278 _SC_trimDomain(CFStringRef domain)
279 {
280 CFIndex length;
281
282 if (!isA_CFString(domain)) {
283 return NULL;
284 }
285
286 // remove any leading/trailing dots
287 length = CFStringGetLength(domain);
288 if ((length > 0) &&
289 (CFStringFindWithOptions(domain,
290 CFSTR("."),
291 CFRangeMake(0, 1),
292 kCFCompareAnchored,
293 NULL) ||
294 CFStringFindWithOptions(domain,
295 CFSTR("."),
296 CFRangeMake(0, length),
297 kCFCompareAnchored|kCFCompareBackwards,
298 NULL))) {
299 CFMutableStringRef trimmed;
300
301 trimmed = CFStringCreateMutableCopy(NULL, 0, domain);
302 CFStringTrim(trimmed, CFSTR("."));
303 domain = (CFStringRef)trimmed;
304 length = CFStringGetLength(domain);
305 } else {
306 CFRetain(domain);
307 }
308
309 if (length == 0) {
310 CFRelease(domain);
311 domain = NULL;
312 }
313
314 return domain;
315 }
316
317
318 CFStringRef
319 _SC_hw_model(Boolean trim)
320 {
321 static CFStringRef model = NULL;
322 static CFStringRef model_trimmed = NULL;
323 static dispatch_once_t once;
324
325 dispatch_once(&once, ^{
326 char *cp;
327 char hwModel[64];
328 int mib[] = { CTL_HW, HW_MODEL };
329 size_t n = sizeof(hwModel);
330 int ret;
331
332 // get HW model name
333 bzero(&hwModel, sizeof(hwModel));
334 ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &hwModel, &n, NULL, 0);
335 if (ret != 0) {
336 SC_log(LOG_NOTICE, "sysctl() CTL_HW/HW_MODEL failed: %s", strerror(errno));
337 return;
338 }
339 hwModel[sizeof(hwModel) - 1] = '\0';
340 model = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII);
341
342 // and the "trimmed" name
343 // ... remove everything after (and including) a comma
344 // ... and then any trailing digits
345 cp = index(hwModel, ',');
346 if (cp != NULL) {
347 *cp = '\0';
348 }
349 n = strlen(hwModel) - 1;
350 while (n > 0) {
351 if (!isdigit(hwModel[n])) {
352 break;
353 }
354 hwModel[n--] = '\0';
355 }
356 model_trimmed = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII);
357 });
358
359 return trim ? model_trimmed : model;
360 }
361
362
363 #pragma mark -
364 #pragma mark Serialization
365
366
367 Boolean
368 _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dataLen)
369 {
370 CFDataRef myXml;
371
372 if ((xml == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
373 /* if not keeping track of allocated space */
374 return FALSE;
375 }
376
377 myXml = CFPropertyListCreateData(NULL,
378 obj,
379 kCFPropertyListBinaryFormat_v1_0,
380 0,
381 NULL);
382 if (myXml == NULL) {
383 SC_log(LOG_NOTICE, "CFPropertyListCreateData() failed");
384 if (xml != NULL) {
385 *xml = NULL;
386 }
387 if ((dataRef != NULL) && (dataLen != NULL)) {
388 *dataLen = 0;
389 *dataRef = NULL;
390 }
391 return FALSE;
392 }
393
394 if (xml != NULL) {
395 *xml = myXml;
396 if ((dataRef != NULL) && (dataLen != NULL)) {
397 *dataRef = (void *)CFDataGetBytePtr(myXml);
398 *dataLen = CFDataGetLength(myXml);
399 }
400 } else {
401 mach_msg_type_number_t len;
402 kern_return_t status;
403
404 status = vm_read(mach_task_self(),
405 (vm_address_t)CFDataGetBytePtr(myXml), // address
406 (vm_size_t) CFDataGetLength(myXml), // size
407 (void *)dataRef,
408 &len);
409 if (status != KERN_SUCCESS) {
410 SC_log(LOG_NOTICE, "vm_read() failed: %s", mach_error_string(status));
411 CFRelease(myXml);
412 *dataRef = NULL;
413 *dataLen = 0;
414 return FALSE;
415 }
416
417 *dataLen = len;
418 CFRelease(myXml);
419 }
420
421 return TRUE;
422 }
423
424
425 Boolean
426 _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen)
427 {
428 CFErrorRef error = NULL;
429
430 if (xml == NULL) {
431 kern_return_t status;
432
433 xml = CFDataCreateWithBytesNoCopy(NULL, (void *)dataRef, dataLen, kCFAllocatorNull);
434 *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error);
435 CFRelease(xml);
436
437 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
438 if (status != KERN_SUCCESS) {
439 SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status));
440 /* non-fatal???, proceed */
441 }
442 } else {
443 *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error);
444 }
445
446 if (*obj == NULL) {
447 if (error != NULL) {
448 SC_log(LOG_NOTICE, "CFPropertyListCreateWithData() faled: %@", error);
449 CFRelease(error);
450 }
451 _SCErrorSet(kSCStatusFailed);
452 return FALSE;
453 }
454
455 return TRUE;
456 }
457
458
459 Boolean
460 _SCSerializeString(CFStringRef str, CFDataRef *data, void **dataRef, CFIndex *dataLen)
461 {
462 CFDataRef myData;
463
464 if (!isA_CFString(str)) {
465 /* if not a CFString */
466 return FALSE;
467 }
468
469 if ((data == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
470 /* if not keeping track of allocated space */
471 return FALSE;
472 }
473
474 myData = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
475 if (myData == NULL) {
476 SC_log(LOG_NOTICE, "CFStringCreateExternalRepresentation() failed");
477 if (data != NULL) {
478 *data = NULL;
479 }
480 if ((dataRef != NULL) && (dataLen != NULL)) {
481 *dataRef = NULL;
482 *dataLen = 0;
483 }
484 return FALSE;
485 }
486
487 if (data != NULL) {
488 *data = myData;
489 if ((dataRef != NULL) && (dataLen != NULL)) {
490 *dataRef = (void *)CFDataGetBytePtr(myData);
491 *dataLen = CFDataGetLength(myData);
492 }
493 } else {
494 mach_msg_type_number_t len;
495 kern_return_t status;
496
497 *dataLen = CFDataGetLength(myData);
498 status = vm_read(mach_task_self(),
499 (vm_address_t)CFDataGetBytePtr(myData), // address
500 *dataLen, // size
501 (void *)dataRef,
502 &len);
503 if (status != KERN_SUCCESS) {
504 SC_log(LOG_NOTICE, "vm_read() failed: %s", mach_error_string(status));
505 CFRelease(myData);
506 *dataRef = NULL;
507 *dataLen = 0;
508 return FALSE;
509 }
510
511 *dataLen = len;
512 CFRelease(myData);
513 }
514
515 return TRUE;
516 }
517
518
519 Boolean
520 _SCUnserializeString(CFStringRef *str, CFDataRef utf8, void *dataRef, CFIndex dataLen)
521 {
522 if (utf8 == NULL) {
523 kern_return_t status;
524
525 utf8 = CFDataCreateWithBytesNoCopy(NULL, dataRef, dataLen, kCFAllocatorNull);
526 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
527 CFRelease(utf8);
528
529 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
530 if (status != KERN_SUCCESS) {
531 SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status));
532 /* non-fatal???, proceed */
533 }
534 } else {
535 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
536 }
537
538 if (*str == NULL) {
539 SC_log(LOG_NOTICE, "CFStringCreateFromExternalRepresentation() failed");
540 return FALSE;
541 }
542
543 return TRUE;
544 }
545
546
547 Boolean
548 _SCSerializeData(CFDataRef data, void **dataRef, CFIndex *dataLen)
549 {
550 mach_msg_type_number_t len;
551 kern_return_t status;
552
553 if (!isA_CFData(data)) {
554 /* if not a CFData */
555 return FALSE;
556 }
557
558 *dataLen = CFDataGetLength(data);
559 status = vm_read(mach_task_self(),
560 (vm_address_t)CFDataGetBytePtr(data), // address
561 *dataLen, // size
562 (void *)dataRef,
563 &len);
564 if (status != KERN_SUCCESS) {
565 SC_log(LOG_NOTICE, "vm_read() failed: %s", mach_error_string(status));
566 *dataRef = NULL;
567 *dataLen = 0;
568 return FALSE;
569 }
570
571 *dataLen = len;
572
573 return TRUE;
574 }
575
576
577 Boolean
578 _SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen)
579 {
580 kern_return_t status;
581
582 *data = CFDataCreate(NULL, dataRef, dataLen);
583 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
584 if (status != KERN_SUCCESS) {
585 SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status));
586 _SCErrorSet(kSCStatusFailed);
587 return FALSE;
588 }
589
590 return TRUE;
591 }
592
593
594 CF_RETURNS_RETAINED CFDictionaryRef
595 _SCSerializeMultiple(CFDictionaryRef dict)
596 {
597 CFIndex i;
598 const void * keys_q[N_QUICK];
599 const void ** keys = keys_q;
600 CFIndex nElements;
601 CFDictionaryRef newDict = NULL;
602 const void * pLists_q[N_QUICK];
603 const void ** pLists = pLists_q;
604 const void * values_q[N_QUICK];
605 const void ** values = values_q;
606
607 nElements = CFDictionaryGetCount(dict);
608 if (nElements > 0) {
609 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
610 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
611 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
612 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFDataRef), 0);
613 }
614 bzero(pLists, nElements * sizeof(CFDataRef));
615
616 CFDictionaryGetKeysAndValues(dict, keys, values);
617 for (i = 0; i < nElements; i++) {
618 pLists[i] = NULL;
619 if (!_SCSerialize((CFPropertyListRef)values[i], (CFDataRef *)&pLists[i], NULL, NULL)) {
620 goto done;
621 }
622 }
623 }
624
625 newDict = CFDictionaryCreate(NULL,
626 keys,
627 pLists,
628 nElements,
629 &kCFTypeDictionaryKeyCallBacks,
630 &kCFTypeDictionaryValueCallBacks);
631
632 done :
633
634 if (nElements > 0) {
635 for (i = 0; i < nElements; i++) {
636 if (pLists[i] != NULL) CFRelease((CFDataRef)pLists[i]);
637 }
638
639 if (keys != keys_q) {
640 CFAllocatorDeallocate(NULL, keys);
641 CFAllocatorDeallocate(NULL, values);
642 CFAllocatorDeallocate(NULL, pLists);
643 }
644 }
645
646 return newDict;
647 }
648
649
650 CF_RETURNS_RETAINED
651 CFDictionaryRef
652 _SCUnserializeMultiple(CFDictionaryRef dict)
653 {
654 const void * keys_q[N_QUICK];
655 const void ** keys = keys_q;
656 CFIndex nElements;
657 CFDictionaryRef newDict = NULL;
658 const void * pLists_q[N_QUICK];
659 const void ** pLists = pLists_q;
660 const void * values_q[N_QUICK];
661 const void ** values = values_q;
662
663 nElements = CFDictionaryGetCount(dict);
664 if (nElements > 0) {
665 CFIndex i;
666
667 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
668 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
669 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
670 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
671 }
672 bzero(pLists, nElements * sizeof(CFTypeRef));
673
674 CFDictionaryGetKeysAndValues(dict, keys, values);
675 for (i = 0; i < nElements; i++) {
676 if (!_SCUnserialize((CFPropertyListRef *)&pLists[i], values[i], NULL, 0)) {
677 goto done;
678 }
679 }
680 }
681
682 newDict = CFDictionaryCreate(NULL,
683 keys,
684 pLists,
685 nElements,
686 &kCFTypeDictionaryKeyCallBacks,
687 &kCFTypeDictionaryValueCallBacks);
688
689 done :
690
691 if (nElements > 0) {
692 CFIndex i;
693
694 for (i = 0; i < nElements; i++) {
695 if (pLists[i]) CFRelease(pLists[i]);
696 }
697
698 if (keys != keys_q) {
699 CFAllocatorDeallocate(NULL, keys);
700 CFAllocatorDeallocate(NULL, values);
701 CFAllocatorDeallocate(NULL, pLists);
702 }
703 }
704
705 return newDict;
706 }
707
708
709 #pragma mark -
710
711
712 CFPropertyListRef
713 _SCCreatePropertyListFromResource(CFURLRef url)
714 {
715 CFDictionaryRef dict = NULL;
716 SInt64 fileLen = 0;
717 Boolean ok;
718 CFReadStreamRef readStream;
719 CFNumberRef val = NULL;
720
721 if (!CFURLCopyResourcePropertyForKey(url, kCFURLFileSizeKey, &val, NULL) ||
722 (val == NULL)) {
723 // if size not available
724 SC_log(LOG_NOTICE, "CFURLCopyResourcePropertyForKey() size not available: %@", url);
725 return NULL;
726 }
727
728 ok = CFNumberGetValue(val, kCFNumberSInt64Type, &fileLen);
729 CFRelease(val);
730 if (!ok || (fileLen == 0)) {
731 // if empty or size too large
732 SC_log(LOG_INFO, "_SCCreatePropertyListFromResource() improper size: %@", url);
733 return NULL;
734 }
735
736 readStream = CFReadStreamCreateWithFile(NULL, url);
737 if (readStream != NULL) {
738 if (CFReadStreamOpen(readStream)) {
739 UInt8 *buffer;
740 CFIndex dataLen;
741
742 buffer = CFAllocatorAllocate(NULL, (CFIndex)fileLen, 0);
743 dataLen = CFReadStreamRead(readStream, buffer, (CFIndex)fileLen);
744 if (dataLen == (CFIndex)fileLen) {
745 CFDataRef data;
746
747 data = CFDataCreateWithBytesNoCopy(NULL, buffer, (CFIndex)fileLen, kCFAllocatorNull);
748 if (data != NULL) {
749 dict = CFPropertyListCreateWithData(NULL,
750 data,
751 kCFPropertyListImmutable,
752 NULL,
753 NULL);
754 CFRelease(data);
755 }
756 }
757 CFAllocatorDeallocate(NULL, buffer);
758 CFReadStreamClose(readStream);
759 }
760 CFRelease(readStream);
761 }
762
763 return dict;
764 }
765
766
767 #pragma mark -
768 #pragma mark CFRunLoop scheduling
769
770
771 __private_extern__ void
772 _SC_signalRunLoop(CFTypeRef obj, CFRunLoopSourceRef rls, CFArrayRef rlList)
773 {
774 CFRunLoopRef rl = NULL;
775 CFRunLoopRef rl1 = NULL;
776 CFIndex i;
777 CFIndex n = CFArrayGetCount(rlList);
778
779 if (n == 0) {
780 return;
781 }
782
783 /* get first runLoop for this object */
784 for (i = 0; i < n; i += 3) {
785 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
786 continue;
787 }
788
789 rl1 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
790 break;
791 }
792
793 if (rl1 == NULL) {
794 /* if not scheduled */
795 return;
796 }
797
798 /* check if we have another runLoop for this object */
799 rl = rl1;
800 for (i = i+3; i < n; i += 3) {
801 CFRunLoopRef rl2;
802
803 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
804 continue;
805 }
806
807 rl2 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
808 if (!CFEqual(rl1, rl2)) {
809 /* we've got more than one runLoop */
810 rl = NULL;
811 break;
812 }
813 }
814
815 if (rl != NULL) {
816 /* if we only have one runLoop */
817 CFRunLoopWakeUp(rl);
818 return;
819 }
820
821 /* more than one different runLoop, so we must pick one */
822 for (i = 0; i < n; i+=3) {
823 CFStringRef rlMode;
824
825 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
826 continue;
827 }
828
829 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
830 rlMode = CFRunLoopCopyCurrentMode(rl);
831 if (rlMode != NULL) {
832 Boolean waiting;
833
834 waiting = (CFRunLoopIsWaiting(rl) && CFRunLoopContainsSource(rl, rls, rlMode));
835 CFRelease(rlMode);
836 if (waiting) {
837 /* we've found a runLoop that's "ready" */
838 CFRunLoopWakeUp(rl);
839 return;
840 }
841 }
842 }
843
844 /* didn't choose one above, so choose first */
845 CFRunLoopWakeUp(rl1);
846 return;
847 }
848
849
850 __private_extern__ Boolean
851 _SC_isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
852 {
853 CFIndex i;
854 CFIndex n = CFArrayGetCount(rlList);
855
856 for (i = 0; i < n; i += 3) {
857 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
858 continue;
859 }
860 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
861 continue;
862 }
863 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
864 continue;
865 }
866 return TRUE;
867 }
868
869 return FALSE;
870 }
871
872
873 __private_extern__ void
874 _SC_schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
875 {
876 CFArrayAppendValue(rlList, obj);
877 CFArrayAppendValue(rlList, runLoop);
878 CFArrayAppendValue(rlList, runLoopMode);
879
880 return;
881 }
882
883
884 __private_extern__ Boolean
885 _SC_unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all)
886 {
887 CFIndex i = 0;
888 Boolean found = FALSE;
889 CFIndex n = CFArrayGetCount(rlList);
890
891 while (i < n) {
892 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
893 i += 3;
894 continue;
895 }
896 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
897 i += 3;
898 continue;
899 }
900 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
901 i += 3;
902 continue;
903 }
904
905 found = TRUE;
906
907 CFArrayRemoveValueAtIndex(rlList, i + 2);
908 CFArrayRemoveValueAtIndex(rlList, i + 1);
909 CFArrayRemoveValueAtIndex(rlList, i);
910
911 if (!all) {
912 return found;
913 }
914
915 n -= 3;
916 }
917
918 return found;
919 }
920
921
922 #pragma mark -
923 #pragma mark Bundle
924
925
926 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
927 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
928
929 #define SUFFIX_SYM "~sym"
930 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
931
932 #define SUFFIX_DST "~dst"
933
934
935 CFBundleRef
936 _SC_CFBundleGet(void)
937 {
938 static CFBundleRef bundle = NULL;
939 char *env;
940 size_t len;
941 CFURLRef url;
942
943 if (bundle != NULL) {
944 goto done;
945 }
946
947 bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID);
948 if (bundle != NULL) {
949 CFRetain(bundle); // we want to hold a reference to the bundle
950 goto done;
951 } else {
952 SC_log(LOG_NOTICE, "could not get CFBundle for \"%@\". Trying harder...",
953 SYSTEMCONFIGURATION_BUNDLE_ID);
954 }
955
956 // if appropriate (e.g. when debugging), try a bit harder
957
958 env = getenv("DYLD_FRAMEWORK_PATH");
959 len = (env != NULL) ? strlen(env) : 0;
960
961 if (len > 0) { /* We are debugging */
962
963 // trim any trailing slashes
964 while (len > 1) {
965 if (env[len - 1] != '/') {
966 break;
967 }
968 len--;
969 }
970
971 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst"
972 if ((len > SUFFIX_SYM_LEN) &&
973 (strncmp(&env[len - SUFFIX_SYM_LEN], SUFFIX_SYM, SUFFIX_SYM_LEN) == 0) &&
974 ((len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN) < MAXPATHLEN)) {
975 char path[MAXPATHLEN];
976
977 strlcpy(path, env, sizeof(path));
978 strlcpy(&path[len - SUFFIX_SYM_LEN], SUFFIX_DST, sizeof(path) - (len - SUFFIX_SYM_LEN));
979 strlcat(&path[len], SYSTEMCONFIGURATION_FRAMEWORK_PATH, sizeof(path) - len);
980
981 url = CFURLCreateFromFileSystemRepresentation(NULL,
982 (UInt8 *)path,
983 len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN,
984 TRUE);
985 bundle = CFBundleCreate(NULL, url);
986 CFRelease(url);
987 }
988 }
989
990 if (bundle == NULL) { /* Try a more "direct" route to get the bundle */
991
992 url = CFURLCreateWithFileSystemPath(NULL,
993 CFSTR(SYSTEMCONFIGURATION_FRAMEWORK_PATH),
994 kCFURLPOSIXPathStyle,
995 TRUE);
996
997 bundle = CFBundleCreate(NULL, url);
998 CFRelease(url);
999 }
1000
1001 if (bundle == NULL) {
1002 SC_log(LOG_ERR, "could not get CFBundle for \"%@\"", SYSTEMCONFIGURATION_BUNDLE_ID);
1003 }
1004
1005 done:
1006 return bundle;
1007 }
1008
1009
1010 CFStringRef
1011 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName)
1012 {
1013 CFURLRef resourcesURL;
1014 CFStringRef str = NULL;
1015 CFDictionaryRef table = NULL;
1016 CFURLRef url;
1017
1018 if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) {
1019 tableName = CFSTR("Localizable");
1020 }
1021
1022 /*
1023 * First, try getting the requested string using a manually constructed
1024 * URL to <bundle>/Resources/English.lproj/<tableName>.strings. Do this
1025 * because CFBundleCopyResourceURLForLocalization() uses CFPreferences
1026 * to get the preferred localizations, CFPreferences talks to
1027 * OpenDirectory, and OpenDirectory tries to obtain the platform UUID.
1028 * On machines where the platform UUID is set by InterfaceNamer, a
1029 * deadlock can occur if InterfaceNamer calls
1030 * CFBundleCopyResourceURLForLocalization() before setting the
1031 * platform UUID in the kernel.
1032 */
1033 resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
1034 if (resourcesURL != NULL) {
1035 CFURLRef en_lproj;
1036 CFStringRef fileName;
1037
1038 en_lproj = CFURLCreateCopyAppendingPathComponent(NULL,
1039 resourcesURL,
1040 CFSTR("English.lproj"),
1041 TRUE);
1042 fileName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.strings"), tableName);
1043 url = CFURLCreateCopyAppendingPathComponent(NULL, en_lproj, fileName, FALSE);
1044 CFRelease(en_lproj);
1045 CFRelease(fileName);
1046 CFRelease(resourcesURL);
1047
1048 table = _SCCreatePropertyListFromResource(url);
1049 CFRelease(url);
1050 }
1051
1052 if (table == NULL) {
1053 url = CFBundleCopyResourceURLForLocalization(bundle,
1054 tableName,
1055 CFSTR("strings"),
1056 NULL,
1057 CFSTR("English"));
1058 if (url != NULL) {
1059 table = _SCCreatePropertyListFromResource(url);
1060 CFRelease(url);
1061 } else {
1062 SC_log(LOG_ERR, "failed to get resource url: {bundle:%@, table: %@}", bundle, tableName);
1063 }
1064 }
1065
1066 if (table != NULL) {
1067 if (isA_CFDictionary(table)) {
1068 str = CFDictionaryGetValue(table, key);
1069 if (str != NULL) {
1070 CFRetain(str);
1071 }
1072 }
1073
1074 CFRelease(table);
1075 }
1076
1077 if (str == NULL) {
1078 str = CFRetain(value);
1079 }
1080
1081 return str;
1082 }
1083
1084
1085 #pragma mark -
1086 #pragma mark Mach port / CFMachPort management
1087
1088
1089 CFMachPortRef
1090 _SC_CFMachPortCreateWithPort(const char *portDescription,
1091 mach_port_t portNum,
1092 CFMachPortCallBack callout,
1093 CFMachPortContext *context)
1094 {
1095 CFMachPortRef port;
1096 Boolean shouldFree = FALSE;
1097
1098 port = CFMachPortCreateWithPort(NULL, portNum, callout, context, &shouldFree);
1099 if ((port == NULL) || shouldFree) {
1100 CFStringRef err;
1101 char *crash_info = NULL;
1102
1103 SC_log(LOG_NOTICE, "%s: CFMachPortCreateWithPort() failed , port = %p",
1104 portDescription,
1105 (void *)(uintptr_t)portNum);
1106 if (port != NULL) {
1107 err = CFStringCreateWithFormat(NULL, NULL,
1108 CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"),
1109 portDescription, port);
1110 } else {
1111 err = CFStringCreateWithFormat(NULL, NULL,
1112 CFSTR("%s: CFMachPortCreateWithPort returned NULL"),
1113 portDescription);
1114 }
1115 crash_info = _SC_cfstring_to_cstring(err, NULL, 0, kCFStringEncodingASCII);
1116 if (err != NULL) CFRelease(err);
1117
1118
1119 err = CFStringCreateWithFormat(NULL,
1120 NULL,
1121 CFSTR("A recycled mach_port has been detected by \"%s\"."),
1122 getprogname());
1123 _SC_crash(crash_info, CFSTR("CFMachPort error"), err);
1124 CFAllocatorDeallocate(NULL, crash_info);
1125 if (err != NULL) CFRelease(err);
1126 }
1127
1128 return port;
1129 }
1130
1131
1132 #pragma mark -
1133 #pragma mark DOS encoding/codepage
1134
1135
1136 #if !TARGET_OS_IPHONE
1137 void
1138 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding,
1139 UInt32 macRegion,
1140 CFStringEncoding *dosEncoding,
1141 UInt32 *dosCodepage)
1142 {
1143 switch (macEncoding) {
1144 case kCFStringEncodingMacRoman:
1145 if (macRegion != 0) /* anything non-zero is not US */
1146 *dosEncoding = kCFStringEncodingDOSLatin1;
1147 else /* US region */
1148 *dosEncoding = kCFStringEncodingDOSLatinUS;
1149 break;
1150
1151 case kCFStringEncodingMacJapanese:
1152 *dosEncoding = kCFStringEncodingDOSJapanese;
1153 break;
1154
1155 case kCFStringEncodingMacChineseTrad:
1156 *dosEncoding = kCFStringEncodingDOSChineseTrad;
1157 break;
1158
1159 case kCFStringEncodingMacKorean:
1160 *dosEncoding = kCFStringEncodingDOSKorean;
1161 break;
1162
1163 case kCFStringEncodingMacArabic:
1164 *dosEncoding = kCFStringEncodingDOSArabic;
1165 break;
1166
1167 case kCFStringEncodingMacHebrew:
1168 *dosEncoding = kCFStringEncodingDOSHebrew;
1169 break;
1170
1171 case kCFStringEncodingMacGreek:
1172 *dosEncoding = kCFStringEncodingDOSGreek;
1173 break;
1174
1175 case kCFStringEncodingMacCyrillic:
1176 *dosEncoding = kCFStringEncodingDOSCyrillic;
1177 break;
1178
1179 case kCFStringEncodingMacThai:
1180 *dosEncoding = kCFStringEncodingDOSThai;
1181 break;
1182
1183 case kCFStringEncodingMacChineseSimp:
1184 *dosEncoding = kCFStringEncodingDOSChineseSimplif;
1185 break;
1186
1187 case kCFStringEncodingMacCentralEurRoman:
1188 *dosEncoding = kCFStringEncodingDOSLatin2;
1189 break;
1190
1191 case kCFStringEncodingMacTurkish:
1192 *dosEncoding = kCFStringEncodingDOSTurkish;
1193 break;
1194
1195 case kCFStringEncodingMacCroatian:
1196 *dosEncoding = kCFStringEncodingDOSLatin2;
1197 break;
1198
1199 case kCFStringEncodingMacIcelandic:
1200 *dosEncoding = kCFStringEncodingDOSIcelandic;
1201 break;
1202
1203 case kCFStringEncodingMacRomanian:
1204 *dosEncoding = kCFStringEncodingDOSLatin2;
1205 break;
1206
1207 case kCFStringEncodingMacFarsi:
1208 *dosEncoding = kCFStringEncodingDOSArabic;
1209 break;
1210
1211 case kCFStringEncodingMacUkrainian:
1212 *dosEncoding = kCFStringEncodingDOSCyrillic;
1213 break;
1214
1215 default:
1216 *dosEncoding = kCFStringEncodingDOSLatin1;
1217 break;
1218 }
1219
1220 *dosCodepage = CFStringConvertEncodingToWindowsCodepage(*dosEncoding);
1221 return;
1222 }
1223 #endif // !TARGET_OS_IPHONE
1224
1225
1226 #pragma mark -
1227 #pragma mark Debugging
1228
1229
1230 /*
1231 * print status of in-use mach ports
1232 */
1233 void
1234 _SC_logMachPortStatus(void)
1235 {
1236 kern_return_t status;
1237 mach_port_name_array_t ports;
1238 mach_port_type_array_t types;
1239 mach_msg_type_number_t pi, pn, tn;
1240 CFMutableStringRef str;
1241
1242 SC_log(LOG_DEBUG, "----------");
1243
1244 /* report on ALL mach ports associated with this task */
1245 status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn);
1246 if (status == MACH_MSG_SUCCESS) {
1247 str = CFStringCreateMutable(NULL, 0);
1248 for (pi = 0; pi < pn; pi++) {
1249 char rights[16], *rp = &rights[0];
1250
1251 if (types[pi] != MACH_PORT_TYPE_NONE) {
1252 *rp++ = ' ';
1253 *rp++ = '(';
1254 if (types[pi] & MACH_PORT_TYPE_SEND)
1255 *rp++ = 'S';
1256 if (types[pi] & MACH_PORT_TYPE_RECEIVE)
1257 *rp++ = 'R';
1258 if (types[pi] & MACH_PORT_TYPE_SEND_ONCE)
1259 *rp++ = 'O';
1260 if (types[pi] & MACH_PORT_TYPE_PORT_SET)
1261 *rp++ = 'P';
1262 if (types[pi] & MACH_PORT_TYPE_DEAD_NAME)
1263 *rp++ = 'D';
1264 *rp++ = ')';
1265 }
1266 *rp = '\0';
1267 CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights);
1268 }
1269 SC_log(LOG_DEBUG, "Task ports (n=%d):%@", pn, str);
1270 CFRelease(str);
1271 }
1272
1273 return;
1274 }
1275
1276
1277 void
1278 _SC_logMachPortReferences(const char *str, mach_port_t port)
1279 {
1280 const char *blanks = " ";
1281 char buf[60];
1282 mach_port_type_t pt;
1283 mach_port_status_t recv_status = { 0 };
1284 mach_port_urefs_t refs_send = 0;
1285 mach_port_urefs_t refs_recv = 0;
1286 mach_port_urefs_t refs_once = 0;
1287 mach_port_urefs_t refs_pset = 0;
1288 mach_port_urefs_t refs_dead = 0;
1289 kern_return_t status;
1290
1291 buf[0] = '\0';
1292 if (str != NULL) {
1293 static int is_configd = -1;
1294
1295 if (is_configd == -1) {
1296 is_configd = (strcmp(getprogname(), _SC_SERVER_PROG) == 0);
1297 }
1298 if (is_configd == 1) {
1299 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1300 strlcpy(buf,
1301 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1302 sizeof(buf));
1303 }
1304
1305 // add provided string
1306 strlcat(buf, str, sizeof(buf));
1307
1308 // fill
1309 strlcat(buf, blanks, sizeof(buf));
1310 if (strcmp(&buf[sizeof(buf) - 3], " ") == 0) {
1311 buf[sizeof(buf) - 3] = ':';
1312 }
1313 }
1314
1315 status = mach_port_type(mach_task_self(), port, &pt);
1316 if (status != KERN_SUCCESS) {
1317 SC_log(LOG_DEBUG, "%smach_port_type(..., 0x%x): %s",
1318 buf,
1319 port,
1320 mach_error_string(status));
1321 return;
1322 }
1323
1324 if ((pt & MACH_PORT_TYPE_SEND) != 0) {
1325 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs_send);
1326 if (status != KERN_SUCCESS) {
1327 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s",
1328 buf,
1329 port,
1330 mach_error_string(status));
1331 return;
1332 }
1333 }
1334
1335 if ((pt & MACH_PORT_TYPE_RECEIVE) != 0) {
1336 mach_msg_type_number_t count;
1337
1338 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, &refs_recv);
1339 if (status != KERN_SUCCESS) {
1340 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s",
1341 buf,
1342 port,
1343 mach_error_string(status));
1344 return;
1345 }
1346
1347 count = MACH_PORT_RECEIVE_STATUS_COUNT;
1348 status = mach_port_get_attributes(mach_task_self(),
1349 port,
1350 MACH_PORT_RECEIVE_STATUS,
1351 (mach_port_info_t)&recv_status,
1352 &count);
1353 if (status != KERN_SUCCESS) {
1354 SC_log(LOG_DEBUG, "%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s",
1355 buf,
1356 port,
1357 mach_error_string(status));
1358 return;
1359 }
1360 }
1361
1362 if ((pt & MACH_PORT_TYPE_SEND_ONCE) != 0) {
1363 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once);
1364 if (status != KERN_SUCCESS) {
1365 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s",
1366 buf,
1367 port,
1368 mach_error_string(status));
1369 return;
1370 }
1371 }
1372
1373 if ((pt & MACH_PORT_TYPE_PORT_SET) != 0) {
1374 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, &refs_pset);
1375 if (status != KERN_SUCCESS) {
1376 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s",
1377 buf,
1378 port,
1379 mach_error_string(status));
1380 return;
1381 }
1382 }
1383
1384 if ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) {
1385 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead);
1386 if (status != KERN_SUCCESS) {
1387 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s",
1388 buf,
1389 port,
1390 mach_error_string(status));
1391 return;
1392 }
1393 }
1394
1395 SC_log(LOG_DEBUG, "%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s",
1396 buf,
1397 port,
1398 port,
1399 refs_send,
1400 refs_recv,
1401 refs_once,
1402 refs_pset,
1403 refs_dead,
1404 recv_status.mps_nsrequest ? ", no more senders" : "",
1405 ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) ? ", dead name request" : "");
1406
1407 return;
1408 }
1409
1410
1411 CFStringRef
1412 _SC_copyBacktrace()
1413 {
1414 int n;
1415 void *stack[64];
1416 char **symbols;
1417 CFMutableStringRef trace;
1418
1419 n = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
1420 if (n == -1) {
1421 SC_log(LOG_NOTICE, "backtrace() failed: %s", strerror(errno));
1422 return NULL;
1423 }
1424
1425 trace = CFStringCreateMutable(NULL, 0);
1426
1427 symbols = backtrace_symbols(stack, n);
1428 if (symbols != NULL) {
1429 int i;
1430
1431 for (i = 0; i < n; i++) {
1432 CFStringAppendFormat(trace, NULL, CFSTR("%s\n"), symbols[i]);
1433 }
1434
1435 free(symbols);
1436 }
1437
1438 return trace;
1439 }
1440
1441
1442 /* CrashReporter info */
1443 #if !TARGET_OS_IPHONE
1444 #include <CrashReporterClient.h>
1445 #else // !TARGET_OS_IPHONE
1446 const char *__crashreporter_info__ = NULL;
1447 asm(".desc ___crashreporter_info__, 0x10");
1448 #endif // !TARGET_OS_IPHONE
1449
1450
1451 static Boolean
1452 _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1453 {
1454 Boolean ok = FALSE;
1455
1456 #if !TARGET_OS_SIMULATOR
1457 static bool (*dyfunc_SimulateCrash)(pid_t, mach_exception_data_type_t, CFStringRef) = NULL;
1458 static void *image = NULL;
1459 static dispatch_once_t once;
1460
1461 dispatch_once(&once, ^{
1462 image = _SC_dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport");
1463 if (image != NULL) {
1464 dyfunc_SimulateCrash = dlsym(image, "SimulateCrash");
1465 }
1466 });
1467
1468 if (dyfunc_SimulateCrash != NULL) {
1469 CFStringRef str;
1470
1471 str = CFStringCreateWithCString(NULL, crash_info, kCFStringEncodingUTF8);
1472 ok = dyfunc_SimulateCrash(getpid(), 0xbad0005cull, str);
1473 CFRelease(str);
1474 }
1475
1476 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1477 if (ok && (notifyHeader != NULL) && (notifyMessage != NULL)) {
1478 static Boolean warned = FALSE;
1479
1480 if (!warned) {
1481 CFStringRef displayMessage;
1482
1483 displayMessage = CFStringCreateWithFormat(NULL,
1484 NULL,
1485 CFSTR("%@\n\nPlease collect the crash report and file a Radar."),
1486 notifyMessage);
1487 CFUserNotificationDisplayNotice(0,
1488 kCFUserNotificationStopAlertLevel,
1489 NULL,
1490 NULL,
1491 NULL,
1492 notifyHeader,
1493 displayMessage,
1494 NULL);
1495 CFRelease(displayMessage);
1496 warned = TRUE;
1497 }
1498 }
1499 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1500 #endif // !TARGET_OS_SIMULATOR
1501
1502 return ok;
1503 }
1504
1505
1506 void
1507 _SC_crash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1508 {
1509 Boolean ok = FALSE;
1510
1511 if (crash_info != NULL) {
1512 #if !TARGET_OS_IPHONE
1513 CRSetCrashLogMessage(crash_info);
1514 #else // !TARGET_OS_IPHONE
1515 __crashreporter_info__ = crash_info;
1516 #endif // !TARGET_OS_IPHONE
1517
1518 SC_log(LOG_NOTICE, "%s", crash_info);
1519 }
1520
1521 if (_SC_isAppleInternal()) {
1522 // simulate a crash report
1523 ok = _SC_SimulateCrash(crash_info, notifyHeader, notifyMessage);
1524 #ifndef DO_NOT_CRASH
1525 if (!ok) {
1526 // if we could not simulate a crash report, crash for real
1527 __builtin_trap();
1528 }
1529 #endif // DO_NOT_CRASH
1530 }
1531
1532 #if !TARGET_OS_IPHONE
1533 CRSetCrashLogMessage(NULL);
1534 #else // !TARGET_OS_IPHONE
1535 __crashreporter_info__ = NULL;
1536 #endif // !TARGET_OS_IPHONE
1537 return;
1538 }
1539
1540
1541 Boolean
1542 _SC_getconninfo(int socket, struct sockaddr_storage *src_addr, struct sockaddr_storage *dest_addr, int *if_index, uint32_t *flags)
1543 {
1544 struct so_cinforeq request;
1545
1546 memset(&request, 0, sizeof(request));
1547
1548 if (src_addr != NULL) {
1549 memset(src_addr, 0, sizeof(*src_addr));
1550 request.scir_src = (struct sockaddr *)src_addr;
1551 request.scir_src_len = sizeof(*src_addr);
1552 }
1553
1554 if (dest_addr != NULL) {
1555 memset(dest_addr, 0, sizeof(*dest_addr));
1556 request.scir_dst = (struct sockaddr *)dest_addr;
1557 request.scir_dst_len = sizeof(*dest_addr);
1558 }
1559
1560 if (ioctl(socket, SIOCGCONNINFO, &request) != 0) {
1561 SC_log(LOG_NOTICE, "SIOCGCONNINFO failed: %s", strerror(errno));
1562 return FALSE;
1563 }
1564
1565 if (if_index != NULL) {
1566 *if_index = 0;
1567 *if_index = request.scir_ifindex;
1568 }
1569
1570 if (flags != NULL) {
1571 *flags = 0;
1572 *flags = request.scir_flags;
1573 }
1574
1575 return TRUE;
1576 }