2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * November 9, 2000 Allan Nathanson <ajn@apple.com>
34 #define SC_LOG_HANDLE _SC_LOG_DEFAULT
35 #include <SystemConfiguration/SystemConfiguration.h>
36 #include <SystemConfiguration/SCValidation.h>
37 #include <SystemConfiguration/SCPrivate.h>
39 #include <sys/param.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
44 #include <net/if_dl.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
48 #include <dispatch/dispatch.h>
50 #include <mach/mach.h>
51 #include <mach/notify.h>
52 #include <mach/mach_error.h>
58 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
59 #include <CoreFoundation/CFUserNotification.h>
60 #endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
62 /* CrashReporter "Application Specific Information" */
63 #include <CrashReporterClient.h>
69 #pragma mark Miscellaneous
72 __private_extern__
char *
73 _SC_cfstring_to_cstring_ext(CFStringRef cfstr
, char *buf
, CFIndex bufLen
, CFStringEncoding encoding
, UInt8 lossByte
, CFIndex
*usedBufLen
)
82 len
= CFStringGetLength(cfstr
);
84 /* how much buffer space will we really need? */
85 converted
= CFStringGetBytes(cfstr
,
93 if (converted
< len
) {
94 /* if full string could not be converted */
102 if (bufLen
< (last
+ 1)) {
103 /* if the size of the provided buffer is too small */
108 /* allocate a buffer */
110 buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
116 (void)CFStringGetBytes(cfstr
,
126 if (usedBufLen
!= NULL
) {
135 _SC_cfstring_to_cstring(CFStringRef cfstr
, char *buf
, CFIndex bufLen
, CFStringEncoding encoding
)
137 return _SC_cfstring_to_cstring_ext(cfstr
, buf
, bufLen
, encoding
, 0, NULL
);
143 _SC_sockaddr_to_string(const struct sockaddr
*address
, char *buf
, size_t bufLen
)
146 const struct sockaddr
*sa
;
147 const struct sockaddr_in
*sin
;
148 const struct sockaddr_in6
*sin6
;
149 const struct sockaddr_dl
*sdl
;
154 memset(buf
, 0, bufLen
);
155 switch (address
->sa_family
) {
157 (void)inet_ntop(addr
.sin
->sin_family
,
163 (void)inet_ntop(addr
.sin6
->sin6_family
,
164 &addr
.sin6
->sin6_addr
,
167 if (addr
.sin6
->sin6_scope_id
!= 0) {
171 if ((n
+IF_NAMESIZE
+1) <= bufLen
) {
173 if_indextoname(addr
.sin6
->sin6_scope_id
, &buf
[n
]);
179 snprintf(buf
, bufLen
, "unexpected address family %d", address
->sa_family
);
188 _SC_string_to_sockaddr(const char *str
, sa_family_t af
, void *buf
, size_t bufLen
)
193 struct sockaddr_in
*sin
;
194 struct sockaddr_in6
*sin6
;
198 bufLen
= sizeof(struct sockaddr_storage
);
199 addr
.buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
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) {
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) {
217 addr
.sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
218 addr
.sin6
->sin6_family
= AF_INET6
;
220 p
= strchr(str
, '%');
222 addr
.sin6
->sin6_scope_id
= if_nametoindex(p
+ 1);
225 if (IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
->sin6_addr
) ||
226 IN6_IS_ADDR_MC_LINKLOCAL(&addr
.sin6
->sin6_addr
)) {
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
;
237 if (addr
.buf
!= buf
) {
238 CFAllocatorDeallocate(NULL
, addr
.buf
);
248 _SC_sendMachMessage(mach_port_t port
, mach_msg_id_t msg_id
)
250 mach_msg_empty_send_t msg
;
251 mach_msg_option_t options
;
252 kern_return_t status
;
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 */
265 MACH_PORT_NULL
, /* rcv_name */
267 MACH_PORT_NULL
); /* notify */
268 if ((status
== MACH_SEND_INVALID_DEST
) || (status
== MACH_SEND_TIMED_OUT
)) {
269 mach_msg_destroy(&msg
.header
);
277 _SC_trimDomain(CFStringRef domain
)
281 if (!isA_CFString(domain
)) {
285 // remove any leading/trailing dots
286 length
= CFStringGetLength(domain
);
288 (CFStringFindWithOptions(domain
,
293 CFStringFindWithOptions(domain
,
295 CFRangeMake(0, length
),
296 kCFCompareAnchored
|kCFCompareBackwards
,
299 CFMutableStringRef trimmed
;
301 trimmed
= CFStringCreateMutableCopy(NULL
, 0, domain
);
302 CFStringTrim(trimmed
, CFSTR("."));
303 domain
= (CFStringRef
)trimmed
;
304 length
= CFStringGetLength(domain
);
319 _SC_hw_model(Boolean trim
)
321 static CFStringRef model
= NULL
;
322 static CFStringRef model_trimmed
= NULL
;
323 static dispatch_once_t once
;
325 dispatch_once(&once
, ^{
328 int mib
[] = { CTL_HW
, HW_MODEL
};
329 size_t n
= sizeof(hwModel
);
333 memset(&hwModel
, 0, sizeof(hwModel
));
334 ret
= sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &hwModel
, &n
, NULL
, 0);
336 SC_log(LOG_NOTICE
, "sysctl() CTL_HW/HW_MODEL failed: %s", strerror(errno
));
339 hwModel
[sizeof(hwModel
) - 1] = '\0';
340 model
= CFStringCreateWithCString(NULL
, hwModel
, kCFStringEncodingASCII
);
342 // and the "trimmed" name
343 // ... remove everything after (and including) a comma
344 // ... and then any trailing digits
345 cp
= index(hwModel
, ',');
349 n
= strlen(hwModel
) - 1;
351 if (!isdigit(hwModel
[n
])) {
356 model_trimmed
= CFStringCreateWithCString(NULL
, hwModel
, kCFStringEncodingASCII
);
359 return trim
? model_trimmed
: model
;
364 #pragma mark Serialization
368 __CFDataCopyVMData(CFDataRef data
, void **dataRef
, CFIndex
*dataLen
)
372 vm_address_t vm_address
;
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
) {
384 memcpy((void *)vm_address
, (char *)CFDataGetBytePtr(data
), vm_size
);
385 *dataRef
= (void *)vm_address
;
393 _SCSerialize(CFPropertyListRef obj
, CFDataRef
*xml
, void **dataRef
, CFIndex
*dataLen
)
397 if ((xml
== NULL
) && ((dataRef
== NULL
) || (dataLen
== NULL
))) {
398 /* if not keeping track of allocated space */
402 myXml
= CFPropertyListCreateData(NULL
,
404 kCFPropertyListBinaryFormat_v1_0
,
408 SC_log(LOG_NOTICE
, "CFPropertyListCreateData() failed");
412 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
421 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
422 *dataRef
= (void *)CFDataGetBytePtr(myXml
);
423 *dataLen
= CFDataGetLength(myXml
);
428 kr
= __CFDataCopyVMData(myXml
, dataRef
, dataLen
);
430 if (kr
!= KERN_SUCCESS
) {
431 SC_log(LOG_NOTICE
, "__CFDataCreateVMData() failed: %s", mach_error_string(kr
));
441 _SCUnserialize(CFPropertyListRef
*obj
, CFDataRef xml
, void *dataRef
, CFIndex dataLen
)
443 CFErrorRef error
= NULL
;
446 kern_return_t status
;
448 xml
= CFDataCreateWithBytesNoCopy(NULL
, (void *)dataRef
, dataLen
, kCFAllocatorNull
);
449 *obj
= CFPropertyListCreateWithData(NULL
, xml
, kCFPropertyListImmutable
, NULL
, &error
);
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 */
458 *obj
= CFPropertyListCreateWithData(NULL
, xml
, kCFPropertyListImmutable
, NULL
, &error
);
463 SC_log(LOG_NOTICE
, "CFPropertyListCreateWithData() failed: %@", error
);
466 _SCErrorSet(kSCStatusFailed
);
475 _SCSerializeString(CFStringRef str
, CFDataRef
*data
, void **dataRef
, CFIndex
*dataLen
)
479 if (!isA_CFString(str
)) {
480 /* if not a CFString */
484 if ((data
== NULL
) && ((dataRef
== NULL
) || (dataLen
== NULL
))) {
485 /* if not keeping track of allocated space */
489 myData
= CFStringCreateExternalRepresentation(NULL
, str
, kCFStringEncodingUTF8
, 0);
490 if (myData
== NULL
) {
491 SC_log(LOG_NOTICE
, "CFStringCreateExternalRepresentation() failed");
495 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
504 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
505 *dataRef
= (void *)CFDataGetBytePtr(myData
);
506 *dataLen
= CFDataGetLength(myData
);
511 kr
= __CFDataCopyVMData(myData
, dataRef
, dataLen
);
513 if (kr
!= KERN_SUCCESS
) {
514 SC_log(LOG_NOTICE
, "__CFDataCreateVMData() failed: %s", mach_error_string(kr
));
524 _SCUnserializeString(CFStringRef
*str
, CFDataRef utf8
, void *dataRef
, CFIndex dataLen
)
527 kern_return_t status
;
529 utf8
= CFDataCreateWithBytesNoCopy(NULL
, dataRef
, dataLen
, kCFAllocatorNull
);
530 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
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 */
539 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
543 SC_log(LOG_NOTICE
, "CFStringCreateFromExternalRepresentation() failed");
552 _SCSerializeData(CFDataRef data
, void **dataRef
, CFIndex
*dataLen
)
556 if (!isA_CFData(data
)) {
557 /* if not a CFData */
561 kr
= __CFDataCopyVMData(data
, dataRef
, dataLen
);
562 if (kr
!= KERN_SUCCESS
) {
563 SC_log(LOG_NOTICE
, "__CFDataCreateVMData() failed: %s", mach_error_string(kr
));
572 _SCUnserializeData(CFDataRef
*data
, void *dataRef
, CFIndex dataLen
)
574 kern_return_t status
;
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
);
588 CF_RETURNS_RETAINED CFDictionaryRef
589 _SCSerializeMultiple(CFDictionaryRef dict
)
592 const void * keys_q
[N_QUICK
];
593 const void ** keys
= keys_q
;
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
;
601 nElements
= CFDictionaryGetCount(dict
);
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);
608 memset(pLists
, 0, nElements
* sizeof(CFDataRef
));
610 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
611 for (i
= 0; i
< nElements
; i
++) {
613 if (!_SCSerialize((CFPropertyListRef
)values
[i
], (CFDataRef
*)&pLists
[i
], NULL
, NULL
)) {
619 newDict
= CFDictionaryCreate(NULL
,
623 &kCFTypeDictionaryKeyCallBacks
,
624 &kCFTypeDictionaryValueCallBacks
);
629 for (i
= 0; i
< nElements
; i
++) {
630 if (pLists
[i
] != NULL
) CFRelease((CFDataRef
)pLists
[i
]);
633 if (keys
!= keys_q
) {
634 CFAllocatorDeallocate(NULL
, keys
);
635 CFAllocatorDeallocate(NULL
, values
);
636 CFAllocatorDeallocate(NULL
, pLists
);
646 _SCUnserializeMultiple(CFDictionaryRef dict
)
648 const void * keys_q
[N_QUICK
];
649 const void ** keys
= keys_q
;
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
;
657 nElements
= CFDictionaryGetCount(dict
);
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);
666 memset(pLists
, 0, nElements
* sizeof(CFTypeRef
));
668 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
669 for (i
= 0; i
< nElements
; i
++) {
670 if (!_SCUnserialize((CFPropertyListRef
*)&pLists
[i
], values
[i
], NULL
, 0)) {
676 newDict
= CFDictionaryCreate(NULL
,
680 &kCFTypeDictionaryKeyCallBacks
,
681 &kCFTypeDictionaryValueCallBacks
);
688 for (i
= 0; i
< nElements
; i
++) {
689 if (pLists
[i
]) CFRelease(pLists
[i
]);
692 if (keys
!= keys_q
) {
693 CFAllocatorDeallocate(NULL
, keys
);
694 CFAllocatorDeallocate(NULL
, values
);
695 CFAllocatorDeallocate(NULL
, pLists
);
707 _SCCreatePropertyListFromResource(CFURLRef url
)
709 CFDictionaryRef dict
= NULL
;
712 CFReadStreamRef readStream
;
713 CFNumberRef val
= NULL
;
715 if (!CFURLCopyResourcePropertyForKey(url
, kCFURLFileSizeKey
, &val
, NULL
) ||
717 // if size not available
718 SC_log(LOG_NOTICE
, "CFURLCopyResourcePropertyForKey() size not available: %@", url
);
722 ok
= CFNumberGetValue(val
, kCFNumberSInt64Type
, &fileLen
);
724 if (!ok
|| (fileLen
== 0)) {
725 // if empty or size too large
726 SC_log(LOG_INFO
, "_SCCreatePropertyListFromResource() improper size: %@", url
);
730 readStream
= CFReadStreamCreateWithFile(NULL
, url
);
731 if (readStream
!= NULL
) {
732 if (CFReadStreamOpen(readStream
)) {
736 buffer
= CFAllocatorAllocate(NULL
, (CFIndex
)fileLen
, 0);
737 dataLen
= CFReadStreamRead(readStream
, buffer
, (CFIndex
)fileLen
);
738 if (dataLen
== (CFIndex
)fileLen
) {
741 data
= CFDataCreateWithBytesNoCopy(NULL
, buffer
, (CFIndex
)fileLen
, kCFAllocatorNull
);
743 dict
= CFPropertyListCreateWithData(NULL
,
745 kCFPropertyListImmutable
,
751 CFAllocatorDeallocate(NULL
, buffer
);
752 CFReadStreamClose(readStream
);
754 CFRelease(readStream
);
762 #pragma mark CFRunLoop scheduling
765 __private_extern__
void
766 _SC_signalRunLoop(CFTypeRef obj
, CFRunLoopSourceRef rls
, CFArrayRef rlList
)
768 CFRunLoopRef rl
= NULL
;
769 CFRunLoopRef rl1
= NULL
;
771 CFIndex n
= CFArrayGetCount(rlList
);
777 /* get first runLoop for this object */
778 for (i
= 0; i
< n
; i
+= 3) {
779 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
783 rl1
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
788 /* if not scheduled */
792 /* check if we have another runLoop for this object */
794 for (i
= i
+3; i
< n
; i
+= 3) {
797 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
801 rl2
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
802 if (!CFEqual(rl1
, rl2
)) {
803 /* we've got more than one runLoop */
810 /* if we only have one runLoop */
815 /* more than one different runLoop, so we must pick one */
816 for (i
= 0; i
< n
; i
+=3) {
819 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
823 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
824 rlMode
= CFRunLoopCopyCurrentMode(rl
);
825 if (rlMode
!= NULL
) {
828 waiting
= (CFRunLoopIsWaiting(rl
) && CFRunLoopContainsSource(rl
, rls
, rlMode
));
831 /* we've found a runLoop that's "ready" */
838 /* didn't choose one above, so choose first */
839 CFRunLoopWakeUp(rl1
);
844 __private_extern__ Boolean
845 _SC_isScheduled(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
848 CFIndex n
= CFArrayGetCount(rlList
);
850 for (i
= 0; i
< n
; i
+= 3) {
851 if ((obj
!= NULL
) && !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
854 if ((runLoop
!= NULL
) && !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
857 if ((runLoopMode
!= NULL
) && !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
867 __private_extern__
void
868 _SC_schedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
870 CFArrayAppendValue(rlList
, obj
);
871 CFArrayAppendValue(rlList
, runLoop
);
872 CFArrayAppendValue(rlList
, runLoopMode
);
878 __private_extern__ Boolean
879 _SC_unschedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
, Boolean all
)
882 Boolean found
= FALSE
;
883 CFIndex n
= CFArrayGetCount(rlList
);
886 if ((obj
!= NULL
) && !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
890 if ((runLoop
!= NULL
) && !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
894 if ((runLoopMode
!= NULL
) && !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
901 CFArrayRemoveValueAtIndex(rlList
, i
+ 2);
902 CFArrayRemoveValueAtIndex(rlList
, i
+ 1);
903 CFArrayRemoveValueAtIndex(rlList
, i
);
921 _SC_getApplicationBundleID(void)
923 static CFStringRef bundleID
= NULL
;
924 static dispatch_once_t once
;
926 dispatch_once(&once
, ^{
929 bundle
= CFBundleGetMainBundle();
930 if (bundle
!= NULL
) {
931 bundleID
= CFBundleGetIdentifier(bundle
);
932 if (bundleID
!= NULL
) {
937 url
= CFBundleCopyExecutableURL(bundle
);
939 bundleID
= CFURLCopyPath(url
);
944 if (bundleID
!= NULL
) {
945 if (CFEqual(bundleID
, CFSTR("/"))) {
951 if (bundleID
== NULL
) {
952 bundleID
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("Unknown(%d)"), getpid());
960 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
961 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
963 #define SUFFIX_SYM "~sym"
964 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
966 #define SUFFIX_DST "~dst"
970 _SC_CFBundleGet(void)
972 static CFBundleRef bundle
= NULL
;
977 if (bundle
!= NULL
) {
981 bundle
= CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID
);
982 if (bundle
!= NULL
) {
983 CFRetain(bundle
); // we want to hold a reference to the bundle
986 SC_log(LOG_NOTICE
, "could not get CFBundle for \"%@\". Trying harder...",
987 SYSTEMCONFIGURATION_BUNDLE_ID
);
990 // if appropriate (e.g. when debugging), try a bit harder
992 env
= getenv("DYLD_FRAMEWORK_PATH");
993 len
= (env
!= NULL
) ? strlen(env
) : 0;
995 if (len
> 0) { /* We are debugging */
997 // trim any trailing slashes
999 if (env
[len
- 1] != '/') {
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
];
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
);
1015 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
1017 len
+ SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN
,
1019 bundle
= CFBundleCreate(NULL
, url
);
1024 if (bundle
== NULL
) { /* Try a more "direct" route to get the bundle */
1026 url
= CFURLCreateWithFileSystemPath(NULL
,
1027 CFSTR(SYSTEMCONFIGURATION_FRAMEWORK_PATH
),
1028 kCFURLPOSIXPathStyle
,
1031 bundle
= CFBundleCreate(NULL
, url
);
1035 if (bundle
== NULL
) {
1036 SC_log(LOG_ERR
, "could not get CFBundle for \"%@\"", SYSTEMCONFIGURATION_BUNDLE_ID
);
1047 * <key>bundleID-tableName</key>
1049 * ... property list from non-localized bundle URL
1053 static CFMutableDictionaryRef cachedInfo
= NULL
;
1056 static dispatch_queue_t
1057 _SC_CFBundleCachedInfoQueue()
1059 static dispatch_once_t once
;
1060 static dispatch_queue_t q
;
1062 dispatch_once(&once
, ^{
1063 q
= dispatch_queue_create("_SC_CFBundleCachedInfo", NULL
);
1071 _SC_CFBundleCachedInfoCopyTableKey(CFBundleRef bundle
, CFStringRef tableName
)
1073 CFStringRef bundleID
;
1074 CFStringRef tableKey
;
1076 bundleID
= CFBundleGetIdentifier(bundle
);
1077 tableKey
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@: %@"), bundleID
, tableName
);
1082 static CFDictionaryRef
1083 _SC_CFBundleCachedInfoCopyTable(CFBundleRef bundle
, CFStringRef tableName
)
1085 __block CFDictionaryRef dict
= NULL
;
1087 dispatch_sync(_SC_CFBundleCachedInfoQueue(), ^{
1088 if (cachedInfo
!= NULL
) {
1089 CFStringRef tableKey
;
1091 tableKey
= _SC_CFBundleCachedInfoCopyTableKey(bundle
, tableName
);
1092 dict
= CFDictionaryGetValue(cachedInfo
, tableKey
);
1096 CFRelease(tableKey
);
1105 _SC_CFBundleCachedInfoSaveTable(CFBundleRef bundle
, CFStringRef tableName
, CFDictionaryRef table
)
1108 dispatch_sync(_SC_CFBundleCachedInfoQueue(), ^{
1109 CFStringRef tableKey
;
1111 tableKey
= _SC_CFBundleCachedInfoCopyTableKey(bundle
, tableName
);
1112 SC_log(LOG_DEBUG
, "Caching %@", tableKey
);
1114 if (cachedInfo
== NULL
) {
1115 cachedInfo
= CFDictionaryCreateMutable(NULL
,
1117 &kCFTypeDictionaryKeyCallBacks
,
1118 &kCFTypeDictionaryValueCallBacks
);
1120 CFDictionarySetValue(cachedInfo
, tableKey
, table
);
1121 CFRelease(tableKey
);
1129 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle
, CFStringRef key
, CFStringRef value
, CFStringRef tableName
)
1131 CFStringRef str
= NULL
;
1132 CFDictionaryRef table
= NULL
;
1135 if ((tableName
== NULL
) || CFEqual(tableName
, CFSTR(""))) {
1136 tableName
= CFSTR("Localizable");
1139 table
= _SC_CFBundleCachedInfoCopyTable(bundle
, tableName
);
1140 if (table
== NULL
) {
1141 url
= CFBundleCopyResourceURLForLocalization(bundle
,
1147 table
= _SCCreatePropertyListFromResource(url
);
1149 if (table
!= NULL
) {
1150 _SC_CFBundleCachedInfoSaveTable(bundle
, tableName
, table
);
1153 SC_log(LOG_ERR
, "failed to get resource url: {bundle:%@, table: %@}", bundle
, tableName
);
1157 if (table
!= NULL
) {
1158 if (isA_CFDictionary(table
)) {
1159 str
= CFDictionaryGetValue(table
, key
);
1169 str
= CFRetain(value
);
1177 #pragma mark Mach port / CFMachPort management
1181 _SC_CFMachPortCreateWithPort(const char *portDescription
,
1182 mach_port_t portNum
,
1183 CFMachPortCallBack callout
,
1184 CFMachPortContext
*context
)
1187 Boolean shouldFree
= FALSE
;
1189 port
= CFMachPortCreateWithPort(NULL
, portNum
, callout
, context
, &shouldFree
);
1190 if ((port
== NULL
) || shouldFree
) {
1194 SC_log(LOG_NOTICE
, "%s: CFMachPortCreateWithPort() failed , port = %p",
1196 (void *)(uintptr_t)portNum
);
1198 err
= CFStringCreateWithFormat(NULL
, NULL
,
1199 CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"),
1200 portDescription
, port
);
1202 err
= CFStringCreateWithFormat(NULL
, NULL
,
1203 CFSTR("%s: CFMachPortCreateWithPort returned NULL"),
1206 crash_info
= _SC_cfstring_to_cstring(err
, NULL
, 0, kCFStringEncodingASCII
);
1209 err
= CFStringCreateWithFormat(NULL
,
1211 CFSTR("A recycled mach_port has been detected by \"%s\"."),
1213 _SC_crash(crash_info
, CFSTR("CFMachPort error"), err
);
1214 CFAllocatorDeallocate(NULL
, crash_info
);
1223 #pragma mark DOS encoding/codepage
1226 #if !TARGET_OS_IPHONE
1228 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding
,
1230 CFStringEncoding
*dosEncoding
,
1231 UInt32
*dosCodepage
)
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
;
1241 case kCFStringEncodingMacJapanese
:
1242 *dosEncoding
= kCFStringEncodingDOSJapanese
;
1245 case kCFStringEncodingMacChineseTrad
:
1246 *dosEncoding
= kCFStringEncodingDOSChineseTrad
;
1249 case kCFStringEncodingMacKorean
:
1250 *dosEncoding
= kCFStringEncodingDOSKorean
;
1253 case kCFStringEncodingMacArabic
:
1254 *dosEncoding
= kCFStringEncodingDOSArabic
;
1257 case kCFStringEncodingMacHebrew
:
1258 *dosEncoding
= kCFStringEncodingDOSHebrew
;
1261 case kCFStringEncodingMacGreek
:
1262 *dosEncoding
= kCFStringEncodingDOSGreek
;
1265 case kCFStringEncodingMacCyrillic
:
1266 *dosEncoding
= kCFStringEncodingDOSCyrillic
;
1269 case kCFStringEncodingMacThai
:
1270 *dosEncoding
= kCFStringEncodingDOSThai
;
1273 case kCFStringEncodingMacChineseSimp
:
1274 *dosEncoding
= kCFStringEncodingDOSChineseSimplif
;
1277 case kCFStringEncodingMacCentralEurRoman
:
1278 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1281 case kCFStringEncodingMacTurkish
:
1282 *dosEncoding
= kCFStringEncodingDOSTurkish
;
1285 case kCFStringEncodingMacCroatian
:
1286 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1289 case kCFStringEncodingMacIcelandic
:
1290 *dosEncoding
= kCFStringEncodingDOSIcelandic
;
1293 case kCFStringEncodingMacRomanian
:
1294 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1297 case kCFStringEncodingMacFarsi
:
1298 *dosEncoding
= kCFStringEncodingDOSArabic
;
1301 case kCFStringEncodingMacUkrainian
:
1302 *dosEncoding
= kCFStringEncodingDOSCyrillic
;
1306 *dosEncoding
= kCFStringEncodingDOSLatin1
;
1310 *dosCodepage
= CFStringConvertEncodingToWindowsCodepage(*dosEncoding
);
1313 #endif // !TARGET_OS_IPHONE
1317 #pragma mark Debugging
1321 * print status of in-use mach ports
1324 _SC_logMachPortStatus(void)
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
;
1332 SC_log(LOG_DEBUG
, "----------");
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];
1341 if (types
[pi
] != MACH_PORT_TYPE_NONE
) {
1344 if (types
[pi
] & MACH_PORT_TYPE_SEND
)
1346 if (types
[pi
] & MACH_PORT_TYPE_RECEIVE
)
1348 if (types
[pi
] & MACH_PORT_TYPE_SEND_ONCE
)
1350 if (types
[pi
] & MACH_PORT_TYPE_PORT_SET
)
1352 if (types
[pi
] & MACH_PORT_TYPE_DEAD_NAME
)
1357 CFStringAppendFormat(str
, NULL
, CFSTR(" %d%s"), ports
[pi
], rights
);
1359 SC_log(LOG_DEBUG
, "Task ports (n=%d):%@", pn
, str
);
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
)
1379 kern_return_t status
;
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",
1386 mach_error_string(status
));
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",
1396 mach_error_string(status
));
1401 if ((refs_recv
!= NULL
) && (recv_status
!= NULL
) && ((*pt
& MACH_PORT_TYPE_RECEIVE
) != 0)) {
1402 mach_msg_type_number_t count
;
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",
1409 mach_error_string(status
));
1413 count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1414 status
= mach_port_get_attributes(mach_task_self(),
1416 MACH_PORT_RECEIVE_STATUS
,
1417 (mach_port_info_t
)recv_status
,
1419 if (status
!= KERN_SUCCESS
) {
1420 SC_log(LOG_DEBUG
, "%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s",
1423 mach_error_string(status
));
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",
1434 mach_error_string(status
));
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",
1445 mach_error_string(status
));
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",
1456 mach_error_string(status
));
1461 return KERN_SUCCESS
;
1466 _SC_logMachPortReferences(const char *str
, mach_port_t port
)
1468 const char *blanks
= " ";
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
;
1481 static int is_configd
= -1;
1483 if (is_configd
== -1) {
1484 is_configd
= (strcmp(getprogname(), _SC_SERVER_PROG
) == 0);
1486 if (is_configd
== 1) {
1487 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1489 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1493 // add provided string
1494 strlcat(buf
, str
, sizeof(buf
));
1497 strlcat(buf
, blanks
, sizeof(buf
));
1498 if (strcmp(&buf
[sizeof(buf
) - 3], " ") == 0) {
1499 buf
[sizeof(buf
) - 3] = ':';
1503 status
= _SC_getMachPortReferences(port
,
1512 if (status
!= KERN_SUCCESS
) {
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",
1525 recv_status
.mps_nsrequest
? ", no more senders" : "",
1526 ((pt
& MACH_PORT_TYPE_DEAD_NAME
) != 0) ? ", dead name request" : "");
1538 CFMutableStringRef trace
;
1540 n
= backtrace(stack
, sizeof(stack
)/sizeof(stack
[0]));
1542 SC_log(LOG_NOTICE
, "backtrace() failed: %s", strerror(errno
));
1546 trace
= CFStringCreateMutable(NULL
, 0);
1548 symbols
= backtrace_symbols(stack
, n
);
1549 if (symbols
!= NULL
) {
1552 for (i
= 0; i
< n
; i
++) {
1553 CFStringAppendFormat(trace
, NULL
, CFSTR("%s\n"), symbols
[i
]);
1564 _SC_ReportCrash(CFStringRef notifyHeader
, CFStringRef notifyMessage
)
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
;
1573 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
1574 CFStringRef displayMessage
;
1576 displayMessage
= CFStringCreateWithFormat(NULL
,
1578 CFSTR("%@\n\nPlease collect the crash report and file a Radar."),
1580 CFUserNotificationDisplayNotice(0,
1581 kCFUserNotificationStopAlertLevel
,
1588 CFRelease(displayMessage
);
1589 #endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
1598 _SC_crash(const char *crash_info
, CFStringRef notifyHeader
, CFStringRef notifyMessage
)
1600 if (_SC_isAppleInternal()) {
1601 if (crash_info
== NULL
) {
1602 crash_info
= "_SC_crash() called w/o \"crash_info\"";
1605 // augment the crash log message
1606 CRSetCrashLogMessage(crash_info
);
1608 // simulate a crash report
1609 os_log_with_type(SC_LOG_HANDLE(), OS_LOG_TYPE_FAULT
, "%s", crash_info
);
1611 // report the crash to the user
1612 if ((notifyHeader
!= NULL
) && (notifyMessage
!= NULL
)) {
1613 _SC_ReportCrash(notifyHeader
, notifyMessage
);
1616 // ... and cleanup after the crash report has been generated
1617 CRSetCrashLogMessage(NULL
);
1625 _SC_getconninfo(int socket
, struct sockaddr_storage
*src_addr
, struct sockaddr_storage
*dest_addr
, int *if_index
, uint32_t *flags
)
1627 struct so_cinforeq request
;
1629 memset(&request
, 0, sizeof(request
));
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
);
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
);
1643 if (ioctl(socket
, SIOCGCONNINFO
, &request
) != 0) {
1644 SC_log(LOG_NOTICE
, "SIOCGCONNINFO failed: %s", strerror(errno
));
1648 if (if_index
!= NULL
) {
1650 *if_index
= request
.scir_ifindex
;
1653 if (flags
!= NULL
) {
1655 *flags
= request
.scir_flags
;