2 * Copyright (c) 2000-2014 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 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCValidation.h>
39 #include <SystemConfiguration/SCPrivate.h>
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
46 #include <net/if_dl.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
50 #include <dispatch/dispatch.h>
52 #include <mach/mach.h>
53 #include <mach/notify.h>
54 #include <mach/mach_error.h>
62 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
63 #include <CoreFoundation/CFUserNotification.h>
64 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
70 #pragma mark Miscellaneous
74 _SC_cfstring_to_cstring(CFStringRef cfstr
, char *buf
, CFIndex bufLen
, CFStringEncoding encoding
)
83 len
= CFStringGetLength(cfstr
);
85 /* how much buffer space will we really need? */
86 converted
= CFStringGetBytes(cfstr
,
94 if (converted
< len
) {
95 /* if full string could not be converted */
103 if (bufLen
< (last
+ 1)) {
104 /* if the size of the provided buffer is too small */
109 /* allocate a buffer */
111 buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
117 (void)CFStringGetBytes(cfstr
,
132 _SC_sockaddr_to_string(const struct sockaddr
*address
, char *buf
, size_t bufLen
)
135 const struct sockaddr
*sa
;
136 const struct sockaddr_in
*sin
;
137 const struct sockaddr_in6
*sin6
;
138 const struct sockaddr_dl
*sdl
;
144 switch (address
->sa_family
) {
146 (void)inet_ntop(addr
.sin
->sin_family
,
152 (void)inet_ntop(addr
.sin6
->sin6_family
,
153 &addr
.sin6
->sin6_addr
,
156 if (addr
.sin6
->sin6_scope_id
!= 0) {
160 if ((n
+IF_NAMESIZE
+1) <= (int)bufLen
) {
162 if_indextoname(addr
.sin6
->sin6_scope_id
, &buf
[n
]);
168 snprintf(buf
, bufLen
, "unexpected address family %d", address
->sa_family
);
177 _SC_string_to_sockaddr(const char *str
, sa_family_t af
, void *buf
, size_t bufLen
)
182 struct sockaddr_in
*sin
;
183 struct sockaddr_in6
*sin6
;
187 bufLen
= sizeof(struct sockaddr_storage
);
188 addr
.buf
= CFAllocatorAllocate(NULL
, bufLen
, 0);
193 bzero(addr
.buf
, bufLen
);
194 if (((af
== AF_UNSPEC
) || (af
== AF_INET
)) &&
195 (bufLen
>= sizeof(struct sockaddr_in
)) &&
196 inet_aton(str
, &addr
.sin
->sin_addr
) == 1) {
198 addr
.sin
->sin_len
= sizeof(struct sockaddr_in
);
199 addr
.sin
->sin_family
= AF_INET
;
200 } else if (((af
== AF_UNSPEC
) || (af
== AF_INET6
)) &&
201 (bufLen
>= sizeof(struct sockaddr_in6
)) &&
202 inet_pton(AF_INET6
, str
, &addr
.sin6
->sin6_addr
) == 1) {
206 addr
.sin6
->sin6_len
= sizeof(struct sockaddr_in6
);
207 addr
.sin6
->sin6_family
= AF_INET6
;
209 p
= strchr(buf
, '%');
211 addr
.sin6
->sin6_scope_id
= if_nametoindex(p
+ 1);
214 if (IN6_IS_ADDR_LINKLOCAL(&addr
.sin6
->sin6_addr
) ||
215 IN6_IS_ADDR_MC_LINKLOCAL(&addr
.sin6
->sin6_addr
)) {
218 if_index
= ntohs(addr
.sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1]);
219 addr
.sin6
->sin6_addr
.__u6_addr
.__u6_addr16
[1] = 0;
220 if (addr
.sin6
->sin6_scope_id
== 0) {
221 // use the scope id that was embedded in the [link local] IPv6 address
222 addr
.sin6
->sin6_scope_id
= if_index
;
226 if (addr
.buf
!= buf
) {
227 CFAllocatorDeallocate(NULL
, addr
.buf
);
237 _SC_sendMachMessage(mach_port_t port
, mach_msg_id_t msg_id
)
239 mach_msg_empty_send_t msg
;
240 mach_msg_option_t options
;
241 kern_return_t status
;
243 msg
.header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
244 msg
.header
.msgh_size
= sizeof(msg
);
245 msg
.header
.msgh_remote_port
= port
;
246 msg
.header
.msgh_local_port
= MACH_PORT_NULL
;
247 msg
.header
.msgh_id
= msg_id
;
248 options
= MACH_SEND_TIMEOUT
;
249 status
= mach_msg(&msg
.header
, /* msg */
250 MACH_SEND_MSG
|options
, /* options */
251 msg
.header
.msgh_size
, /* send_size */
253 MACH_PORT_NULL
, /* rcv_name */
255 MACH_PORT_NULL
); /* notify */
256 if (status
!= MACH_MSG_SUCCESS
) {
257 mach_msg_destroy(&msg
.header
);
265 _SC_trimDomain(CFStringRef domain
)
269 if (!isA_CFString(domain
)) {
273 // remove any leading/trailing dots
274 length
= CFStringGetLength(domain
);
276 (CFStringFindWithOptions(domain
,
281 CFStringFindWithOptions(domain
,
283 CFRangeMake(0, length
),
284 kCFCompareAnchored
|kCFCompareBackwards
,
286 CFMutableStringRef trimmed
;
288 trimmed
= CFStringCreateMutableCopy(NULL
, 0, domain
);
289 CFStringTrim(trimmed
, CFSTR("."));
290 domain
= (CFStringRef
)trimmed
;
291 length
= CFStringGetLength(domain
);
306 _SC_hw_model(Boolean trim
)
308 static CFStringRef model
= NULL
;
309 static CFStringRef model_trimmed
= NULL
;
310 static dispatch_once_t once
;
312 dispatch_once(&once
, ^{
315 int mib
[] = { CTL_HW
, HW_MODEL
};
316 size_t n
= sizeof(hwModel
);
320 bzero(&hwModel
, sizeof(hwModel
));
321 ret
= sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), &hwModel
, &n
, NULL
, 0);
323 SCLog(TRUE
, LOG_ERR
, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno
));
326 hwModel
[sizeof(hwModel
) - 1] = '\0';
327 model
= CFStringCreateWithCString(NULL
, hwModel
, kCFStringEncodingASCII
);
329 // and the "trimmed" name
330 // ... remove everything after (and including) a comma
331 // ... and then any trailing digits
332 cp
= index(hwModel
, ',');
336 n
= strlen(hwModel
) - 1;
338 if (!isdigit(hwModel
[n
])) {
343 model_trimmed
= CFStringCreateWithCString(NULL
, hwModel
, kCFStringEncodingASCII
);
346 return trim
? model_trimmed
: model
;
351 #pragma mark Serialization
355 _SCSerialize(CFPropertyListRef obj
, CFDataRef
*xml
, void **dataRef
, CFIndex
*dataLen
)
359 if ((xml
== NULL
) && ((dataRef
== NULL
) || (dataLen
== NULL
))) {
360 /* if not keeping track of allocated space */
364 myXml
= CFPropertyListCreateData(NULL
,
366 kCFPropertyListBinaryFormat_v1_0
,
370 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerialize() failed"));
374 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
383 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
384 *dataRef
= (void *)CFDataGetBytePtr(myXml
);
385 *dataLen
= CFDataGetLength(myXml
);
388 mach_msg_type_number_t len
;
389 kern_return_t status
;
391 status
= vm_read(mach_task_self(),
392 (vm_address_t
)CFDataGetBytePtr(myXml
), // address
393 (vm_size_t
) CFDataGetLength(myXml
), // size
396 if (status
!= KERN_SUCCESS
) {
397 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerialize(): %s"), mach_error_string(status
));
413 _SCUnserialize(CFPropertyListRef
*obj
, CFDataRef xml
, void *dataRef
, CFIndex dataLen
)
415 CFErrorRef error
= NULL
;
418 kern_return_t status
;
420 xml
= CFDataCreateWithBytesNoCopy(NULL
, (void *)dataRef
, dataLen
, kCFAllocatorNull
);
421 *obj
= CFPropertyListCreateWithData(NULL
, xml
, kCFPropertyListImmutable
, NULL
, &error
);
424 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
425 if (status
!= KERN_SUCCESS
) {
426 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("_SCUnserialize(): %s"), mach_error_string(status
));
427 /* non-fatal???, proceed */
430 *obj
= CFPropertyListCreateWithData(NULL
, xml
, kCFPropertyListImmutable
, NULL
, &error
);
435 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCUnserialize(): %@"), error
);
438 _SCErrorSet(kSCStatusFailed
);
447 _SCSerializeString(CFStringRef str
, CFDataRef
*data
, void **dataRef
, CFIndex
*dataLen
)
451 if (!isA_CFString(str
)) {
452 /* if not a CFString */
456 if ((data
== NULL
) && ((dataRef
== NULL
) || (dataLen
== NULL
))) {
457 /* if not keeping track of allocated space */
461 myData
= CFStringCreateExternalRepresentation(NULL
, str
, kCFStringEncodingUTF8
, 0);
462 if (myData
== NULL
) {
463 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerializeString() failed"));
467 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
476 if ((dataRef
!= NULL
) && (dataLen
!= NULL
)) {
477 *dataRef
= (void *)CFDataGetBytePtr(myData
);
478 *dataLen
= CFDataGetLength(myData
);
481 mach_msg_type_number_t len
;
482 kern_return_t status
;
484 *dataLen
= CFDataGetLength(myData
);
485 status
= vm_read(mach_task_self(),
486 (vm_address_t
)CFDataGetBytePtr(myData
), // address
490 if (status
!= KERN_SUCCESS
) {
491 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerializeString(): %s"), mach_error_string(status
));
507 _SCUnserializeString(CFStringRef
*str
, CFDataRef utf8
, void *dataRef
, CFIndex dataLen
)
510 kern_return_t status
;
512 utf8
= CFDataCreateWithBytesNoCopy(NULL
, dataRef
, dataLen
, kCFAllocatorNull
);
513 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
516 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
517 if (status
!= KERN_SUCCESS
) {
518 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("_SCUnserializeString(): %s"), mach_error_string(status
));
519 /* non-fatal???, proceed */
522 *str
= CFStringCreateFromExternalRepresentation(NULL
, utf8
, kCFStringEncodingUTF8
);
526 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCUnserializeString() failed"));
535 _SCSerializeData(CFDataRef data
, void **dataRef
, CFIndex
*dataLen
)
537 mach_msg_type_number_t len
;
538 kern_return_t status
;
540 if (!isA_CFData(data
)) {
541 /* if not a CFData */
545 *dataLen
= CFDataGetLength(data
);
546 status
= vm_read(mach_task_self(),
547 (vm_address_t
)CFDataGetBytePtr(data
), // address
551 if (status
!= KERN_SUCCESS
) {
552 SCLog(TRUE
, LOG_ERR
, CFSTR("_SCSerializeData(): %s"), mach_error_string(status
));
565 _SCUnserializeData(CFDataRef
*data
, void *dataRef
, CFIndex dataLen
)
567 kern_return_t status
;
569 *data
= CFDataCreate(NULL
, dataRef
, dataLen
);
570 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
571 if (status
!= KERN_SUCCESS
) {
572 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("_SCUnserializeData(): %s"), mach_error_string(status
));
573 _SCErrorSet(kSCStatusFailed
);
581 CF_RETURNS_RETAINED CFDictionaryRef
582 _SCSerializeMultiple(CFDictionaryRef dict
)
585 const void * keys_q
[N_QUICK
];
586 const void ** keys
= keys_q
;
588 CFDictionaryRef newDict
= NULL
;
589 const void * pLists_q
[N_QUICK
];
590 const void ** pLists
= pLists_q
;
591 const void * values_q
[N_QUICK
];
592 const void ** values
= values_q
;
594 nElements
= CFDictionaryGetCount(dict
);
596 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
597 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
598 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
599 pLists
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFDataRef
), 0);
601 bzero(pLists
, nElements
* sizeof(CFDataRef
));
603 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
604 for (i
= 0; i
< nElements
; i
++) {
606 if (!_SCSerialize((CFPropertyListRef
)values
[i
], (CFDataRef
*)&pLists
[i
], NULL
, NULL
)) {
612 newDict
= CFDictionaryCreate(NULL
,
616 &kCFTypeDictionaryKeyCallBacks
,
617 &kCFTypeDictionaryValueCallBacks
);
622 for (i
= 0; i
< nElements
; i
++) {
623 if (pLists
[i
] != NULL
) CFRelease((CFDataRef
)pLists
[i
]);
626 if (keys
!= keys_q
) {
627 CFAllocatorDeallocate(NULL
, keys
);
628 CFAllocatorDeallocate(NULL
, values
);
629 CFAllocatorDeallocate(NULL
, pLists
);
639 _SCUnserializeMultiple(CFDictionaryRef dict
)
641 const void * keys_q
[N_QUICK
];
642 const void ** keys
= keys_q
;
644 CFDictionaryRef newDict
= NULL
;
645 const void * pLists_q
[N_QUICK
];
646 const void ** pLists
= pLists_q
;
647 const void * values_q
[N_QUICK
];
648 const void ** values
= values_q
;
650 nElements
= CFDictionaryGetCount(dict
);
654 if (nElements
> (CFIndex
)(sizeof(keys_q
) / sizeof(CFTypeRef
))) {
655 keys
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
656 values
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
657 pLists
= CFAllocatorAllocate(NULL
, nElements
* sizeof(CFTypeRef
), 0);
659 bzero(pLists
, nElements
* sizeof(CFTypeRef
));
661 CFDictionaryGetKeysAndValues(dict
, keys
, values
);
662 for (i
= 0; i
< nElements
; i
++) {
663 if (!_SCUnserialize((CFPropertyListRef
*)&pLists
[i
], values
[i
], NULL
, 0)) {
669 newDict
= CFDictionaryCreate(NULL
,
673 &kCFTypeDictionaryKeyCallBacks
,
674 &kCFTypeDictionaryValueCallBacks
);
681 for (i
= 0; i
< nElements
; i
++) {
682 if (pLists
[i
]) CFRelease(pLists
[i
]);
685 if (keys
!= keys_q
) {
686 CFAllocatorDeallocate(NULL
, keys
);
687 CFAllocatorDeallocate(NULL
, values
);
688 CFAllocatorDeallocate(NULL
, pLists
);
697 #pragma mark CFRunLoop scheduling
700 __private_extern__
void
701 _SC_signalRunLoop(CFTypeRef obj
, CFRunLoopSourceRef rls
, CFArrayRef rlList
)
703 CFRunLoopRef rl
= NULL
;
704 CFRunLoopRef rl1
= NULL
;
706 CFIndex n
= CFArrayGetCount(rlList
);
712 /* get first runLoop for this object */
713 for (i
= 0; i
< n
; i
+= 3) {
714 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
718 rl1
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
723 /* if not scheduled */
727 /* check if we have another runLoop for this object */
729 for (i
= i
+3; i
< n
; i
+= 3) {
732 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
736 rl2
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
737 if (!CFEqual(rl1
, rl2
)) {
738 /* we've got more than one runLoop */
745 /* if we only have one runLoop */
750 /* more than one different runLoop, so we must pick one */
751 for (i
= 0; i
< n
; i
+=3) {
754 if (!CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
758 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlList
, i
+1);
759 rlMode
= CFRunLoopCopyCurrentMode(rl
);
760 if (rlMode
!= NULL
) {
763 waiting
= (CFRunLoopIsWaiting(rl
) && CFRunLoopContainsSource(rl
, rls
, rlMode
));
766 /* we've found a runLoop that's "ready" */
773 /* didn't choose one above, so choose first */
774 CFRunLoopWakeUp(rl1
);
779 __private_extern__ Boolean
780 _SC_isScheduled(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
783 CFIndex n
= CFArrayGetCount(rlList
);
785 for (i
= 0; i
< n
; i
+= 3) {
786 if ((obj
!= NULL
) && !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
789 if ((runLoop
!= NULL
) && !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
792 if ((runLoopMode
!= NULL
) && !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
802 __private_extern__
void
803 _SC_schedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
)
805 CFArrayAppendValue(rlList
, obj
);
806 CFArrayAppendValue(rlList
, runLoop
);
807 CFArrayAppendValue(rlList
, runLoopMode
);
813 __private_extern__ Boolean
814 _SC_unschedule(CFTypeRef obj
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
, CFMutableArrayRef rlList
, Boolean all
)
817 Boolean found
= FALSE
;
818 CFIndex n
= CFArrayGetCount(rlList
);
821 if ((obj
!= NULL
) && !CFEqual(obj
, CFArrayGetValueAtIndex(rlList
, i
))) {
825 if ((runLoop
!= NULL
) && !CFEqual(runLoop
, CFArrayGetValueAtIndex(rlList
, i
+1))) {
829 if ((runLoopMode
!= NULL
) && !CFEqual(runLoopMode
, CFArrayGetValueAtIndex(rlList
, i
+2))) {
836 CFArrayRemoveValueAtIndex(rlList
, i
+ 2);
837 CFArrayRemoveValueAtIndex(rlList
, i
+ 1);
838 CFArrayRemoveValueAtIndex(rlList
, i
);
855 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
856 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH "/System/Library/Frameworks/SystemConfiguration.framework"
857 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
859 #define SUFFIX_SYM "~sym"
860 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
862 #define SUFFIX_DST "~dst"
866 _SC_CFBundleGet(void)
868 static CFBundleRef bundle
= NULL
;
872 if (bundle
!= NULL
) {
876 bundle
= CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID
);
877 if (bundle
!= NULL
) {
878 CFRetain(bundle
); // we want to hold a reference to the bundle
882 // if appropriate (e.g. when debugging), try a bit harder
884 env
= getenv("DYLD_FRAMEWORK_PATH");
885 len
= (env
!= NULL
) ? strlen(env
) : 0;
887 // trim any trailing slashes
889 if (env
[len
- 1] != '/') {
895 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst"
896 if ((len
> SUFFIX_SYM_LEN
) &&
897 (strncmp(&env
[len
- SUFFIX_SYM_LEN
], SUFFIX_SYM
, SUFFIX_SYM_LEN
) == 0) &&
898 ((len
+ SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN
) < MAXPATHLEN
)) {
899 char path
[MAXPATHLEN
];
902 strlcpy(path
, env
, sizeof(path
));
903 strlcpy(&path
[len
- SUFFIX_SYM_LEN
], SUFFIX_DST
, sizeof(path
) - (len
- SUFFIX_SYM_LEN
));
904 strlcat(&path
[len
], SYSTEMCONFIGURATION_FRAMEWORK_PATH
, sizeof(path
) - len
);
906 url
= CFURLCreateFromFileSystemRepresentation(NULL
,
908 len
+ SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN
,
910 bundle
= CFBundleCreate(NULL
, url
);
914 if (bundle
== NULL
) {
915 static Boolean warned
= FALSE
;
917 SCLog(!warned
, LOG_WARNING
,
918 CFSTR("_SC_CFBundleGet(), could not get CFBundle for \"%@\""),
919 SYSTEMCONFIGURATION_BUNDLE_ID
);
928 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle
, CFStringRef key
, CFStringRef value
, CFStringRef tableName
)
930 CFDataRef data
= NULL
;
933 CFURLRef resourcesURL
;
934 CFStringRef str
= NULL
;
937 if ((tableName
== NULL
) || CFEqual(tableName
, CFSTR(""))) tableName
= CFSTR("Localizable");
940 * First, try getting the requested string using a manually constructed
941 * URL to <bundle>/Resources/English.lproj/<tableName>.strings. Do this
942 * because CFBundleCopyResourceURLForLocalization() uses CFPreferences
943 * to get the preferred localizations, CFPreferences talks to
944 * OpenDirectory, and OpenDirectory tries to obtain the platform UUID.
945 * On machines where the platform UUID is set by InterfaceNamer, a
946 * deadlock can occur if InterfaceNamer calls
947 * CFBundleCopyResourceURLForLocalization() before setting the
948 * platform UUID in the kernel.
950 resourcesURL
= CFBundleCopyResourcesDirectoryURL(bundle
);
951 if (resourcesURL
!= NULL
) {
952 CFStringRef fileName
= CFStringCreateWithFormat(
953 NULL
, NULL
, CFSTR("%@.strings"), tableName
);
954 CFURLRef enlproj
= CFURLCreateCopyAppendingPathComponent(
955 NULL
, resourcesURL
, CFSTR("English.lproj"), true);
956 url
= CFURLCreateCopyAppendingPathComponent(
957 NULL
, enlproj
, fileName
, false);
960 CFRelease(resourcesURL
);
962 #pragma GCC diagnostic push
963 #pragma GCC diagnostic ignored "-Wdeprecated"
964 ok
= CFURLCreateDataAndPropertiesFromResource(NULL
,
970 #pragma GCC diagnostic pop
973 * Failed to get the data using a manually-constructed URL
974 * for the given strings table. Fall back to using
975 * CFBundleCopyResourceURLForLocalization() below.
983 url
= CFBundleCopyResourceURLForLocalization(bundle
,
989 #pragma GCC diagnostic push
990 #pragma GCC diagnostic ignored "-Wdeprecated"
991 ok
= CFURLCreateDataAndPropertiesFromResource(NULL
,
997 #pragma GCC diagnostic pop
1006 CFDictionaryRef table
;
1008 table
= CFPropertyListCreateWithData(NULL
,
1010 kCFPropertyListImmutable
,
1013 if (table
!= NULL
) {
1014 if (isA_CFDictionary(table
)) {
1015 str
= CFDictionaryGetValue(table
, key
);
1028 str
= CFRetain(value
);
1036 #pragma mark Mach port / CFMachPort management
1040 _SC_CFMachPortCreateWithPort(const char *portDescription
,
1041 mach_port_t portNum
,
1042 CFMachPortCallBack callout
,
1043 CFMachPortContext
*context
)
1046 Boolean shouldFree
= FALSE
;
1048 port
= CFMachPortCreateWithPort(NULL
, portNum
, callout
, context
, &shouldFree
);
1049 if ((port
== NULL
) || shouldFree
) {
1051 char *crash_info
= NULL
;
1053 SCLog(TRUE
, LOG_ERR
,
1054 CFSTR("%s: CFMachPortCreateWithPort() failed , port = %p"),
1056 (void *)(uintptr_t)portNum
);
1058 err
= CFStringCreateWithFormat(NULL
, NULL
,
1059 CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"),
1060 portDescription
, port
);
1062 err
= CFStringCreateWithFormat(NULL
, NULL
,
1063 CFSTR("%s: CFMachPortCreateWithPort returned NULL"),
1066 crash_info
= _SC_cfstring_to_cstring(err
, NULL
, 0, kCFStringEncodingASCII
);
1067 if (err
!= NULL
) CFRelease(err
);
1070 err
= CFStringCreateWithFormat(NULL
,
1072 CFSTR("A recycled mach_port has been detected by \"%s\"."),
1074 _SC_crash(crash_info
, CFSTR("CFMachPort error"), err
);
1075 CFAllocatorDeallocate(NULL
, crash_info
);
1076 if (err
!= NULL
) CFRelease(err
);
1084 #pragma mark DOS encoding/codepage
1087 #if !TARGET_OS_IPHONE
1089 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding
,
1091 CFStringEncoding
*dosEncoding
,
1092 UInt32
*dosCodepage
)
1094 switch (macEncoding
) {
1095 case kCFStringEncodingMacRoman
:
1096 if (macRegion
!= 0) /* anything non-zero is not US */
1097 *dosEncoding
= kCFStringEncodingDOSLatin1
;
1098 else /* US region */
1099 *dosEncoding
= kCFStringEncodingDOSLatinUS
;
1102 case kCFStringEncodingMacJapanese
:
1103 *dosEncoding
= kCFStringEncodingDOSJapanese
;
1106 case kCFStringEncodingMacChineseTrad
:
1107 *dosEncoding
= kCFStringEncodingDOSChineseTrad
;
1110 case kCFStringEncodingMacKorean
:
1111 *dosEncoding
= kCFStringEncodingDOSKorean
;
1114 case kCFStringEncodingMacArabic
:
1115 *dosEncoding
= kCFStringEncodingDOSArabic
;
1118 case kCFStringEncodingMacHebrew
:
1119 *dosEncoding
= kCFStringEncodingDOSHebrew
;
1122 case kCFStringEncodingMacGreek
:
1123 *dosEncoding
= kCFStringEncodingDOSGreek
;
1126 case kCFStringEncodingMacCyrillic
:
1127 *dosEncoding
= kCFStringEncodingDOSCyrillic
;
1130 case kCFStringEncodingMacThai
:
1131 *dosEncoding
= kCFStringEncodingDOSThai
;
1134 case kCFStringEncodingMacChineseSimp
:
1135 *dosEncoding
= kCFStringEncodingDOSChineseSimplif
;
1138 case kCFStringEncodingMacCentralEurRoman
:
1139 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1142 case kCFStringEncodingMacTurkish
:
1143 *dosEncoding
= kCFStringEncodingDOSTurkish
;
1146 case kCFStringEncodingMacCroatian
:
1147 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1150 case kCFStringEncodingMacIcelandic
:
1151 *dosEncoding
= kCFStringEncodingDOSIcelandic
;
1154 case kCFStringEncodingMacRomanian
:
1155 *dosEncoding
= kCFStringEncodingDOSLatin2
;
1158 case kCFStringEncodingMacFarsi
:
1159 *dosEncoding
= kCFStringEncodingDOSArabic
;
1162 case kCFStringEncodingMacUkrainian
:
1163 *dosEncoding
= kCFStringEncodingDOSCyrillic
;
1167 *dosEncoding
= kCFStringEncodingDOSLatin1
;
1171 *dosCodepage
= CFStringConvertEncodingToWindowsCodepage(*dosEncoding
);
1174 #endif // !TARGET_OS_IPHONE
1178 #pragma mark Debugging
1182 * print status of in-use mach ports
1185 _SC_logMachPortStatus(void)
1187 kern_return_t status
;
1188 mach_port_name_array_t ports
;
1189 mach_port_type_array_t types
;
1190 mach_msg_type_number_t pi
, pn
, tn
;
1191 CFMutableStringRef str
;
1193 SCLog(TRUE
, LOG_NOTICE
, CFSTR("----------"));
1195 /* report on ALL mach ports associated with this task */
1196 status
= mach_port_names(mach_task_self(), &ports
, &pn
, &types
, &tn
);
1197 if (status
== MACH_MSG_SUCCESS
) {
1198 str
= CFStringCreateMutable(NULL
, 0);
1199 for (pi
= 0; pi
< pn
; pi
++) {
1200 char rights
[16], *rp
= &rights
[0];
1202 if (types
[pi
] != MACH_PORT_TYPE_NONE
) {
1205 if (types
[pi
] & MACH_PORT_TYPE_SEND
)
1207 if (types
[pi
] & MACH_PORT_TYPE_RECEIVE
)
1209 if (types
[pi
] & MACH_PORT_TYPE_SEND_ONCE
)
1211 if (types
[pi
] & MACH_PORT_TYPE_PORT_SET
)
1213 if (types
[pi
] & MACH_PORT_TYPE_DEAD_NAME
)
1218 CFStringAppendFormat(str
, NULL
, CFSTR(" %d%s"), ports
[pi
], rights
);
1220 SCLog(TRUE
, LOG_NOTICE
, CFSTR("Task ports (n=%d):%@"), pn
, str
);
1229 _SC_logMachPortReferences(const char *str
, mach_port_t port
)
1231 const char *blanks
= " ";
1233 mach_port_type_t pt
;
1234 mach_port_status_t recv_status
= { 0 };
1235 mach_port_urefs_t refs_send
= 0;
1236 mach_port_urefs_t refs_recv
= 0;
1237 mach_port_urefs_t refs_once
= 0;
1238 mach_port_urefs_t refs_pset
= 0;
1239 mach_port_urefs_t refs_dead
= 0;
1240 kern_return_t status
;
1244 static int is_configd
= -1;
1246 if (is_configd
== -1) {
1247 is_configd
= (strcmp(getprogname(), _SC_SERVER_PROG
) == 0);
1249 if (is_configd
== 1) {
1250 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1252 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1256 // add provided string
1257 strlcat(buf
, str
, sizeof(buf
));
1260 strlcat(buf
, blanks
, sizeof(buf
));
1261 if (strcmp(&buf
[sizeof(buf
) - 3], " ") == 0) {
1262 buf
[sizeof(buf
) - 3] = ':';
1266 status
= mach_port_type(mach_task_self(), port
, &pt
);
1267 if (status
!= KERN_SUCCESS
) {
1268 SCLog(TRUE
, LOG_NOTICE
,
1269 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"),
1272 mach_error_string(status
));
1276 if ((pt
& MACH_PORT_TYPE_SEND
) != 0) {
1277 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND
, &refs_send
);
1278 if (status
!= KERN_SUCCESS
) {
1279 SCLog(TRUE
, LOG_NOTICE
,
1280 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"),
1283 mach_error_string(status
));
1288 if ((pt
& MACH_PORT_TYPE_RECEIVE
) != 0) {
1289 mach_msg_type_number_t count
;
1291 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, &refs_recv
);
1292 if (status
!= KERN_SUCCESS
) {
1293 SCLog(TRUE
, LOG_NOTICE
,
1294 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s"),
1297 mach_error_string(status
));
1301 count
= MACH_PORT_RECEIVE_STATUS_COUNT
;
1302 status
= mach_port_get_attributes(mach_task_self(),
1304 MACH_PORT_RECEIVE_STATUS
,
1305 (mach_port_info_t
)&recv_status
,
1307 if (status
!= KERN_SUCCESS
) {
1308 SCLog(TRUE
, LOG_NOTICE
,
1309 CFSTR("%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s"),
1312 mach_error_string(status
));
1317 if ((pt
& MACH_PORT_TYPE_SEND_ONCE
) != 0) {
1318 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND_ONCE
, &refs_once
);
1319 if (status
!= KERN_SUCCESS
) {
1320 SCLog(TRUE
, LOG_NOTICE
,
1321 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s"),
1324 mach_error_string(status
));
1329 if ((pt
& MACH_PORT_TYPE_PORT_SET
) != 0) {
1330 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_PORT_SET
, &refs_pset
);
1331 if (status
!= KERN_SUCCESS
) {
1332 SCLog(TRUE
, LOG_NOTICE
,
1333 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s"),
1336 mach_error_string(status
));
1341 if ((pt
& MACH_PORT_TYPE_DEAD_NAME
) != 0) {
1342 status
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_DEAD_NAME
, &refs_dead
);
1343 if (status
!= KERN_SUCCESS
) {
1344 SCLog(TRUE
, LOG_NOTICE
,
1345 CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s"),
1348 mach_error_string(status
));
1353 SCLog(TRUE
, LOG_NOTICE
,
1354 CFSTR("%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s"),
1363 recv_status
.mps_nsrequest
? ", no more senders" : "",
1364 ((pt
& MACH_PORT_TYPE_DEAD_NAME
) != 0) ? ", dead name request" : "");
1376 CFMutableStringRef trace
;
1378 n
= backtrace(stack
, sizeof(stack
)/sizeof(stack
[0]));
1380 SCLog(TRUE
, LOG_ERR
, CFSTR("backtrace() failed: %s"), strerror(errno
));
1384 trace
= CFStringCreateMutable(NULL
, 0);
1386 symbols
= backtrace_symbols(stack
, n
);
1387 if (symbols
!= NULL
) {
1390 for (i
= 0; i
< n
; i
++) {
1391 CFStringAppendFormat(trace
, NULL
, CFSTR("%s\n"), symbols
[i
]);
1401 /* CrashReporter info */
1402 #if !TARGET_OS_IPHONE
1403 #include <CrashReporterClient.h>
1404 #else // !TARGET_OS_IPHONE
1405 const char *__crashreporter_info__
= NULL
;
1406 asm(".desc ___crashreporter_info__, 0x10");
1407 #endif // !TARGET_OS_IPHONE
1411 _SC_SimulateCrash(const char *crash_info
, CFStringRef notifyHeader
, CFStringRef notifyMessage
)
1415 #if ! TARGET_IPHONE_SIMULATOR
1416 static bool (*dyfunc_SimulateCrash
)(pid_t
, mach_exception_data_type_t
, CFStringRef
) = NULL
;
1417 static void *image
= NULL
;
1419 if ((dyfunc_SimulateCrash
== NULL
) && (image
== NULL
)) {
1420 const char *framework
= "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport";
1421 struct stat statbuf
;
1422 const char *suffix
= getenv("DYLD_IMAGE_SUFFIX");
1423 char path
[MAXPATHLEN
];
1425 strlcpy(path
, framework
, sizeof(path
));
1426 if (suffix
) strlcat(path
, suffix
, sizeof(path
));
1427 if (0 <= stat(path
, &statbuf
)) {
1428 image
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
1430 image
= dlopen(framework
, RTLD_LAZY
| RTLD_LOCAL
);
1433 if (image
!= NULL
) {
1434 dyfunc_SimulateCrash
= dlsym(image
, "SimulateCrash");
1436 image
= (void *)0x1; // to ensure that we only dlopen() once
1440 if (dyfunc_SimulateCrash
!= NULL
) {
1443 str
= CFStringCreateWithCString(NULL
, crash_info
, kCFStringEncodingUTF8
);
1444 ok
= dyfunc_SimulateCrash(getpid(), 0xbad0005cull
, str
);
1448 #if TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1449 if (ok
&& (notifyHeader
!= NULL
) && (notifyMessage
!= NULL
)) {
1450 static Boolean warned
= FALSE
;
1453 CFStringRef displayMessage
;
1455 displayMessage
= CFStringCreateWithFormat(NULL
,
1457 CFSTR("%@\n\nPlease collect the crash report and file a Radar."),
1459 CFUserNotificationDisplayNotice(0,
1460 kCFUserNotificationStopAlertLevel
,
1467 CFRelease(displayMessage
);
1471 #endif // TARGET_OS_EMBEDDED && !defined(DO_NOT_INFORM)
1472 #endif /* ! TARGET_IPHONE_SIMULATOR */
1479 _SC_crash(const char *crash_info
, CFStringRef notifyHeader
, CFStringRef notifyMessage
)
1483 if (crash_info
!= NULL
) {
1484 #if !TARGET_OS_IPHONE
1485 CRSetCrashLogMessage(crash_info
);
1486 #else // !TARGET_OS_IPHONE
1487 __crashreporter_info__
= crash_info
;
1488 #endif // !TARGET_OS_IPHONE
1490 SCLog(TRUE
, LOG_ERR
, CFSTR("%s"), crash_info
);
1493 if (_SC_isAppleInternal()) {
1494 // simulate a crash report
1495 ok
= _SC_SimulateCrash(crash_info
, notifyHeader
, notifyMessage
);
1496 #ifndef DO_NOT_CRASH
1498 // if we could not simulate a crash report, crash for real
1501 #endif // DO_NOT_CRASH
1504 #if !TARGET_OS_IPHONE
1505 CRSetCrashLogMessage(NULL
);
1506 #else // !TARGET_OS_IPHONE
1507 __crashreporter_info__
= NULL
;
1508 #endif // !TARGET_OS_IPHONE
1514 _SC_getconninfo(int socket
, struct sockaddr_storage
*src_addr
, struct sockaddr_storage
*dest_addr
, int *if_index
, uint32_t *flags
)
1516 struct so_cinforeq request
;
1518 memset(&request
, 0, sizeof(request
));
1520 if (src_addr
!= NULL
) {
1521 memset(src_addr
, 0, sizeof(*src_addr
));
1522 request
.scir_src
= (struct sockaddr
*)src_addr
;
1523 request
.scir_src_len
= sizeof(*src_addr
);
1526 if (dest_addr
!= NULL
) {
1527 memset(dest_addr
, 0, sizeof(*dest_addr
));
1528 request
.scir_dst
= (struct sockaddr
*)dest_addr
;
1529 request
.scir_dst_len
= sizeof(*dest_addr
);
1532 if (ioctl(socket
, SIOCGCONNINFO
, &request
) != 0) {
1533 SCLog(TRUE
, LOG_WARNING
, CFSTR("SIOCGCONNINFO failed: %s"), strerror(errno
));
1537 if (if_index
!= NULL
) {
1539 *if_index
= request
.scir_ifindex
;
1542 if (flags
!= NULL
) {
1544 *flags
= request
.scir_flags
;