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