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