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