]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDPrivate.c
configd-699.30.1.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDPrivate.c
1 /*
2 * Copyright (c) 2000-2014 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 SCLog(TRUE, LOG_ERR, CFSTR("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 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerialize() 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 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerialize(): %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 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserialize(): %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 SCLog(TRUE, LOG_ERR, CFSTR("_SCUnserialize(): %@"), 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 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeString() 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 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeString(): %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 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserializeString(): %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 SCLog(TRUE, LOG_ERR, CFSTR("_SCUnserializeString() 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 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeData(): %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 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserializeData(): %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 "/System/Library/Frameworks/SystemConfiguration.framework"
857 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
858
859 #define SUFFIX_SYM "~sym"
860 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
861
862 #define SUFFIX_DST "~dst"
863
864
865 CFBundleRef
866 _SC_CFBundleGet(void)
867 {
868 static CFBundleRef bundle = NULL;
869 char *env;
870 size_t len;
871
872 if (bundle != NULL) {
873 return bundle;
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 return bundle;
880 }
881
882 // if appropriate (e.g. when debugging), try a bit harder
883
884 env = getenv("DYLD_FRAMEWORK_PATH");
885 len = (env != NULL) ? strlen(env) : 0;
886
887 // trim any trailing slashes
888 while (len > 1) {
889 if (env[len - 1] != '/') {
890 break;
891 }
892 len--;
893 }
894
895 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst"
896 if ((len > SUFFIX_SYM_LEN) &&
897 (strncmp(&env[len - SUFFIX_SYM_LEN], SUFFIX_SYM, SUFFIX_SYM_LEN) == 0) &&
898 ((len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN) < MAXPATHLEN)) {
899 char path[MAXPATHLEN];
900 CFURLRef url;
901
902 strlcpy(path, env, sizeof(path));
903 strlcpy(&path[len - SUFFIX_SYM_LEN], SUFFIX_DST, sizeof(path) - (len - SUFFIX_SYM_LEN));
904 strlcat(&path[len], SYSTEMCONFIGURATION_FRAMEWORK_PATH, sizeof(path) - len);
905
906 url = CFURLCreateFromFileSystemRepresentation(NULL,
907 (UInt8 *)path,
908 len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN,
909 TRUE);
910 bundle = CFBundleCreate(NULL, url);
911 CFRelease(url);
912 }
913
914 if (bundle == NULL) {
915 static Boolean warned = FALSE;
916
917 SCLog(!warned, LOG_WARNING,
918 CFSTR("_SC_CFBundleGet(), could not get CFBundle for \"%@\""),
919 SYSTEMCONFIGURATION_BUNDLE_ID);
920 warned = TRUE;
921 }
922
923 return bundle;
924 }
925
926
927 CFStringRef
928 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName)
929 {
930 CFDataRef data = NULL;
931 SInt32 errCode = 0;
932 Boolean ok;
933 CFURLRef resourcesURL;
934 CFStringRef str = NULL;
935 CFURLRef url;
936
937 if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) tableName = CFSTR("Localizable");
938
939 /*
940 * First, try getting the requested string using a manually constructed
941 * URL to <bundle>/Resources/English.lproj/<tableName>.strings. Do this
942 * because CFBundleCopyResourceURLForLocalization() uses CFPreferences
943 * to get the preferred localizations, CFPreferences talks to
944 * OpenDirectory, and OpenDirectory tries to obtain the platform UUID.
945 * On machines where the platform UUID is set by InterfaceNamer, a
946 * deadlock can occur if InterfaceNamer calls
947 * CFBundleCopyResourceURLForLocalization() before setting the
948 * platform UUID in the kernel.
949 */
950 resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
951 if (resourcesURL != NULL) {
952 CFStringRef fileName = CFStringCreateWithFormat(
953 NULL, NULL, CFSTR("%@.strings"), tableName);
954 CFURLRef enlproj = CFURLCreateCopyAppendingPathComponent(
955 NULL, resourcesURL, CFSTR("English.lproj"), true);
956 url = CFURLCreateCopyAppendingPathComponent(
957 NULL, enlproj, fileName, false);
958 CFRelease(enlproj);
959 CFRelease(fileName);
960 CFRelease(resourcesURL);
961
962 #pragma GCC diagnostic push
963 #pragma GCC diagnostic ignored "-Wdeprecated"
964 ok = CFURLCreateDataAndPropertiesFromResource(NULL,
965 url,
966 &data,
967 NULL,
968 NULL,
969 &errCode);
970 #pragma GCC diagnostic pop
971 if (!ok) {
972 /*
973 * Failed to get the data using a manually-constructed URL
974 * for the given strings table. Fall back to using
975 * CFBundleCopyResourceURLForLocalization() below.
976 */
977 data = NULL;
978 }
979 CFRelease(url);
980 }
981
982 if (data == NULL) {
983 url = CFBundleCopyResourceURLForLocalization(bundle,
984 tableName,
985 CFSTR("strings"),
986 NULL,
987 CFSTR("English"));
988 if (url != NULL) {
989 #pragma GCC diagnostic push
990 #pragma GCC diagnostic ignored "-Wdeprecated"
991 ok = CFURLCreateDataAndPropertiesFromResource(NULL,
992 url,
993 &data,
994 NULL,
995 NULL,
996 &errCode);
997 #pragma GCC diagnostic pop
998 if (!ok) {
999 data = NULL;
1000 }
1001 CFRelease(url);
1002 }
1003 }
1004
1005 if (data != NULL) {
1006 CFDictionaryRef table;
1007
1008 table = CFPropertyListCreateWithData(NULL,
1009 data,
1010 kCFPropertyListImmutable,
1011 NULL,
1012 NULL);
1013 if (table != NULL) {
1014 if (isA_CFDictionary(table)) {
1015 str = CFDictionaryGetValue(table, key);
1016 if (str != NULL) {
1017 CFRetain(str);
1018 }
1019 }
1020
1021 CFRelease(table);
1022 }
1023
1024 CFRelease(data);
1025 }
1026
1027 if (str == NULL) {
1028 str = CFRetain(value);
1029 }
1030
1031 return str;
1032 }
1033
1034
1035 #pragma mark -
1036 #pragma mark Mach port / CFMachPort management
1037
1038
1039 CFMachPortRef
1040 _SC_CFMachPortCreateWithPort(const char *portDescription,
1041 mach_port_t portNum,
1042 CFMachPortCallBack callout,
1043 CFMachPortContext *context)
1044 {
1045 CFMachPortRef port;
1046 Boolean shouldFree = FALSE;
1047
1048 port = CFMachPortCreateWithPort(NULL, portNum, callout, context, &shouldFree);
1049 if ((port == NULL) || shouldFree) {
1050 CFStringRef err;
1051 char *crash_info = NULL;
1052
1053 SCLog(TRUE, LOG_ERR,
1054 CFSTR("%s: CFMachPortCreateWithPort() failed , port = %p"),
1055 portDescription,
1056 (void *)(uintptr_t)portNum);
1057 if (port != NULL) {
1058 err = CFStringCreateWithFormat(NULL, NULL,
1059 CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"),
1060 portDescription, port);
1061 } else {
1062 err = CFStringCreateWithFormat(NULL, NULL,
1063 CFSTR("%s: CFMachPortCreateWithPort returned NULL"),
1064 portDescription);
1065 }
1066 crash_info = _SC_cfstring_to_cstring(err, NULL, 0, kCFStringEncodingASCII);
1067 if (err != NULL) CFRelease(err);
1068
1069
1070 err = CFStringCreateWithFormat(NULL,
1071 NULL,
1072 CFSTR("A recycled mach_port has been detected by \"%s\"."),
1073 getprogname());
1074 _SC_crash(crash_info, CFSTR("CFMachPort error"), err);
1075 CFAllocatorDeallocate(NULL, crash_info);
1076 if (err != NULL) CFRelease(err);
1077 }
1078
1079 return port;
1080 }
1081
1082
1083 #pragma mark -
1084 #pragma mark DOS encoding/codepage
1085
1086
1087 #if !TARGET_OS_IPHONE
1088 void
1089 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding,
1090 UInt32 macRegion,
1091 CFStringEncoding *dosEncoding,
1092 UInt32 *dosCodepage)
1093 {
1094 switch (macEncoding) {
1095 case kCFStringEncodingMacRoman:
1096 if (macRegion != 0) /* anything non-zero is not US */
1097 *dosEncoding = kCFStringEncodingDOSLatin1;
1098 else /* US region */
1099 *dosEncoding = kCFStringEncodingDOSLatinUS;
1100 break;
1101
1102 case kCFStringEncodingMacJapanese:
1103 *dosEncoding = kCFStringEncodingDOSJapanese;
1104 break;
1105
1106 case kCFStringEncodingMacChineseTrad:
1107 *dosEncoding = kCFStringEncodingDOSChineseTrad;
1108 break;
1109
1110 case kCFStringEncodingMacKorean:
1111 *dosEncoding = kCFStringEncodingDOSKorean;
1112 break;
1113
1114 case kCFStringEncodingMacArabic:
1115 *dosEncoding = kCFStringEncodingDOSArabic;
1116 break;
1117
1118 case kCFStringEncodingMacHebrew:
1119 *dosEncoding = kCFStringEncodingDOSHebrew;
1120 break;
1121
1122 case kCFStringEncodingMacGreek:
1123 *dosEncoding = kCFStringEncodingDOSGreek;
1124 break;
1125
1126 case kCFStringEncodingMacCyrillic:
1127 *dosEncoding = kCFStringEncodingDOSCyrillic;
1128 break;
1129
1130 case kCFStringEncodingMacThai:
1131 *dosEncoding = kCFStringEncodingDOSThai;
1132 break;
1133
1134 case kCFStringEncodingMacChineseSimp:
1135 *dosEncoding = kCFStringEncodingDOSChineseSimplif;
1136 break;
1137
1138 case kCFStringEncodingMacCentralEurRoman:
1139 *dosEncoding = kCFStringEncodingDOSLatin2;
1140 break;
1141
1142 case kCFStringEncodingMacTurkish:
1143 *dosEncoding = kCFStringEncodingDOSTurkish;
1144 break;
1145
1146 case kCFStringEncodingMacCroatian:
1147 *dosEncoding = kCFStringEncodingDOSLatin2;
1148 break;
1149
1150 case kCFStringEncodingMacIcelandic:
1151 *dosEncoding = kCFStringEncodingDOSIcelandic;
1152 break;
1153
1154 case kCFStringEncodingMacRomanian:
1155 *dosEncoding = kCFStringEncodingDOSLatin2;
1156 break;
1157
1158 case kCFStringEncodingMacFarsi:
1159 *dosEncoding = kCFStringEncodingDOSArabic;
1160 break;
1161
1162 case kCFStringEncodingMacUkrainian:
1163 *dosEncoding = kCFStringEncodingDOSCyrillic;
1164 break;
1165
1166 default:
1167 *dosEncoding = kCFStringEncodingDOSLatin1;
1168 break;
1169 }
1170
1171 *dosCodepage = CFStringConvertEncodingToWindowsCodepage(*dosEncoding);
1172 return;
1173 }
1174 #endif // !TARGET_OS_IPHONE
1175
1176
1177 #pragma mark -
1178 #pragma mark Debugging
1179
1180
1181 /*
1182 * print status of in-use mach ports
1183 */
1184 void
1185 _SC_logMachPortStatus(void)
1186 {
1187 kern_return_t status;
1188 mach_port_name_array_t ports;
1189 mach_port_type_array_t types;
1190 mach_msg_type_number_t pi, pn, tn;
1191 CFMutableStringRef str;
1192
1193 SCLog(TRUE, LOG_NOTICE, CFSTR("----------"));
1194
1195 /* report on ALL mach ports associated with this task */
1196 status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn);
1197 if (status == MACH_MSG_SUCCESS) {
1198 str = CFStringCreateMutable(NULL, 0);
1199 for (pi = 0; pi < pn; pi++) {
1200 char rights[16], *rp = &rights[0];
1201
1202 if (types[pi] != MACH_PORT_TYPE_NONE) {
1203 *rp++ = ' ';
1204 *rp++ = '(';
1205 if (types[pi] & MACH_PORT_TYPE_SEND)
1206 *rp++ = 'S';
1207 if (types[pi] & MACH_PORT_TYPE_RECEIVE)
1208 *rp++ = 'R';
1209 if (types[pi] & MACH_PORT_TYPE_SEND_ONCE)
1210 *rp++ = 'O';
1211 if (types[pi] & MACH_PORT_TYPE_PORT_SET)
1212 *rp++ = 'P';
1213 if (types[pi] & MACH_PORT_TYPE_DEAD_NAME)
1214 *rp++ = 'D';
1215 *rp++ = ')';
1216 }
1217 *rp = '\0';
1218 CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights);
1219 }
1220 SCLog(TRUE, LOG_NOTICE, CFSTR("Task ports (n=%d):%@"), pn, str);
1221 CFRelease(str);
1222 }
1223
1224 return;
1225 }
1226
1227
1228 void
1229 _SC_logMachPortReferences(const char *str, mach_port_t port)
1230 {
1231 const char *blanks = " ";
1232 char buf[60];
1233 mach_port_type_t pt;
1234 mach_port_status_t recv_status = { 0 };
1235 mach_port_urefs_t refs_send = 0;
1236 mach_port_urefs_t refs_recv = 0;
1237 mach_port_urefs_t refs_once = 0;
1238 mach_port_urefs_t refs_pset = 0;
1239 mach_port_urefs_t refs_dead = 0;
1240 kern_return_t status;
1241
1242 buf[0] = '\0';
1243 if (str != NULL) {
1244 static int is_configd = -1;
1245
1246 if (is_configd == -1) {
1247 is_configd = (strcmp(getprogname(), _SC_SERVER_PROG) == 0);
1248 }
1249 if (is_configd == 1) {
1250 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1251 strlcpy(buf,
1252 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1253 sizeof(buf));
1254 }
1255
1256 // add provided string
1257 strlcat(buf, str, sizeof(buf));
1258
1259 // fill
1260 strlcat(buf, blanks, sizeof(buf));
1261 if (strcmp(&buf[sizeof(buf) - 3], " ") == 0) {
1262 buf[sizeof(buf) - 3] = ':';
1263 }
1264 }
1265
1266 status = mach_port_type(mach_task_self(), port, &pt);
1267 if (status != KERN_SUCCESS) {
1268 SCLog(TRUE, LOG_NOTICE,
1269 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"),
1270 buf,
1271 port,
1272 mach_error_string(status));
1273 return;
1274 }
1275
1276 if ((pt & MACH_PORT_TYPE_SEND) != 0) {
1277 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs_send);
1278 if (status != KERN_SUCCESS) {
1279 SCLog(TRUE, LOG_NOTICE,
1280 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"),
1281 buf,
1282 port,
1283 mach_error_string(status));
1284 return;
1285 }
1286 }
1287
1288 if ((pt & MACH_PORT_TYPE_RECEIVE) != 0) {
1289 mach_msg_type_number_t count;
1290
1291 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, &refs_recv);
1292 if (status != KERN_SUCCESS) {
1293 SCLog(TRUE, LOG_NOTICE,
1294 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s"),
1295 buf,
1296 port,
1297 mach_error_string(status));
1298 return;
1299 }
1300
1301 count = MACH_PORT_RECEIVE_STATUS_COUNT;
1302 status = mach_port_get_attributes(mach_task_self(),
1303 port,
1304 MACH_PORT_RECEIVE_STATUS,
1305 (mach_port_info_t)&recv_status,
1306 &count);
1307 if (status != KERN_SUCCESS) {
1308 SCLog(TRUE, LOG_NOTICE,
1309 CFSTR("%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s"),
1310 buf,
1311 port,
1312 mach_error_string(status));
1313 return;
1314 }
1315 }
1316
1317 if ((pt & MACH_PORT_TYPE_SEND_ONCE) != 0) {
1318 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once);
1319 if (status != KERN_SUCCESS) {
1320 SCLog(TRUE, LOG_NOTICE,
1321 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s"),
1322 buf,
1323 port,
1324 mach_error_string(status));
1325 return;
1326 }
1327 }
1328
1329 if ((pt & MACH_PORT_TYPE_PORT_SET) != 0) {
1330 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, &refs_pset);
1331 if (status != KERN_SUCCESS) {
1332 SCLog(TRUE, LOG_NOTICE,
1333 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s"),
1334 buf,
1335 port,
1336 mach_error_string(status));
1337 return;
1338 }
1339 }
1340
1341 if ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) {
1342 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead);
1343 if (status != KERN_SUCCESS) {
1344 SCLog(TRUE, LOG_NOTICE,
1345 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s"),
1346 buf,
1347 port,
1348 mach_error_string(status));
1349 return;
1350 }
1351 }
1352
1353 SCLog(TRUE, LOG_NOTICE,
1354 CFSTR("%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s"),
1355 buf,
1356 port,
1357 port,
1358 refs_send,
1359 refs_recv,
1360 refs_once,
1361 refs_pset,
1362 refs_dead,
1363 recv_status.mps_nsrequest ? ", no more senders" : "",
1364 ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) ? ", dead name request" : "");
1365
1366 return;
1367 }
1368
1369
1370 CFStringRef
1371 _SC_copyBacktrace()
1372 {
1373 int n;
1374 void *stack[64];
1375 char **symbols;
1376 CFMutableStringRef trace;
1377
1378 n = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
1379 if (n == -1) {
1380 SCLog(TRUE, LOG_ERR, CFSTR("backtrace() failed: %s"), strerror(errno));
1381 return NULL;
1382 }
1383
1384 trace = CFStringCreateMutable(NULL, 0);
1385
1386 symbols = backtrace_symbols(stack, n);
1387 if (symbols != NULL) {
1388 int i;
1389
1390 for (i = 0; i < n; i++) {
1391 CFStringAppendFormat(trace, NULL, CFSTR("%s\n"), symbols[i]);
1392 }
1393
1394 free(symbols);
1395 }
1396
1397 return trace;
1398 }
1399
1400
1401 /* CrashReporter info */
1402 #if !TARGET_OS_IPHONE
1403 #include <CrashReporterClient.h>
1404 #else // !TARGET_OS_IPHONE
1405 const char *__crashreporter_info__ = NULL;
1406 asm(".desc ___crashreporter_info__, 0x10");
1407 #endif // !TARGET_OS_IPHONE
1408
1409
1410 static Boolean
1411 _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1412 {
1413 Boolean ok = FALSE;
1414
1415 #if ! TARGET_IPHONE_SIMULATOR
1416 static bool (*dyfunc_SimulateCrash)(pid_t, mach_exception_data_type_t, CFStringRef) = NULL;
1417 static void *image = NULL;
1418
1419 if ((dyfunc_SimulateCrash == NULL) && (image == NULL)) {
1420 const char *framework = "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport";
1421 struct stat statbuf;
1422 const char *suffix = getenv("DYLD_IMAGE_SUFFIX");
1423 char path[MAXPATHLEN];
1424
1425 strlcpy(path, framework, sizeof(path));
1426 if (suffix) strlcat(path, suffix, sizeof(path));
1427 if (0 <= stat(path, &statbuf)) {
1428 image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
1429 } else {
1430 image = dlopen(framework, RTLD_LAZY | RTLD_LOCAL);
1431 }
1432
1433 if (image != NULL) {
1434 dyfunc_SimulateCrash = dlsym(image, "SimulateCrash");
1435 } else {
1436 image = (void *)0x1; // to ensure that we only dlopen() once
1437 }
1438 }
1439
1440 if (dyfunc_SimulateCrash != NULL) {
1441 CFStringRef str;
1442
1443 str = CFStringCreateWithCString(NULL, crash_info, kCFStringEncodingUTF8);
1444 ok = dyfunc_SimulateCrash(getpid(), 0xbad0005cull, str);
1445 CFRelease(str);
1446 }
1447
1448 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1449 if (ok && (notifyHeader != NULL) && (notifyMessage != NULL)) {
1450 static Boolean warned = FALSE;
1451
1452 if (!warned) {
1453 CFStringRef displayMessage;
1454
1455 displayMessage = CFStringCreateWithFormat(NULL,
1456 NULL,
1457 CFSTR("%@\n\nPlease collect the crash report and file a Radar."),
1458 notifyMessage);
1459 CFUserNotificationDisplayNotice(0,
1460 kCFUserNotificationStopAlertLevel,
1461 NULL,
1462 NULL,
1463 NULL,
1464 notifyHeader,
1465 displayMessage,
1466 NULL);
1467 CFRelease(displayMessage);
1468 warned = TRUE;
1469 }
1470 }
1471 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1472 #endif /* ! TARGET_IPHONE_SIMULATOR */
1473
1474 return ok;
1475 }
1476
1477
1478 void
1479 _SC_crash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1480 {
1481 Boolean ok = FALSE;
1482
1483 if (crash_info != NULL) {
1484 #if !TARGET_OS_IPHONE
1485 CRSetCrashLogMessage(crash_info);
1486 #else // !TARGET_OS_IPHONE
1487 __crashreporter_info__ = crash_info;
1488 #endif // !TARGET_OS_IPHONE
1489
1490 SCLog(TRUE, LOG_ERR, CFSTR("%s"), crash_info);
1491 }
1492
1493 if (_SC_isAppleInternal()) {
1494 // simulate a crash report
1495 ok = _SC_SimulateCrash(crash_info, notifyHeader, notifyMessage);
1496 #ifndef DO_NOT_CRASH
1497 if (!ok) {
1498 // if we could not simulate a crash report, crash for real
1499 __builtin_trap();
1500 }
1501 #endif // DO_NOT_CRASH
1502 }
1503
1504 #if !TARGET_OS_IPHONE
1505 CRSetCrashLogMessage(NULL);
1506 #else // !TARGET_OS_IPHONE
1507 __crashreporter_info__ = NULL;
1508 #endif // !TARGET_OS_IPHONE
1509 return;
1510 }
1511
1512
1513 Boolean
1514 _SC_getconninfo(int socket, struct sockaddr_storage *src_addr, struct sockaddr_storage *dest_addr, int *if_index, uint32_t *flags)
1515 {
1516 struct so_cinforeq request;
1517
1518 memset(&request, 0, sizeof(request));
1519
1520 if (src_addr != NULL) {
1521 memset(src_addr, 0, sizeof(*src_addr));
1522 request.scir_src = (struct sockaddr *)src_addr;
1523 request.scir_src_len = sizeof(*src_addr);
1524 }
1525
1526 if (dest_addr != NULL) {
1527 memset(dest_addr, 0, sizeof(*dest_addr));
1528 request.scir_dst = (struct sockaddr *)dest_addr;
1529 request.scir_dst_len = sizeof(*dest_addr);
1530 }
1531
1532 if (ioctl(socket, SIOCGCONNINFO, &request) != 0) {
1533 SCLog(TRUE, LOG_WARNING, CFSTR("SIOCGCONNINFO failed: %s"), strerror(errno));
1534 return FALSE;
1535 }
1536
1537 if (if_index != NULL) {
1538 *if_index = 0;
1539 *if_index = request.scir_ifindex;
1540 }
1541
1542 if (flags != NULL) {
1543 *flags = 0;
1544 *flags = request.scir_flags;
1545 }
1546
1547 return TRUE;
1548 }