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