]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDPrivate.c
configd-963.50.8.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 static kern_return_t
369 __CFDataCopyVMData(CFDataRef data, void **dataRef, CFIndex *dataLen)
370 {
371 kern_return_t kr;
372
373 vm_address_t vm_address;
374 vm_size_t vm_size;
375
376 vm_address = (vm_address_t)CFDataGetBytePtr(data);
377 vm_size = (vm_size_t)CFDataGetLength(data);
378 kr = vm_allocate(mach_task_self(), &vm_address, vm_size, VM_FLAGS_ANYWHERE);
379 if (kr != KERN_SUCCESS) {
380 *dataRef = NULL;
381 *dataLen = 0;
382 return kr;
383 }
384
385 bcopy((char *)CFDataGetBytePtr(data), (void *)vm_address, vm_size);
386 *dataRef = (void *)vm_address;
387 *dataLen = vm_size;
388
389 return kr;
390 }
391
392
393 Boolean
394 _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dataLen)
395 {
396 CFDataRef myXml;
397
398 if ((xml == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
399 /* if not keeping track of allocated space */
400 return FALSE;
401 }
402
403 myXml = CFPropertyListCreateData(NULL,
404 obj,
405 kCFPropertyListBinaryFormat_v1_0,
406 0,
407 NULL);
408 if (myXml == NULL) {
409 SC_log(LOG_NOTICE, "CFPropertyListCreateData() failed");
410 if (xml != NULL) {
411 *xml = NULL;
412 }
413 if ((dataRef != NULL) && (dataLen != NULL)) {
414 *dataLen = 0;
415 *dataRef = NULL;
416 }
417 return FALSE;
418 }
419
420 if (xml != NULL) {
421 *xml = myXml;
422 if ((dataRef != NULL) && (dataLen != NULL)) {
423 *dataRef = (void *)CFDataGetBytePtr(myXml);
424 *dataLen = CFDataGetLength(myXml);
425 }
426 } else {
427 kern_return_t kr;
428
429 kr = __CFDataCopyVMData(myXml, dataRef, dataLen);
430 CFRelease(myXml);
431 if (kr != KERN_SUCCESS) {
432 SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr));
433 return FALSE;
434 }
435 }
436
437 return TRUE;
438 }
439
440
441 Boolean
442 _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen)
443 {
444 CFErrorRef error = NULL;
445
446 if (xml == NULL) {
447 kern_return_t status;
448
449 xml = CFDataCreateWithBytesNoCopy(NULL, (void *)dataRef, dataLen, kCFAllocatorNull);
450 *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error);
451 CFRelease(xml);
452
453 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
454 if (status != KERN_SUCCESS) {
455 SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status));
456 /* non-fatal???, proceed */
457 }
458 } else {
459 *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error);
460 }
461
462 if (*obj == NULL) {
463 if (error != NULL) {
464 SC_log(LOG_NOTICE, "CFPropertyListCreateWithData() failed: %@", error);
465 CFRelease(error);
466 }
467 _SCErrorSet(kSCStatusFailed);
468 return FALSE;
469 }
470
471 return TRUE;
472 }
473
474
475 Boolean
476 _SCSerializeString(CFStringRef str, CFDataRef *data, void **dataRef, CFIndex *dataLen)
477 {
478 CFDataRef myData;
479
480 if (!isA_CFString(str)) {
481 /* if not a CFString */
482 return FALSE;
483 }
484
485 if ((data == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
486 /* if not keeping track of allocated space */
487 return FALSE;
488 }
489
490 myData = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
491 if (myData == NULL) {
492 SC_log(LOG_NOTICE, "CFStringCreateExternalRepresentation() failed");
493 if (data != NULL) {
494 *data = NULL;
495 }
496 if ((dataRef != NULL) && (dataLen != NULL)) {
497 *dataRef = NULL;
498 *dataLen = 0;
499 }
500 return FALSE;
501 }
502
503 if (data != NULL) {
504 *data = myData;
505 if ((dataRef != NULL) && (dataLen != NULL)) {
506 *dataRef = (void *)CFDataGetBytePtr(myData);
507 *dataLen = CFDataGetLength(myData);
508 }
509 } else {
510 kern_return_t kr;
511
512 kr = __CFDataCopyVMData(myData, dataRef, dataLen);
513 CFRelease(myData);
514 if (kr != KERN_SUCCESS) {
515 SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr));
516 return FALSE;
517 }
518 }
519
520 return TRUE;
521 }
522
523
524 Boolean
525 _SCUnserializeString(CFStringRef *str, CFDataRef utf8, void *dataRef, CFIndex dataLen)
526 {
527 if (utf8 == NULL) {
528 kern_return_t status;
529
530 utf8 = CFDataCreateWithBytesNoCopy(NULL, dataRef, dataLen, kCFAllocatorNull);
531 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
532 CFRelease(utf8);
533
534 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
535 if (status != KERN_SUCCESS) {
536 SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status));
537 /* non-fatal???, proceed */
538 }
539 } else {
540 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
541 }
542
543 if (*str == NULL) {
544 SC_log(LOG_NOTICE, "CFStringCreateFromExternalRepresentation() failed");
545 return FALSE;
546 }
547
548 return TRUE;
549 }
550
551
552 Boolean
553 _SCSerializeData(CFDataRef data, void **dataRef, CFIndex *dataLen)
554 {
555 kern_return_t kr;
556
557 if (!isA_CFData(data)) {
558 /* if not a CFData */
559 return FALSE;
560 }
561
562 kr = __CFDataCopyVMData(data, dataRef, dataLen);
563 if (kr != KERN_SUCCESS) {
564 SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr));
565 return FALSE;
566 }
567
568 return TRUE;
569 }
570
571
572 Boolean
573 _SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen)
574 {
575 kern_return_t status;
576
577 *data = CFDataCreate(NULL, dataRef, dataLen);
578 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
579 if (status != KERN_SUCCESS) {
580 SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status));
581 _SCErrorSet(kSCStatusFailed);
582 return FALSE;
583 }
584
585 return TRUE;
586 }
587
588
589 CF_RETURNS_RETAINED CFDictionaryRef
590 _SCSerializeMultiple(CFDictionaryRef dict)
591 {
592 CFIndex i;
593 const void * keys_q[N_QUICK];
594 const void ** keys = keys_q;
595 CFIndex nElements;
596 CFDictionaryRef newDict = NULL;
597 const void * pLists_q[N_QUICK];
598 const void ** pLists = pLists_q;
599 const void * values_q[N_QUICK];
600 const void ** values = values_q;
601
602 nElements = CFDictionaryGetCount(dict);
603 if (nElements > 0) {
604 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
605 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
606 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
607 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFDataRef), 0);
608 }
609 bzero(pLists, nElements * sizeof(CFDataRef));
610
611 CFDictionaryGetKeysAndValues(dict, keys, values);
612 for (i = 0; i < nElements; i++) {
613 pLists[i] = NULL;
614 if (!_SCSerialize((CFPropertyListRef)values[i], (CFDataRef *)&pLists[i], NULL, NULL)) {
615 goto done;
616 }
617 }
618 }
619
620 newDict = CFDictionaryCreate(NULL,
621 keys,
622 pLists,
623 nElements,
624 &kCFTypeDictionaryKeyCallBacks,
625 &kCFTypeDictionaryValueCallBacks);
626
627 done :
628
629 if (nElements > 0) {
630 for (i = 0; i < nElements; i++) {
631 if (pLists[i] != NULL) CFRelease((CFDataRef)pLists[i]);
632 }
633
634 if (keys != keys_q) {
635 CFAllocatorDeallocate(NULL, keys);
636 CFAllocatorDeallocate(NULL, values);
637 CFAllocatorDeallocate(NULL, pLists);
638 }
639 }
640
641 return newDict;
642 }
643
644
645 CF_RETURNS_RETAINED
646 CFDictionaryRef
647 _SCUnserializeMultiple(CFDictionaryRef dict)
648 {
649 const void * keys_q[N_QUICK];
650 const void ** keys = keys_q;
651 CFIndex nElements;
652 CFDictionaryRef newDict = NULL;
653 const void * pLists_q[N_QUICK];
654 const void ** pLists = pLists_q;
655 const void * values_q[N_QUICK];
656 const void ** values = values_q;
657
658 nElements = CFDictionaryGetCount(dict);
659 if (nElements > 0) {
660 CFIndex i;
661
662 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
663 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
664 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
665 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
666 }
667 bzero(pLists, nElements * sizeof(CFTypeRef));
668
669 CFDictionaryGetKeysAndValues(dict, keys, values);
670 for (i = 0; i < nElements; i++) {
671 if (!_SCUnserialize((CFPropertyListRef *)&pLists[i], values[i], NULL, 0)) {
672 goto done;
673 }
674 }
675 }
676
677 newDict = CFDictionaryCreate(NULL,
678 keys,
679 pLists,
680 nElements,
681 &kCFTypeDictionaryKeyCallBacks,
682 &kCFTypeDictionaryValueCallBacks);
683
684 done :
685
686 if (nElements > 0) {
687 CFIndex i;
688
689 for (i = 0; i < nElements; i++) {
690 if (pLists[i]) CFRelease(pLists[i]);
691 }
692
693 if (keys != keys_q) {
694 CFAllocatorDeallocate(NULL, keys);
695 CFAllocatorDeallocate(NULL, values);
696 CFAllocatorDeallocate(NULL, pLists);
697 }
698 }
699
700 return newDict;
701 }
702
703
704 #pragma mark -
705
706
707 CFPropertyListRef
708 _SCCreatePropertyListFromResource(CFURLRef url)
709 {
710 CFDictionaryRef dict = NULL;
711 SInt64 fileLen = 0;
712 Boolean ok;
713 CFReadStreamRef readStream;
714 CFNumberRef val = NULL;
715
716 if (!CFURLCopyResourcePropertyForKey(url, kCFURLFileSizeKey, &val, NULL) ||
717 (val == NULL)) {
718 // if size not available
719 SC_log(LOG_NOTICE, "CFURLCopyResourcePropertyForKey() size not available: %@", url);
720 return NULL;
721 }
722
723 ok = CFNumberGetValue(val, kCFNumberSInt64Type, &fileLen);
724 CFRelease(val);
725 if (!ok || (fileLen == 0)) {
726 // if empty or size too large
727 SC_log(LOG_INFO, "_SCCreatePropertyListFromResource() improper size: %@", url);
728 return NULL;
729 }
730
731 readStream = CFReadStreamCreateWithFile(NULL, url);
732 if (readStream != NULL) {
733 if (CFReadStreamOpen(readStream)) {
734 UInt8 *buffer;
735 CFIndex dataLen;
736
737 buffer = CFAllocatorAllocate(NULL, (CFIndex)fileLen, 0);
738 dataLen = CFReadStreamRead(readStream, buffer, (CFIndex)fileLen);
739 if (dataLen == (CFIndex)fileLen) {
740 CFDataRef data;
741
742 data = CFDataCreateWithBytesNoCopy(NULL, buffer, (CFIndex)fileLen, kCFAllocatorNull);
743 if (data != NULL) {
744 dict = CFPropertyListCreateWithData(NULL,
745 data,
746 kCFPropertyListImmutable,
747 NULL,
748 NULL);
749 CFRelease(data);
750 }
751 }
752 CFAllocatorDeallocate(NULL, buffer);
753 CFReadStreamClose(readStream);
754 }
755 CFRelease(readStream);
756 }
757
758 return dict;
759 }
760
761
762 #pragma mark -
763 #pragma mark CFRunLoop scheduling
764
765
766 __private_extern__ void
767 _SC_signalRunLoop(CFTypeRef obj, CFRunLoopSourceRef rls, CFArrayRef rlList)
768 {
769 CFRunLoopRef rl = NULL;
770 CFRunLoopRef rl1 = NULL;
771 CFIndex i;
772 CFIndex n = CFArrayGetCount(rlList);
773
774 if (n == 0) {
775 return;
776 }
777
778 /* get first runLoop for this object */
779 for (i = 0; i < n; i += 3) {
780 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
781 continue;
782 }
783
784 rl1 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
785 break;
786 }
787
788 if (rl1 == NULL) {
789 /* if not scheduled */
790 return;
791 }
792
793 /* check if we have another runLoop for this object */
794 rl = rl1;
795 for (i = i+3; i < n; i += 3) {
796 CFRunLoopRef rl2;
797
798 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
799 continue;
800 }
801
802 rl2 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
803 if (!CFEqual(rl1, rl2)) {
804 /* we've got more than one runLoop */
805 rl = NULL;
806 break;
807 }
808 }
809
810 if (rl != NULL) {
811 /* if we only have one runLoop */
812 CFRunLoopWakeUp(rl);
813 return;
814 }
815
816 /* more than one different runLoop, so we must pick one */
817 for (i = 0; i < n; i+=3) {
818 CFStringRef rlMode;
819
820 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
821 continue;
822 }
823
824 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
825 rlMode = CFRunLoopCopyCurrentMode(rl);
826 if (rlMode != NULL) {
827 Boolean waiting;
828
829 waiting = (CFRunLoopIsWaiting(rl) && CFRunLoopContainsSource(rl, rls, rlMode));
830 CFRelease(rlMode);
831 if (waiting) {
832 /* we've found a runLoop that's "ready" */
833 CFRunLoopWakeUp(rl);
834 return;
835 }
836 }
837 }
838
839 /* didn't choose one above, so choose first */
840 CFRunLoopWakeUp(rl1);
841 return;
842 }
843
844
845 __private_extern__ Boolean
846 _SC_isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
847 {
848 CFIndex i;
849 CFIndex n = CFArrayGetCount(rlList);
850
851 for (i = 0; i < n; i += 3) {
852 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
853 continue;
854 }
855 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
856 continue;
857 }
858 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
859 continue;
860 }
861 return TRUE;
862 }
863
864 return FALSE;
865 }
866
867
868 __private_extern__ void
869 _SC_schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
870 {
871 CFArrayAppendValue(rlList, obj);
872 CFArrayAppendValue(rlList, runLoop);
873 CFArrayAppendValue(rlList, runLoopMode);
874
875 return;
876 }
877
878
879 __private_extern__ Boolean
880 _SC_unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all)
881 {
882 CFIndex i = 0;
883 Boolean found = FALSE;
884 CFIndex n = CFArrayGetCount(rlList);
885
886 while (i < n) {
887 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
888 i += 3;
889 continue;
890 }
891 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
892 i += 3;
893 continue;
894 }
895 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
896 i += 3;
897 continue;
898 }
899
900 found = TRUE;
901
902 CFArrayRemoveValueAtIndex(rlList, i + 2);
903 CFArrayRemoveValueAtIndex(rlList, i + 1);
904 CFArrayRemoveValueAtIndex(rlList, i);
905
906 if (!all) {
907 return found;
908 }
909
910 n -= 3;
911 }
912
913 return found;
914 }
915
916
917 #pragma mark -
918 #pragma mark Bundle
919
920
921 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
922 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
923
924 #define SUFFIX_SYM "~sym"
925 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
926
927 #define SUFFIX_DST "~dst"
928
929
930 CFBundleRef
931 _SC_CFBundleGet(void)
932 {
933 static CFBundleRef bundle = NULL;
934 char *env;
935 size_t len;
936 CFURLRef url;
937
938 if (bundle != NULL) {
939 goto done;
940 }
941
942 bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID);
943 if (bundle != NULL) {
944 CFRetain(bundle); // we want to hold a reference to the bundle
945 goto done;
946 } else {
947 SC_log(LOG_NOTICE, "could not get CFBundle for \"%@\". Trying harder...",
948 SYSTEMCONFIGURATION_BUNDLE_ID);
949 }
950
951 // if appropriate (e.g. when debugging), try a bit harder
952
953 env = getenv("DYLD_FRAMEWORK_PATH");
954 len = (env != NULL) ? strlen(env) : 0;
955
956 if (len > 0) { /* We are debugging */
957
958 // trim any trailing slashes
959 while (len > 1) {
960 if (env[len - 1] != '/') {
961 break;
962 }
963 len--;
964 }
965
966 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst"
967 if ((len > SUFFIX_SYM_LEN) &&
968 (strncmp(&env[len - SUFFIX_SYM_LEN], SUFFIX_SYM, SUFFIX_SYM_LEN) == 0) &&
969 ((len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN) < MAXPATHLEN)) {
970 char path[MAXPATHLEN];
971
972 strlcpy(path, env, sizeof(path));
973 strlcpy(&path[len - SUFFIX_SYM_LEN], SUFFIX_DST, sizeof(path) - (len - SUFFIX_SYM_LEN));
974 strlcat(&path[len], SYSTEMCONFIGURATION_FRAMEWORK_PATH, sizeof(path) - len);
975
976 url = CFURLCreateFromFileSystemRepresentation(NULL,
977 (UInt8 *)path,
978 len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN,
979 TRUE);
980 bundle = CFBundleCreate(NULL, url);
981 CFRelease(url);
982 }
983 }
984
985 if (bundle == NULL) { /* Try a more "direct" route to get the bundle */
986
987 url = CFURLCreateWithFileSystemPath(NULL,
988 CFSTR(SYSTEMCONFIGURATION_FRAMEWORK_PATH),
989 kCFURLPOSIXPathStyle,
990 TRUE);
991
992 bundle = CFBundleCreate(NULL, url);
993 CFRelease(url);
994 }
995
996 if (bundle == NULL) {
997 SC_log(LOG_ERR, "could not get CFBundle for \"%@\"", SYSTEMCONFIGURATION_BUNDLE_ID);
998 }
999
1000 done:
1001 return bundle;
1002 }
1003
1004
1005 /*
1006 * cachedInfo
1007 * <dict>
1008 * <key>bundleID-tableName</key>
1009 * <dict>
1010 * ... property list from non-localized bundle URL
1011 * </dict>
1012 * </dict>
1013 */
1014 static CFMutableDictionaryRef cachedInfo = NULL;
1015
1016
1017 static dispatch_queue_t
1018 _SC_CFBundleCachedInfoQueue()
1019 {
1020 static dispatch_once_t once;
1021 static dispatch_queue_t q;
1022
1023 dispatch_once(&once, ^{
1024 q = dispatch_queue_create("_SC_CFBundleCachedInfo", NULL);
1025 });
1026
1027 return q;
1028 }
1029
1030
1031 static CFStringRef
1032 _SC_CFBundleCachedInfoCopyTableKey(CFBundleRef bundle, CFStringRef tableName)
1033 {
1034 CFStringRef bundleID;
1035 CFStringRef tableKey;
1036
1037 bundleID = CFBundleGetIdentifier(bundle);
1038 tableKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@: %@"), bundleID, tableName);
1039 return tableKey;
1040 }
1041
1042
1043 static CFDictionaryRef
1044 _SC_CFBundleCachedInfoCopyTable(CFBundleRef bundle, CFStringRef tableName)
1045 {
1046 __block CFDictionaryRef dict = NULL;
1047
1048 dispatch_sync(_SC_CFBundleCachedInfoQueue(), ^{
1049 if (cachedInfo != NULL) {
1050 CFStringRef tableKey;
1051
1052 tableKey = _SC_CFBundleCachedInfoCopyTableKey(bundle, tableName);
1053 dict = CFDictionaryGetValue(cachedInfo, tableKey);
1054 if (dict != NULL) {
1055 CFRetain(dict);
1056 }
1057 CFRelease(tableKey);
1058 }
1059 });
1060
1061 return dict;
1062 }
1063
1064
1065 static void
1066 _SC_CFBundleCachedInfoSaveTable(CFBundleRef bundle, CFStringRef tableName, CFDictionaryRef table)
1067 {
1068
1069 dispatch_sync(_SC_CFBundleCachedInfoQueue(), ^{
1070 CFStringRef tableKey;
1071
1072 tableKey = _SC_CFBundleCachedInfoCopyTableKey(bundle, tableName);
1073 SC_log(LOG_DEBUG, "Caching %@", tableKey);
1074
1075 if (cachedInfo == NULL) {
1076 cachedInfo = CFDictionaryCreateMutable(NULL,
1077 0,
1078 &kCFTypeDictionaryKeyCallBacks,
1079 &kCFTypeDictionaryValueCallBacks);
1080 }
1081 CFDictionarySetValue(cachedInfo, tableKey, table);
1082 CFRelease(tableKey);
1083 });
1084
1085 return;
1086 }
1087
1088
1089 CFStringRef
1090 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName)
1091 {
1092 CFStringRef str = NULL;
1093 CFDictionaryRef table = NULL;
1094 CFURLRef url;
1095
1096 if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) {
1097 tableName = CFSTR("Localizable");
1098 }
1099
1100 table = _SC_CFBundleCachedInfoCopyTable(bundle, tableName);
1101 if (table == NULL) {
1102 url = CFBundleCopyResourceURLForLocalization(bundle,
1103 tableName,
1104 CFSTR("strings"),
1105 NULL,
1106 CFSTR("English"));
1107 if (url != NULL) {
1108 table = _SCCreatePropertyListFromResource(url);
1109 CFRelease(url);
1110 if (table != NULL) {
1111 _SC_CFBundleCachedInfoSaveTable(bundle, tableName, table);
1112 }
1113 } else {
1114 SC_log(LOG_ERR, "failed to get resource url: {bundle:%@, table: %@}", bundle, tableName);
1115 }
1116 }
1117
1118 if (table != NULL) {
1119 if (isA_CFDictionary(table)) {
1120 str = CFDictionaryGetValue(table, key);
1121 if (str != NULL) {
1122 CFRetain(str);
1123 }
1124 }
1125
1126 CFRelease(table);
1127 }
1128
1129 if (str == NULL) {
1130 str = CFRetain(value);
1131 }
1132
1133 return str;
1134 }
1135
1136
1137 #pragma mark -
1138 #pragma mark Mach port / CFMachPort management
1139
1140
1141 CFMachPortRef
1142 _SC_CFMachPortCreateWithPort(const char *portDescription,
1143 mach_port_t portNum,
1144 CFMachPortCallBack callout,
1145 CFMachPortContext *context)
1146 {
1147 CFMachPortRef port;
1148 Boolean shouldFree = FALSE;
1149
1150 port = CFMachPortCreateWithPort(NULL, portNum, callout, context, &shouldFree);
1151 if ((port == NULL) || shouldFree) {
1152 CFStringRef err;
1153 char *crash_info = NULL;
1154
1155 SC_log(LOG_NOTICE, "%s: CFMachPortCreateWithPort() failed , port = %p",
1156 portDescription,
1157 (void *)(uintptr_t)portNum);
1158 if (port != NULL) {
1159 err = CFStringCreateWithFormat(NULL, NULL,
1160 CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"),
1161 portDescription, port);
1162 } else {
1163 err = CFStringCreateWithFormat(NULL, NULL,
1164 CFSTR("%s: CFMachPortCreateWithPort returned NULL"),
1165 portDescription);
1166 }
1167 crash_info = _SC_cfstring_to_cstring(err, NULL, 0, kCFStringEncodingASCII);
1168 if (err != NULL) CFRelease(err);
1169
1170
1171 err = CFStringCreateWithFormat(NULL,
1172 NULL,
1173 CFSTR("A recycled mach_port has been detected by \"%s\"."),
1174 getprogname());
1175 _SC_crash(crash_info, CFSTR("CFMachPort error"), err);
1176 CFAllocatorDeallocate(NULL, crash_info);
1177 if (err != NULL) CFRelease(err);
1178 }
1179
1180 return port;
1181 }
1182
1183
1184 #pragma mark -
1185 #pragma mark DOS encoding/codepage
1186
1187
1188 #if !TARGET_OS_IPHONE
1189 void
1190 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding,
1191 UInt32 macRegion,
1192 CFStringEncoding *dosEncoding,
1193 UInt32 *dosCodepage)
1194 {
1195 switch (macEncoding) {
1196 case kCFStringEncodingMacRoman:
1197 if (macRegion != 0) /* anything non-zero is not US */
1198 *dosEncoding = kCFStringEncodingDOSLatin1;
1199 else /* US region */
1200 *dosEncoding = kCFStringEncodingDOSLatinUS;
1201 break;
1202
1203 case kCFStringEncodingMacJapanese:
1204 *dosEncoding = kCFStringEncodingDOSJapanese;
1205 break;
1206
1207 case kCFStringEncodingMacChineseTrad:
1208 *dosEncoding = kCFStringEncodingDOSChineseTrad;
1209 break;
1210
1211 case kCFStringEncodingMacKorean:
1212 *dosEncoding = kCFStringEncodingDOSKorean;
1213 break;
1214
1215 case kCFStringEncodingMacArabic:
1216 *dosEncoding = kCFStringEncodingDOSArabic;
1217 break;
1218
1219 case kCFStringEncodingMacHebrew:
1220 *dosEncoding = kCFStringEncodingDOSHebrew;
1221 break;
1222
1223 case kCFStringEncodingMacGreek:
1224 *dosEncoding = kCFStringEncodingDOSGreek;
1225 break;
1226
1227 case kCFStringEncodingMacCyrillic:
1228 *dosEncoding = kCFStringEncodingDOSCyrillic;
1229 break;
1230
1231 case kCFStringEncodingMacThai:
1232 *dosEncoding = kCFStringEncodingDOSThai;
1233 break;
1234
1235 case kCFStringEncodingMacChineseSimp:
1236 *dosEncoding = kCFStringEncodingDOSChineseSimplif;
1237 break;
1238
1239 case kCFStringEncodingMacCentralEurRoman:
1240 *dosEncoding = kCFStringEncodingDOSLatin2;
1241 break;
1242
1243 case kCFStringEncodingMacTurkish:
1244 *dosEncoding = kCFStringEncodingDOSTurkish;
1245 break;
1246
1247 case kCFStringEncodingMacCroatian:
1248 *dosEncoding = kCFStringEncodingDOSLatin2;
1249 break;
1250
1251 case kCFStringEncodingMacIcelandic:
1252 *dosEncoding = kCFStringEncodingDOSIcelandic;
1253 break;
1254
1255 case kCFStringEncodingMacRomanian:
1256 *dosEncoding = kCFStringEncodingDOSLatin2;
1257 break;
1258
1259 case kCFStringEncodingMacFarsi:
1260 *dosEncoding = kCFStringEncodingDOSArabic;
1261 break;
1262
1263 case kCFStringEncodingMacUkrainian:
1264 *dosEncoding = kCFStringEncodingDOSCyrillic;
1265 break;
1266
1267 default:
1268 *dosEncoding = kCFStringEncodingDOSLatin1;
1269 break;
1270 }
1271
1272 *dosCodepage = CFStringConvertEncodingToWindowsCodepage(*dosEncoding);
1273 return;
1274 }
1275 #endif // !TARGET_OS_IPHONE
1276
1277
1278 #pragma mark -
1279 #pragma mark Debugging
1280
1281
1282 /*
1283 * print status of in-use mach ports
1284 */
1285 void
1286 _SC_logMachPortStatus(void)
1287 {
1288 kern_return_t status;
1289 mach_port_name_array_t ports;
1290 mach_port_type_array_t types;
1291 mach_msg_type_number_t pi, pn, tn;
1292 CFMutableStringRef str;
1293
1294 SC_log(LOG_DEBUG, "----------");
1295
1296 /* report on ALL mach ports associated with this task */
1297 status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn);
1298 if (status == MACH_MSG_SUCCESS) {
1299 str = CFStringCreateMutable(NULL, 0);
1300 for (pi = 0; pi < pn; pi++) {
1301 char rights[16], *rp = &rights[0];
1302
1303 if (types[pi] != MACH_PORT_TYPE_NONE) {
1304 *rp++ = ' ';
1305 *rp++ = '(';
1306 if (types[pi] & MACH_PORT_TYPE_SEND)
1307 *rp++ = 'S';
1308 if (types[pi] & MACH_PORT_TYPE_RECEIVE)
1309 *rp++ = 'R';
1310 if (types[pi] & MACH_PORT_TYPE_SEND_ONCE)
1311 *rp++ = 'O';
1312 if (types[pi] & MACH_PORT_TYPE_PORT_SET)
1313 *rp++ = 'P';
1314 if (types[pi] & MACH_PORT_TYPE_DEAD_NAME)
1315 *rp++ = 'D';
1316 *rp++ = ')';
1317 }
1318 *rp = '\0';
1319 CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights);
1320 }
1321 SC_log(LOG_DEBUG, "Task ports (n=%d):%@", pn, str);
1322 CFRelease(str);
1323 }
1324
1325 return;
1326 }
1327
1328
1329 __private_extern__
1330 kern_return_t
1331 _SC_getMachPortReferences(mach_port_t port,
1332 mach_port_type_t *pt,
1333 mach_port_urefs_t *refs_send,
1334 mach_port_urefs_t *refs_recv,
1335 mach_port_status_t *recv_status,
1336 mach_port_urefs_t *refs_once,
1337 mach_port_urefs_t *refs_pset,
1338 mach_port_urefs_t *refs_dead,
1339 const char *err_prefix)
1340 {
1341 kern_return_t status;
1342
1343 status = mach_port_type(mach_task_self(), port, pt);
1344 if (status != KERN_SUCCESS) {
1345 SC_log(LOG_DEBUG, "%smach_port_type(..., 0x%x): %s",
1346 err_prefix,
1347 port,
1348 mach_error_string(status));
1349 return status;
1350 }
1351
1352 if ((refs_send != NULL) && ((*pt & MACH_PORT_TYPE_SEND) != 0)) {
1353 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, refs_send);
1354 if (status != KERN_SUCCESS) {
1355 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s",
1356 err_prefix,
1357 port,
1358 mach_error_string(status));
1359 return status;
1360 }
1361 }
1362
1363 if ((refs_recv != NULL) && (recv_status != NULL) && ((*pt & MACH_PORT_TYPE_RECEIVE) != 0)) {
1364 mach_msg_type_number_t count;
1365
1366 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, refs_recv);
1367 if (status != KERN_SUCCESS) {
1368 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s",
1369 err_prefix,
1370 port,
1371 mach_error_string(status));
1372 return status;
1373 }
1374
1375 count = MACH_PORT_RECEIVE_STATUS_COUNT;
1376 status = mach_port_get_attributes(mach_task_self(),
1377 port,
1378 MACH_PORT_RECEIVE_STATUS,
1379 (mach_port_info_t)recv_status,
1380 &count);
1381 if (status != KERN_SUCCESS) {
1382 SC_log(LOG_DEBUG, "%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s",
1383 err_prefix,
1384 port,
1385 mach_error_string(status));
1386 return status;
1387 }
1388 }
1389
1390 if ((refs_once != NULL) && ((*pt & MACH_PORT_TYPE_SEND_ONCE) != 0)) {
1391 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, refs_once);
1392 if (status != KERN_SUCCESS) {
1393 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s",
1394 err_prefix,
1395 port,
1396 mach_error_string(status));
1397 return status;
1398 }
1399 }
1400
1401 if ((refs_pset != NULL) && ((*pt & MACH_PORT_TYPE_PORT_SET) != 0)) {
1402 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, refs_pset);
1403 if (status != KERN_SUCCESS) {
1404 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s",
1405 err_prefix,
1406 port,
1407 mach_error_string(status));
1408 return status;
1409 }
1410 }
1411
1412 if ((refs_dead != NULL) && ((*pt & MACH_PORT_TYPE_DEAD_NAME) != 0)) {
1413 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, refs_dead);
1414 if (status != KERN_SUCCESS) {
1415 SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s",
1416 err_prefix,
1417 port,
1418 mach_error_string(status));
1419 return status;
1420 }
1421 }
1422
1423 return KERN_SUCCESS;
1424 }
1425
1426
1427 void
1428 _SC_logMachPortReferences(const char *str, mach_port_t port)
1429 {
1430 const char *blanks = " ";
1431 char buf[60];
1432 mach_port_type_t pt;
1433 mach_port_status_t recv_status = { .mps_nsrequest = 0, };
1434 mach_port_urefs_t refs_send = 0;
1435 mach_port_urefs_t refs_recv = 0;
1436 mach_port_urefs_t refs_once = 0;
1437 mach_port_urefs_t refs_pset = 0;
1438 mach_port_urefs_t refs_dead = 0;
1439 kern_return_t status;
1440
1441 buf[0] = '\0';
1442 if (str != NULL) {
1443 static int is_configd = -1;
1444
1445 if (is_configd == -1) {
1446 is_configd = (strcmp(getprogname(), _SC_SERVER_PROG) == 0);
1447 }
1448 if (is_configd == 1) {
1449 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1450 strlcpy(buf,
1451 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1452 sizeof(buf));
1453 }
1454
1455 // add provided string
1456 strlcat(buf, str, sizeof(buf));
1457
1458 // fill
1459 strlcat(buf, blanks, sizeof(buf));
1460 if (strcmp(&buf[sizeof(buf) - 3], " ") == 0) {
1461 buf[sizeof(buf) - 3] = ':';
1462 }
1463 }
1464
1465 status = _SC_getMachPortReferences(port,
1466 &pt,
1467 &refs_send,
1468 &refs_recv,
1469 &recv_status,
1470 &refs_once,
1471 &refs_pset,
1472 &refs_dead,
1473 buf);
1474 if (status != KERN_SUCCESS) {
1475 return;
1476 }
1477
1478 SC_log(LOG_DEBUG, "%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s",
1479 buf,
1480 port,
1481 port,
1482 refs_send,
1483 refs_recv,
1484 refs_once,
1485 refs_pset,
1486 refs_dead,
1487 recv_status.mps_nsrequest ? ", no more senders" : "",
1488 ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) ? ", dead name request" : "");
1489
1490 return;
1491 }
1492
1493
1494 CFStringRef
1495 _SC_copyBacktrace()
1496 {
1497 int n;
1498 void *stack[64];
1499 char **symbols;
1500 CFMutableStringRef trace;
1501
1502 n = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
1503 if (n == -1) {
1504 SC_log(LOG_NOTICE, "backtrace() failed: %s", strerror(errno));
1505 return NULL;
1506 }
1507
1508 trace = CFStringCreateMutable(NULL, 0);
1509
1510 symbols = backtrace_symbols(stack, n);
1511 if (symbols != NULL) {
1512 int i;
1513
1514 for (i = 0; i < n; i++) {
1515 CFStringAppendFormat(trace, NULL, CFSTR("%s\n"), symbols[i]);
1516 }
1517
1518 free(symbols);
1519 }
1520
1521 return trace;
1522 }
1523
1524
1525 /* CrashReporter info */
1526 #if !TARGET_OS_IPHONE
1527 #include <CrashReporterClient.h>
1528 #else // !TARGET_OS_IPHONE
1529 const char *__crashreporter_info__ = NULL;
1530 asm(".desc ___crashreporter_info__, 0x10");
1531 #endif // !TARGET_OS_IPHONE
1532
1533
1534 static Boolean
1535 _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1536 {
1537 #if !TARGET_OS_EMBEDDED || defined(DO_NOT_INFORM)
1538 #pragma unused(notifyHeader)
1539 #pragma unused(notifyMessage)
1540 #endif // !TARGET_OS_EMBEDDED || defined(DO_NOT_INFORM)
1541 #if TARGET_OS_SIMULATOR
1542 #pragma unused(crash_info)
1543 #endif // TARGET_OS_SIMULATOR
1544 Boolean ok = FALSE;
1545
1546 #if !TARGET_OS_SIMULATOR
1547 static bool (*dyfunc_SimulateCrash)(pid_t, mach_exception_data_type_t, CFStringRef) = NULL;
1548 static void *image = NULL;
1549 static dispatch_once_t once;
1550
1551 dispatch_once(&once, ^{
1552 image = _SC_dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport");
1553 if (image != NULL) {
1554 dyfunc_SimulateCrash = dlsym(image, "SimulateCrash");
1555 }
1556 });
1557
1558 if (dyfunc_SimulateCrash != NULL) {
1559 CFStringRef str;
1560
1561 str = CFStringCreateWithCString(NULL, crash_info, kCFStringEncodingUTF8);
1562 ok = dyfunc_SimulateCrash(getpid(), 0xbad0005cull, str);
1563 CFRelease(str);
1564 }
1565
1566 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1567 if (ok && (notifyHeader != NULL) && (notifyMessage != NULL)) {
1568 static Boolean warned = FALSE;
1569
1570 if (!warned) {
1571 CFStringRef displayMessage;
1572
1573 displayMessage = CFStringCreateWithFormat(NULL,
1574 NULL,
1575 CFSTR("%@\n\nPlease collect the crash report and file a Radar."),
1576 notifyMessage);
1577 CFUserNotificationDisplayNotice(0,
1578 kCFUserNotificationStopAlertLevel,
1579 NULL,
1580 NULL,
1581 NULL,
1582 notifyHeader,
1583 displayMessage,
1584 NULL);
1585 CFRelease(displayMessage);
1586 warned = TRUE;
1587 }
1588 }
1589 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1590 #endif // !TARGET_OS_SIMULATOR
1591
1592 return ok;
1593 }
1594
1595
1596 void
1597 _SC_crash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1598 {
1599 Boolean ok = FALSE;
1600
1601 if (crash_info != NULL) {
1602 #if !TARGET_OS_IPHONE
1603 CRSetCrashLogMessage(crash_info);
1604 #else // !TARGET_OS_IPHONE
1605 __crashreporter_info__ = crash_info;
1606 #endif // !TARGET_OS_IPHONE
1607
1608 SC_log(LOG_NOTICE, "%s", crash_info);
1609 }
1610
1611 if (_SC_isAppleInternal()) {
1612 // simulate a crash report
1613 ok = _SC_SimulateCrash(crash_info, notifyHeader, notifyMessage);
1614 #ifndef DO_NOT_CRASH
1615 if (!ok) {
1616 // if we could not simulate a crash report, crash for real
1617 __builtin_trap();
1618 }
1619 #endif // DO_NOT_CRASH
1620 }
1621
1622 #if !TARGET_OS_IPHONE
1623 CRSetCrashLogMessage(NULL);
1624 #else // !TARGET_OS_IPHONE
1625 __crashreporter_info__ = NULL;
1626 #endif // !TARGET_OS_IPHONE
1627 return;
1628 }
1629
1630
1631 Boolean
1632 _SC_getconninfo(int socket, struct sockaddr_storage *src_addr, struct sockaddr_storage *dest_addr, int *if_index, uint32_t *flags)
1633 {
1634 struct so_cinforeq request;
1635
1636 memset(&request, 0, sizeof(request));
1637
1638 if (src_addr != NULL) {
1639 memset(src_addr, 0, sizeof(*src_addr));
1640 request.scir_src = (struct sockaddr *)src_addr;
1641 request.scir_src_len = sizeof(*src_addr);
1642 }
1643
1644 if (dest_addr != NULL) {
1645 memset(dest_addr, 0, sizeof(*dest_addr));
1646 request.scir_dst = (struct sockaddr *)dest_addr;
1647 request.scir_dst_len = sizeof(*dest_addr);
1648 }
1649
1650 if (ioctl(socket, SIOCGCONNINFO, &request) != 0) {
1651 SC_log(LOG_NOTICE, "SIOCGCONNINFO failed: %s", strerror(errno));
1652 return FALSE;
1653 }
1654
1655 if (if_index != NULL) {
1656 *if_index = 0;
1657 *if_index = request.scir_ifindex;
1658 }
1659
1660 if (flags != NULL) {
1661 *flags = 0;
1662 *flags = request.scir_flags;
1663 }
1664
1665 return TRUE;
1666 }