2 * Copyright (c) 2000-2016 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 DO_NOT_CRASH
35 //#define DO_NOT_INFORM
37 #define SC_LOG_HANDLE _SC_LOG_DEFAULT()
38 #include <SystemConfiguration/SystemConfiguration.h>
39 #include <SystemConfiguration/SCValidation.h>
40 #include <SystemConfiguration/SCPrivate.h>
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
45 #include <sys/ioctl.h>
47 #include <net/if_dl.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
51 #include <dispatch/dispatch.h>
53 #include <mach/mach.h>
54 #include <mach/notify.h>
55 #include <mach/mach_error.h>
63 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
64 #include <CoreFoundation/CFUserNotification.h>
65 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
71 #pragma mark Miscellaneous
74 __private_extern__
char *
75 _SC_cfstring_to_cstring_ext(CFStringRef cfstr
, char *buf
, CFIndex bufLen
, CFStringEncoding encoding
, UInt8 lossByte
, CFIndex
*usedBufLen
)
84 len
= CFStringGetLength(cfstr
);
86 /* how much buffer space will we really need? */
87 converted
= CFStringGetBytes(cfstr
,
95 if (converted
< len
) {
96 /* if full string could not be converted */
104 if (bufLen
< (last
+ 1)) {
105 /* if the size of the provided buffer is too small */
110 /* allocate a buffer */
112 buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
118 (void)CFStringGetBytes(cfstr
,
128 if (usedBufLen
!= NULL
) {
137 _SC_cfstring_to_cstring(CFStringRef cfstr
, char *buf
, CFIndex bufLen
, CFStringEncoding encoding
)
139 return _SC_cfstring_to_cstring_ext(cfstr
, buf
, bufLen
, encoding
, 0, NULL
);
145 _SC_sockaddr_to_string(const struct sockaddr
*address
, char *buf
, size_t bufLen
)
148 const struct sockaddr
*sa
;
149 const struct sockaddr_in
*sin
;
150 const struct sockaddr_in6
*sin6
;
151 const struct sockaddr_dl
*sdl
;
157 switch (address
->sa_family
) {
159 (void)inet_ntop(addr
.sin
->sin_family
,
165 (void)inet_ntop(addr
.sin6
->sin6_family
,
166 &addr
.sin6
->sin6_addr
,
169 if (addr
.sin6
->sin6_scope_id
!= 0) {
173 if ((n
+IF_NAMESIZE
+1) <= (int)bufLen
) {
175 if_indextoname(addr
.sin6
->sin6_scope_id
, &buf
[n
]);
181 snprintf(buf
, bufLen
, "unexpected address family %d", address
->sa_family
);
190 _SC_string_to_sockaddr(const char *str
, sa_family_t af
, void *buf
, size_t bufLen
)
195 struct sockaddr_in
*sin
;
196 struct sockaddr_in6
*sin6
;
200 bufLen
= sizeof(struct sockaddr_storage
);
201 addr
.buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
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) {
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) {
219 addr
.sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
220 addr
.sin6
->sin6_family
= AF_INET6
;
222 p
= strchr(str
, '%');
224 addr
.sin6
->sin6_scope_id
= if_nametoindex(p
+ 1);
227 if (IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
->sin6_addr
) ||
228 IN6_IS_ADDR_MC_LINKLOCAL(&addr
.sin6
->sin6_addr
)) {
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
;
239 if (addr
.buf
!= buf
) {
240 CFAllocatorDeallocate(NULL
, addr
.buf
);
250 _SC_sendMachMessage(mach_port_t port
, mach_msg_id_t msg_id
)
252 mach_msg_empty_send_t msg
;
253 mach_msg_option_t options
;
254 kern_return_t status
;
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 */
266 MACH_PORT_NULL
, /* rcv_name */
268 MACH_PORT_NULL
); /* notify */
269 if (status
!= MACH_MSG_SUCCESS
) {
270 mach_msg_destroy(&msg
.header
);
278 _SC_trimDomain(CFStringRef domain
)
282 if (!isA_CFString(domain
)) {
286 // remove any leading/trailing dots
287 length
= CFStringGetLength(domain
);
289 (CFStringFindWithOptions(domain
,
294 CFStringFindWithOptions(domain
,
296 CFRangeMake(0, length
),
297 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 bzero(&hwModel
, 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 _SCSerialize(CFPropertyListRef obj
, CFDataRef
*xml
, void **dataRef
, CFIndex
*dataLen
)
372 if ((xml
== NULL
) && ((dataRef
== NULL
) || (dataLen
== NULL
))) {
373 /* if not keeping track of allocated space */
377 myXml
= CFPropertyListCreateData(NULL
,
379 kCFPropertyListBinaryFormat_v1_0
,
383 SC_log(LOG_NOTICE
, "CFPropertyListCreateData() failed");
387 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
396 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
397 *dataRef
= (void *)CFDataGetBytePtr(myXml
);
398 *dataLen
= CFDataGetLength(myXml
);
401 mach_msg_type_number_t len
;
402 kern_return_t status
;
404 status
= vm_read(mach_task_self(),
405 (vm_address_t
)CFDataGetBytePtr(myXml
), // address
406 (vm_size_t
) CFDataGetLength(myXml
), // size
409 if (status
!= KERN_SUCCESS
) {
410 SC_log(LOG_NOTICE
, "vm_read() failed: %s", mach_error_string(status
));
426 _SCUnserialize(CFPropertyListRef
*obj
, CFDataRef xml
, void *dataRef
, CFIndex dataLen
)
428 CFErrorRef error
= NULL
;
431 kern_return_t status
;
433 xml
= CFDataCreateWithBytesNoCopy(NULL
, (void *)dataRef
, dataLen
, kCFAllocatorNull
);
434 *obj
= CFPropertyListCreateWithData(NULL
, xml
, kCFPropertyListImmutable
, NULL
, &error
);
437 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
438 if (status
!= KERN_SUCCESS
) {
439 SC_log(LOG_NOTICE
, "vm_deallocate() failed: %s", mach_error_string(status
));
440 /* non-fatal???, proceed */
443 *obj
= CFPropertyListCreateWithData(NULL
, xml
, kCFPropertyListImmutable
, NULL
, &error
);
448 SC_log(LOG_NOTICE
, "CFPropertyListCreateWithData() faled: %@", error
);
451 _SCErrorSet(kSCStatusFailed
);
460 _SCSerializeString(CFStringRef str
, CFDataRef
*data
, void **dataRef
, CFIndex
*dataLen
)
464 if (!isA_CFString(str
)) {
465 /* if not a CFString */
469 if ((data
== NULL
) && ((dataRef
== NULL
) || (dataLen
== NULL
))) {
470 /* if not keeping track of allocated space */
474 myData
= CFStringCreateExternalRepresentation(NULL
, str
, kCFStringEncodingUTF8
, 0);
475 if (myData
== NULL
) {
476 SC_log(LOG_NOTICE
, "CFStringCreateExternalRepresentation() failed");
480 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
489 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
490 *dataRef
= (void *)CFDataGetBytePtr(myData
);
491 *dataLen
= CFDataGetLength(myData
);
494 mach_msg_type_number_t len
;
495 kern_return_t status
;
497 *dataLen
= CFDataGetLength(myData
);
498 status
= vm_read(mach_task_self(),
499 (vm_address_t
)CFDataGetBytePtr(myData
), // address
503 if (status
!= KERN_SUCCESS
) {
504 SC_log(LOG_NOTICE
, "vm_read() failed: %s", mach_error_string(status
));
520 _SCUnserializeString(CFStringRef
*str
, CFDataRef utf8
, void *dataRef
, CFIndex dataLen
)
523 kern_return_t status
;
525 utf8
= CFDataCreateWithBytesNoCopy(NULL
, dataRef
, dataLen
, kCFAllocatorNull
);
526 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
529 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
530 if (status
!= KERN_SUCCESS
) {
531 SC_log(LOG_NOTICE
, "vm_deallocate() failed: %s", mach_error_string(status
));
532 /* non-fatal???, proceed */
535 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
539 SC_log(LOG_NOTICE
, "CFStringCreateFromExternalRepresentation() failed");
548 _SCSerializeData(CFDataRef data
, void **dataRef
, CFIndex
*dataLen
)
550 mach_msg_type_number_t len
;
551 kern_return_t status
;
553 if (!isA_CFData(data
)) {
554 /* if not a CFData */
558 *dataLen
= CFDataGetLength(data
);
559 status
= vm_read(mach_task_self(),
560 (vm_address_t
)CFDataGetBytePtr(data
), // address
564 if (status
!= KERN_SUCCESS
) {
565 SC_log(LOG_NOTICE
, "vm_read() failed: %s", mach_error_string(status
));
578 _SCUnserializeData(CFDataRef
*data
, void *dataRef
, CFIndex dataLen
)
580 kern_return_t status
;
582 *data
= CFDataCreate(NULL
, dataRef
, dataLen
);
583 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
584 if (status
!= KERN_SUCCESS
) {
585 SC_log(LOG_NOTICE
, "vm_deallocate() failed: %s", mach_error_string(status
));
586 _SCErrorSet(kSCStatusFailed
);
594 CF_RETURNS_RETAINED CFDictionaryRef
595 _SCSerializeMultiple(CFDictionaryRef dict
)
598 const void * keys_q
[N_QUICK
];
599 const void ** keys
= keys_q
;
601 CFDictionaryRef newDict
= NULL
;
602 const void * pLists_q
[N_QUICK
];
603 const void ** pLists
= pLists_q
;
604 const void * values_q
[N_QUICK
];
605 const void ** values
= values_q
;
607 nElements
= CFDictionaryGetCount(dict
);
609 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
610 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
611 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
612 pLists
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFDataRef
), 0);
614 bzero(pLists
, nElements
* sizeof(CFDataRef
));
616 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
617 for (i
= 0; i
< nElements
; i
++) {
619 if (!_SCSerialize((CFPropertyListRef
)values
[i
], (CFDataRef
*)&pLists
[i
], NULL
, NULL
)) {
625 newDict
= CFDictionaryCreate(NULL
,
629 &kCFTypeDictionaryKeyCallBacks
,
630 &kCFTypeDictionaryValueCallBacks
);
635 for (i
= 0; i
< nElements
; i
++) {
636 if (pLists
[i
] != NULL
) CFRelease((CFDataRef
)pLists
[i
]);
639 if (keys
!= keys_q
) {
640 CFAllocatorDeallocate(NULL
, keys
);
641 CFAllocatorDeallocate(NULL
, values
);
642 CFAllocatorDeallocate(NULL
, pLists
);
652 _SCUnserializeMultiple(CFDictionaryRef dict
)
654 const void * keys_q
[N_QUICK
];
655 const void ** keys
= keys_q
;
657 CFDictionaryRef newDict
= NULL
;
658 const void * pLists_q
[N_QUICK
];
659 const void ** pLists
= pLists_q
;
660 const void * values_q
[N_QUICK
];
661 const void ** values
= values_q
;
663 nElements
= CFDictionaryGetCount(dict
);
667 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
668 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
669 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
670 pLists
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
672 bzero(pLists
, nElements
* sizeof(CFTypeRef
));
674 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
675 for (i
= 0; i
< nElements
; i
++) {
676 if (!_SCUnserialize((CFPropertyListRef
*)&pLists
[i
], values
[i
], NULL
, 0)) {
682 newDict
= CFDictionaryCreate(NULL
,
686 &kCFTypeDictionaryKeyCallBacks
,
687 &kCFTypeDictionaryValueCallBacks
);
694 for (i
= 0; i
< nElements
; i
++) {
695 if (pLists
[i
]) CFRelease(pLists
[i
]);
698 if (keys
!= keys_q
) {
699 CFAllocatorDeallocate(NULL
, keys
);
700 CFAllocatorDeallocate(NULL
, values
);
701 CFAllocatorDeallocate(NULL
, pLists
);
713 _SCCreatePropertyListFromResource(CFURLRef url
)
715 CFDictionaryRef dict
= NULL
;
718 CFReadStreamRef readStream
;
719 CFNumberRef val
= NULL
;
721 if (!CFURLCopyResourcePropertyForKey(url
, kCFURLFileSizeKey
, &val
, NULL
) ||
723 // if size not available
724 SC_log(LOG_NOTICE
, "CFURLCopyResourcePropertyForKey() size not available: %@", url
);
728 ok
= CFNumberGetValue(val
, kCFNumberSInt64Type
, &fileLen
);
730 if (!ok
|| (fileLen
== 0)) {
731 // if empty or size too large
732 SC_log(LOG_INFO
, "_SCCreatePropertyListFromResource() improper size: %@", url
);
736 readStream
= CFReadStreamCreateWithFile(NULL
, url
);
737 if (readStream
!= NULL
) {
738 if (CFReadStreamOpen(readStream
)) {
742 buffer
= CFAllocatorAllocate(NULL
, (CFIndex
)fileLen
, 0);
743 dataLen
= CFReadStreamRead(readStream
, buffer
, (CFIndex
)fileLen
);
744 if (dataLen
== (CFIndex
)fileLen
) {
747 data
= CFDataCreateWithBytesNoCopy(NULL
, buffer
, (CFIndex
)fileLen
, kCFAllocatorNull
);
749 dict
= CFPropertyListCreateWithData(NULL
,
751 kCFPropertyListImmutable
,
757 CFAllocatorDeallocate(NULL
, buffer
);
758 CFReadStreamClose(readStream
);
760 CFRelease(readStream
);
768 #pragma mark CFRunLoop scheduling
771 __private_extern__
void
772 _SC_signalRunLoop(CFTypeRef obj
, CFRunLoopSourceRef rls
, CFArrayRef rlList
)
774 CFRunLoopRef rl
= NULL
;
775 CFRunLoopRef rl1
= NULL
;
777 CFIndex n
= CFArrayGetCount(rlList
);
783 /* get first runLoop for this object */
784 for (i
= 0; i
< n
; i
+= 3) {
785 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
789 rl1
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
794 /* if not scheduled */
798 /* check if we have another runLoop for this object */
800 for (i
= i
+3; i
< n
; i
+= 3) {
803 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
807 rl2
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
808 if (!CFEqual(rl1
, rl2
)) {
809 /* we've got more than one runLoop */
816 /* if we only have one runLoop */
821 /* more than one different runLoop, so we must pick one */
822 for (i
= 0; i
< n
; i
+=3) {
825 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
829 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
830 rlMode
= CFRunLoopCopyCurrentMode(rl
);
831 if (rlMode
!= NULL
) {
834 waiting
= (CFRunLoopIsWaiting(rl
) && CFRunLoopContainsSource(rl
, rls
, rlMode
));
837 /* we've found a runLoop that's "ready" */
844 /* didn't choose one above, so choose first */
845 CFRunLoopWakeUp(rl1
);
850 __private_extern__ Boolean
851 _SC_isScheduled(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
854 CFIndex n
= CFArrayGetCount(rlList
);
856 for (i
= 0; i
< n
; i
+= 3) {
857 if ((obj
!= NULL
) && !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
860 if ((runLoop
!= NULL
) && !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
863 if ((runLoopMode
!= NULL
) && !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
873 __private_extern__
void
874 _SC_schedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
876 CFArrayAppendValue(rlList
, obj
);
877 CFArrayAppendValue(rlList
, runLoop
);
878 CFArrayAppendValue(rlList
, runLoopMode
);
884 __private_extern__ Boolean
885 _SC_unschedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
, Boolean all
)
888 Boolean found
= FALSE
;
889 CFIndex n
= CFArrayGetCount(rlList
);
892 if ((obj
!= NULL
) && !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
896 if ((runLoop
!= NULL
) && !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
900 if ((runLoopMode
!= NULL
) && !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
907 CFArrayRemoveValueAtIndex(rlList
, i
+ 2);
908 CFArrayRemoveValueAtIndex(rlList
, i
+ 1);
909 CFArrayRemoveValueAtIndex(rlList
, i
);
926 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
927 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
929 #define SUFFIX_SYM "~sym"
930 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
932 #define SUFFIX_DST "~dst"
936 _SC_CFBundleGet(void)
938 static CFBundleRef bundle
= NULL
;
943 if (bundle
!= NULL
) {
947 bundle
= CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID
);
948 if (bundle
!= NULL
) {
949 CFRetain(bundle
); // we want to hold a reference to the bundle
952 SC_log(LOG_NOTICE
, "could not get CFBundle for \"%@\". Trying harder...",
953 SYSTEMCONFIGURATION_BUNDLE_ID
);
956 // if appropriate (e.g. when debugging), try a bit harder
958 env
= getenv("DYLD_FRAMEWORK_PATH");
959 len
= (env
!= NULL
) ? strlen(env
) : 0;
961 if (len
> 0) { /* We are debugging */
963 // trim any trailing slashes
965 if (env
[len
- 1] != '/') {
971 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst"
972 if ((len
> SUFFIX_SYM_LEN
) &&
973 (strncmp(&env
[len
- SUFFIX_SYM_LEN
], SUFFIX_SYM
, SUFFIX_SYM_LEN
) == 0) &&
974 ((len
+ SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN
) < MAXPATHLEN
)) {
975 char path
[MAXPATHLEN
];
977 strlcpy(path
, env
, sizeof(path
));
978 strlcpy(&path
[len
- SUFFIX_SYM_LEN
], SUFFIX_DST
, sizeof(path
) - (len
- SUFFIX_SYM_LEN
));
979 strlcat(&path
[len
], SYSTEMCONFIGURATION_FRAMEWORK_PATH
, sizeof(path
) - len
);
981 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
983 len
+ SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN
,
985 bundle
= CFBundleCreate(NULL
, url
);
990 if (bundle
== NULL
) { /* Try a more "direct" route to get the bundle */
992 url
= CFURLCreateWithFileSystemPath(NULL
,
993 CFSTR(SYSTEMCONFIGURATION_FRAMEWORK_PATH
),
994 kCFURLPOSIXPathStyle
,
997 bundle
= CFBundleCreate(NULL
, url
);
1001 if (bundle
== NULL
) {
1002 SC_log(LOG_ERR
, "could not get CFBundle for \"%@\"", SYSTEMCONFIGURATION_BUNDLE_ID
);
1011 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle
, CFStringRef key
, CFStringRef value
, CFStringRef tableName
)
1013 CFURLRef resourcesURL
;
1014 CFStringRef str
= NULL
;
1015 CFDictionaryRef table
= NULL
;
1018 if ((tableName
== NULL
) || CFEqual(tableName
, CFSTR(""))) {
1019 tableName
= CFSTR("Localizable");
1023 * First, try getting the requested string using a manually constructed
1024 * URL to <bundle>/Resources/English.lproj/<tableName>.strings. Do this
1025 * because CFBundleCopyResourceURLForLocalization() uses CFPreferences
1026 * to get the preferred localizations, CFPreferences talks to
1027 * OpenDirectory, and OpenDirectory tries to obtain the platform UUID.
1028 * On machines where the platform UUID is set by InterfaceNamer, a
1029 * deadlock can occur if InterfaceNamer calls
1030 * CFBundleCopyResourceURLForLocalization() before setting the
1031 * platform UUID in the kernel.
1033 resourcesURL
= CFBundleCopyResourcesDirectoryURL(bundle
);
1034 if (resourcesURL
!= NULL
) {
1036 CFStringRef fileName
;
1038 en_lproj
= CFURLCreateCopyAppendingPathComponent(NULL
,
1040 CFSTR("English.lproj"),
1042 fileName
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@.strings"), tableName
);
1043 url
= CFURLCreateCopyAppendingPathComponent(NULL
, en_lproj
, fileName
, FALSE
);
1044 CFRelease(en_lproj
);
1045 CFRelease(fileName
);
1046 CFRelease(resourcesURL
);
1048 table
= _SCCreatePropertyListFromResource(url
);
1052 if (table
== NULL
) {
1053 url
= CFBundleCopyResourceURLForLocalization(bundle
,
1059 table
= _SCCreatePropertyListFromResource(url
);
1062 SC_log(LOG_ERR
, "failed to get resource url: {bundle:%@, table: %@}", bundle
, tableName
);
1066 if (table
!= NULL
) {
1067 if (isA_CFDictionary(table
)) {
1068 str
= CFDictionaryGetValue(table
, key
);
1078 str
= CFRetain(value
);
1086 #pragma mark Mach port / CFMachPort management
1090 _SC_CFMachPortCreateWithPort(const char *portDescription
,
1091 mach_port_t portNum
,
1092 CFMachPortCallBack callout
,
1093 CFMachPortContext
*context
)
1096 Boolean shouldFree
= FALSE
;
1098 port
= CFMachPortCreateWithPort(NULL
, portNum
, callout
, context
, &shouldFree
);
1099 if ((port
== NULL
) || shouldFree
) {
1101 char *crash_info
= NULL
;
1103 SC_log(LOG_NOTICE
, "%s: CFMachPortCreateWithPort() failed , port = %p",
1105 (void *)(uintptr_t)portNum
);
1107 err
= CFStringCreateWithFormat(NULL
, NULL
,
1108 CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"),
1109 portDescription
, port
);
1111 err
= CFStringCreateWithFormat(NULL
, NULL
,
1112 CFSTR("%s: CFMachPortCreateWithPort returned NULL"),
1115 crash_info
= _SC_cfstring_to_cstring(err
, NULL
, 0, kCFStringEncodingASCII
);
1116 if (err
!= NULL
) CFRelease(err
);
1119 err
= CFStringCreateWithFormat(NULL
,
1121 CFSTR("A recycled mach_port has been detected by \"%s\"."),
1123 _SC_crash(crash_info
, CFSTR("CFMachPort error"), err
);
1124 CFAllocatorDeallocate(NULL
, crash_info
);
1125 if (err
!= NULL
) CFRelease(err
);
1133 #pragma mark DOS encoding/codepage
1136 #if !TARGET_OS_IPHONE
1138 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding
,
1140 CFStringEncoding
*dosEncoding
,
1141 UInt32
*dosCodepage
)
1143 switch (macEncoding
) {
1144 case kCFStringEncodingMacRoman
:
1145 if (macRegion
!= 0) /* anything non-zero is not US */
1146 *dosEncoding
= kCFStringEncodingDOSLatin1
;
1147 else /* US region */
1148 *dosEncoding
= kCFStringEncodingDOSLatinUS
;
1151 case kCFStringEncodingMacJapanese
:
1152 *dosEncoding
= kCFStringEncodingDOSJapanese
;
1155 case kCFStringEncodingMacChineseTrad
:
1156 *dosEncoding
= kCFStringEncodingDOSChineseTrad
;
1159 case kCFStringEncodingMacKorean
:
1160 *dosEncoding
= kCFStringEncodingDOSKorean
;
1163 case kCFStringEncodingMacArabic
:
1164 *dosEncoding
= kCFStringEncodingDOSArabic
;
1167 case kCFStringEncodingMacHebrew
:
1168 *dosEncoding
= kCFStringEncodingDOSHebrew
;
1171 case kCFStringEncodingMacGreek
:
1172 *dosEncoding
= kCFStringEncodingDOSGreek
;
1175 case kCFStringEncodingMacCyrillic
:
1176 *dosEncoding
= kCFStringEncodingDOSCyrillic
;
1179 case kCFStringEncodingMacThai
:
1180 *dosEncoding
= kCFStringEncodingDOSThai
;
1183 case kCFStringEncodingMacChineseSimp
:
1184 *dosEncoding
= kCFStringEncodingDOSChineseSimplif
;
1187 case kCFStringEncodingMacCentralEurRoman
:
1188 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1191 case kCFStringEncodingMacTurkish
:
1192 *dosEncoding
= kCFStringEncodingDOSTurkish
;
1195 case kCFStringEncodingMacCroatian
:
1196 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1199 case kCFStringEncodingMacIcelandic
:
1200 *dosEncoding
= kCFStringEncodingDOSIcelandic
;
1203 case kCFStringEncodingMacRomanian
:
1204 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1207 case kCFStringEncodingMacFarsi
:
1208 *dosEncoding
= kCFStringEncodingDOSArabic
;
1211 case kCFStringEncodingMacUkrainian
:
1212 *dosEncoding
= kCFStringEncodingDOSCyrillic
;
1216 *dosEncoding
= kCFStringEncodingDOSLatin1
;
1220 *dosCodepage
= CFStringConvertEncodingToWindowsCodepage(*dosEncoding
);
1223 #endif // !TARGET_OS_IPHONE
1227 #pragma mark Debugging
1231 * print status of in-use mach ports
1234 _SC_logMachPortStatus(void)
1236 kern_return_t status
;
1237 mach_port_name_array_t ports
;
1238 mach_port_type_array_t types
;
1239 mach_msg_type_number_t pi
, pn
, tn
;
1240 CFMutableStringRef str
;
1242 SC_log(LOG_DEBUG
, "----------");
1244 /* report on ALL mach ports associated with this task */
1245 status
= mach_port_names(mach_task_self(), &ports
, &pn
, &types
, &tn
);
1246 if (status
== MACH_MSG_SUCCESS
) {
1247 str
= CFStringCreateMutable(NULL
, 0);
1248 for (pi
= 0; pi
< pn
; pi
++) {
1249 char rights
[16], *rp
= &rights
[0];
1251 if (types
[pi
] != MACH_PORT_TYPE_NONE
) {
1254 if (types
[pi
] & MACH_PORT_TYPE_SEND
)
1256 if (types
[pi
] & MACH_PORT_TYPE_RECEIVE
)
1258 if (types
[pi
] & MACH_PORT_TYPE_SEND_ONCE
)
1260 if (types
[pi
] & MACH_PORT_TYPE_PORT_SET
)
1262 if (types
[pi
] & MACH_PORT_TYPE_DEAD_NAME
)
1267 CFStringAppendFormat(str
, NULL
, CFSTR(" %d%s"), ports
[pi
], rights
);
1269 SC_log(LOG_DEBUG
, "Task ports (n=%d):%@", pn
, str
);
1278 _SC_logMachPortReferences(const char *str
, mach_port_t port
)
1280 const char *blanks
= " ";
1282 mach_port_type_t pt
;
1283 mach_port_status_t recv_status
= { 0 };
1284 mach_port_urefs_t refs_send
= 0;
1285 mach_port_urefs_t refs_recv
= 0;
1286 mach_port_urefs_t refs_once
= 0;
1287 mach_port_urefs_t refs_pset
= 0;
1288 mach_port_urefs_t refs_dead
= 0;
1289 kern_return_t status
;
1293 static int is_configd
= -1;
1295 if (is_configd
== -1) {
1296 is_configd
= (strcmp(getprogname(), _SC_SERVER_PROG
) == 0);
1298 if (is_configd
== 1) {
1299 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1301 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1305 // add provided string
1306 strlcat(buf
, str
, sizeof(buf
));
1309 strlcat(buf
, blanks
, sizeof(buf
));
1310 if (strcmp(&buf
[sizeof(buf
) - 3], " ") == 0) {
1311 buf
[sizeof(buf
) - 3] = ':';
1315 status
= mach_port_type(mach_task_self(), port
, &pt
);
1316 if (status
!= KERN_SUCCESS
) {
1317 SC_log(LOG_DEBUG
, "%smach_port_type(..., 0x%x): %s",
1320 mach_error_string(status
));
1324 if ((pt
& MACH_PORT_TYPE_SEND
) != 0) {
1325 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND
, &refs_send
);
1326 if (status
!= KERN_SUCCESS
) {
1327 SC_log(LOG_DEBUG
, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s",
1330 mach_error_string(status
));
1335 if ((pt
& MACH_PORT_TYPE_RECEIVE
) != 0) {
1336 mach_msg_type_number_t count
;
1338 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, &refs_recv
);
1339 if (status
!= KERN_SUCCESS
) {
1340 SC_log(LOG_DEBUG
, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s",
1343 mach_error_string(status
));
1347 count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1348 status
= mach_port_get_attributes(mach_task_self(),
1350 MACH_PORT_RECEIVE_STATUS
,
1351 (mach_port_info_t
)&recv_status
,
1353 if (status
!= KERN_SUCCESS
) {
1354 SC_log(LOG_DEBUG
, "%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s",
1357 mach_error_string(status
));
1362 if ((pt
& MACH_PORT_TYPE_SEND_ONCE
) != 0) {
1363 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND_ONCE
, &refs_once
);
1364 if (status
!= KERN_SUCCESS
) {
1365 SC_log(LOG_DEBUG
, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s",
1368 mach_error_string(status
));
1373 if ((pt
& MACH_PORT_TYPE_PORT_SET
) != 0) {
1374 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_PORT_SET
, &refs_pset
);
1375 if (status
!= KERN_SUCCESS
) {
1376 SC_log(LOG_DEBUG
, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s",
1379 mach_error_string(status
));
1384 if ((pt
& MACH_PORT_TYPE_DEAD_NAME
) != 0) {
1385 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_DEAD_NAME
, &refs_dead
);
1386 if (status
!= KERN_SUCCESS
) {
1387 SC_log(LOG_DEBUG
, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s",
1390 mach_error_string(status
));
1395 SC_log(LOG_DEBUG
, "%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s",
1404 recv_status
.mps_nsrequest
? ", no more senders" : "",
1405 ((pt
& MACH_PORT_TYPE_DEAD_NAME
) != 0) ? ", dead name request" : "");
1417 CFMutableStringRef trace
;
1419 n
= backtrace(stack
, sizeof(stack
)/sizeof(stack
[0]));
1421 SC_log(LOG_NOTICE
, "backtrace() failed: %s", strerror(errno
));
1425 trace
= CFStringCreateMutable(NULL
, 0);
1427 symbols
= backtrace_symbols(stack
, n
);
1428 if (symbols
!= NULL
) {
1431 for (i
= 0; i
< n
; i
++) {
1432 CFStringAppendFormat(trace
, NULL
, CFSTR("%s\n"), symbols
[i
]);
1442 /* CrashReporter info */
1443 #if !TARGET_OS_IPHONE
1444 #include <CrashReporterClient.h>
1445 #else // !TARGET_OS_IPHONE
1446 const char *__crashreporter_info__
= NULL
;
1447 asm(".desc ___crashreporter_info__, 0x10");
1448 #endif // !TARGET_OS_IPHONE
1452 _SC_SimulateCrash(const char *crash_info
, CFStringRef notifyHeader
, CFStringRef notifyMessage
)
1456 #if !TARGET_OS_SIMULATOR
1457 static bool (*dyfunc_SimulateCrash
)(pid_t
, mach_exception_data_type_t
, CFStringRef
) = NULL
;
1458 static void *image
= NULL
;
1459 static dispatch_once_t once
;
1461 dispatch_once(&once
, ^{
1462 image
= _SC_dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport");
1463 if (image
!= NULL
) {
1464 dyfunc_SimulateCrash
= dlsym(image
, "SimulateCrash");
1468 if (dyfunc_SimulateCrash
!= NULL
) {
1471 str
= CFStringCreateWithCString(NULL
, crash_info
, kCFStringEncodingUTF8
);
1472 ok
= dyfunc_SimulateCrash(getpid(), 0xbad0005cull
, str
);
1476 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1477 if (ok
&& (notifyHeader
!= NULL
) && (notifyMessage
!= NULL
)) {
1478 static Boolean warned
= FALSE
;
1481 CFStringRef displayMessage
;
1483 displayMessage
= CFStringCreateWithFormat(NULL
,
1485 CFSTR("%@\n\nPlease collect the crash report and file a Radar."),
1487 CFUserNotificationDisplayNotice(0,
1488 kCFUserNotificationStopAlertLevel
,
1495 CFRelease(displayMessage
);
1499 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1500 #endif // !TARGET_OS_SIMULATOR
1507 _SC_crash(const char *crash_info
, CFStringRef notifyHeader
, CFStringRef notifyMessage
)
1511 if (crash_info
!= NULL
) {
1512 #if !TARGET_OS_IPHONE
1513 CRSetCrashLogMessage(crash_info
);
1514 #else // !TARGET_OS_IPHONE
1515 __crashreporter_info__
= crash_info
;
1516 #endif // !TARGET_OS_IPHONE
1518 SC_log(LOG_NOTICE
, "%s", crash_info
);
1521 if (_SC_isAppleInternal()) {
1522 // simulate a crash report
1523 ok
= _SC_SimulateCrash(crash_info
, notifyHeader
, notifyMessage
);
1524 #ifndef DO_NOT_CRASH
1526 // if we could not simulate a crash report, crash for real
1529 #endif // DO_NOT_CRASH
1532 #if !TARGET_OS_IPHONE
1533 CRSetCrashLogMessage(NULL
);
1534 #else // !TARGET_OS_IPHONE
1535 __crashreporter_info__
= NULL
;
1536 #endif // !TARGET_OS_IPHONE
1542 _SC_getconninfo(int socket
, struct sockaddr_storage
*src_addr
, struct sockaddr_storage
*dest_addr
, int *if_index
, uint32_t *flags
)
1544 struct so_cinforeq request
;
1546 memset(&request
, 0, sizeof(request
));
1548 if (src_addr
!= NULL
) {
1549 memset(src_addr
, 0, sizeof(*src_addr
));
1550 request
.scir_src
= (struct sockaddr
*)src_addr
;
1551 request
.scir_src_len
= sizeof(*src_addr
);
1554 if (dest_addr
!= NULL
) {
1555 memset(dest_addr
, 0, sizeof(*dest_addr
));
1556 request
.scir_dst
= (struct sockaddr
*)dest_addr
;
1557 request
.scir_dst_len
= sizeof(*dest_addr
);
1560 if (ioctl(socket
, SIOCGCONNINFO
, &request
) != 0) {
1561 SC_log(LOG_NOTICE
, "SIOCGCONNINFO failed: %s", strerror(errno
));
1565 if (if_index
!= NULL
) {
1567 *if_index
= request
.scir_ifindex
;
1570 if (flags
!= NULL
) {
1572 *flags
= request
.scir_flags
;