Something went wrong. Try again.
Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
39 kB · 1618 lines
C
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619/* * Copyright (c) 2000-2019 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */
/* * Modification History * * June 1, 2001 Allan Nathanson <ajn@apple.com> * - public API conversion * * November 9, 2000 Allan Nathanson <ajn@apple.com> * - initial revision */
#define SC_LOG_HANDLE _SC_LOG_DEFAULT#include <SystemConfiguration/SystemConfiguration.h>#include <SystemConfiguration/SCValidation.h>#include <SystemConfiguration/SCPrivate.h>
#include <sys/param.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <net/if.h>#include <net/if_dl.h>#include <netinet/in.h>#include <arpa/inet.h>
#include <dispatch/dispatch.h>
#include <mach/mach.h>#include <mach/notify.h>#include <mach/mach_error.h>#include <pthread.h>
#include <execinfo.h>#include <unistd.h>
#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR#include <CoreFoundation/CFUserNotification.h>#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
/* CrashReporter "Application Specific Information" */#include <CrashReporterClient.h>
#define N_QUICK 32
#pragma mark -#pragma mark Miscellaneous
__private_extern__ char *_SC_cfstring_to_cstring_ext(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEncoding encoding, UInt8 lossByte, CFIndex *usedBufLen){ CFIndex converted; CFIndex last = 0; CFIndex len;
if (cfstr == NULL) { cfstr = CFSTR(""); } len = CFStringGetLength(cfstr);
/* how much buffer space will we really need? */ converted = CFStringGetBytes(cfstr, CFRangeMake(0, len), encoding, lossByte, FALSE, NULL, 0, &last); if (converted < len) { /* if full string could not be converted */ if (buf != NULL) { buf[0] = '\0'; } return NULL; }
if (buf != NULL) { if (bufLen < (last + 1)) { /* if the size of the provided buffer is too small */ buf[0] = '\0'; return NULL; } } else { /* allocate a buffer */ bufLen = last + 1; buf = CFAllocatorAllocate(NULL, bufLen, 0); if (buf == NULL) { return NULL; } }
(void)CFStringGetBytes(cfstr, CFRangeMake(0, len), encoding, lossByte, FALSE, (UInt8 *)buf, bufLen, &last); buf[last] = '\0';
if (usedBufLen != NULL) { *usedBufLen = last; }
return buf;}
char *_SC_cfstring_to_cstring(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEncoding encoding){ return _SC_cfstring_to_cstring_ext(cfstr, buf, bufLen, encoding, 0, NULL);
}
void_SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen){ union { const struct sockaddr *sa; const struct sockaddr_in *sin; const struct sockaddr_in6 *sin6; const struct sockaddr_dl *sdl; } addr;
addr.sa = address;
memset(buf, 0, bufLen); switch (address->sa_family) { case AF_INET : (void)inet_ntop(addr.sin->sin_family, &addr.sin->sin_addr, buf, (socklen_t)bufLen); break; case AF_INET6 : { (void)inet_ntop(addr.sin6->sin6_family, &addr.sin6->sin6_addr, buf, (socklen_t)bufLen); if (addr.sin6->sin6_scope_id != 0) { size_t n;
n = strlen(buf); if ((n+IF_NAMESIZE+1) <= bufLen) { buf[n++] = '%'; if_indextoname(addr.sin6->sin6_scope_id, &buf[n]); } } break; } default : snprintf(buf, bufLen, "unexpected address family %d", address->sa_family); break; }
return;}
struct sockaddr *_SC_string_to_sockaddr(const char *str, sa_family_t af, void *buf, size_t bufLen){ union { void *buf; struct sockaddr *sa; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; } addr;
if (buf == NULL) { bufLen = sizeof(struct sockaddr_storage); addr.buf = CFAllocatorAllocate(NULL, bufLen, 0); } else { addr.buf = buf; }
memset(addr.buf, 0, bufLen); if (((af == AF_UNSPEC) || (af == AF_INET)) && (bufLen >= sizeof(struct sockaddr_in)) && inet_aton(str, &addr.sin->sin_addr) == 1) { // if IPv4 address addr.sin->sin_len = sizeof(struct sockaddr_in); addr.sin->sin_family = AF_INET; } else if (((af == AF_UNSPEC) || (af == AF_INET6)) && (bufLen >= sizeof(struct sockaddr_in6)) && inet_pton(AF_INET6, str, &addr.sin6->sin6_addr) == 1) { // if IPv6 address char *p;
addr.sin6->sin6_len = sizeof(struct sockaddr_in6); addr.sin6->sin6_family = AF_INET6;
p = strchr(str, '%'); if (p != NULL) { addr.sin6->sin6_scope_id = if_nametoindex(p + 1); }
if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6->sin6_addr)) { uint16_t if_index;
if_index = ntohs(addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1]); addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1] = 0; if (addr.sin6->sin6_scope_id == 0) { // use the scope id that was embedded in the [link local] IPv6 address addr.sin6->sin6_scope_id = if_index; } } } else { if (addr.buf != buf) { CFAllocatorDeallocate(NULL, addr.buf); } addr.buf = NULL; }
return addr.sa;}
void_SC_sendMachMessage(mach_port_t port, mach_msg_id_t msg_id){ mach_msg_empty_send_t msg; mach_msg_option_t options; kern_return_t status;
memset(&msg, 0, sizeof(msg)); msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); msg.header.msgh_size = sizeof(msg); msg.header.msgh_remote_port = port; msg.header.msgh_local_port = MACH_PORT_NULL; msg.header.msgh_id = msg_id; options = MACH_SEND_TIMEOUT; status = mach_msg(&msg.header, /* msg */ MACH_SEND_MSG|options, /* options */ msg.header.msgh_size, /* send_size */ 0, /* rcv_size */ MACH_PORT_NULL, /* rcv_name */ 0, /* timeout */ MACH_PORT_NULL); /* notify */ if ((status == MACH_SEND_INVALID_DEST) || (status == MACH_SEND_TIMED_OUT)) { mach_msg_destroy(&msg.header); }
return;}
CFStringRef_SC_trimDomain(CFStringRef domain){ CFIndex length;
if (!isA_CFString(domain)) { return NULL; }
// remove any leading/trailing dots length = CFStringGetLength(domain); if ((length > 0) && (CFStringFindWithOptions(domain, CFSTR("."), CFRangeMake(0, 1), kCFCompareAnchored, NULL) || CFStringFindWithOptions(domain, CFSTR("."), CFRangeMake(0, length), kCFCompareAnchored|kCFCompareBackwards, NULL)) ) { CFMutableStringRef trimmed;
trimmed = CFStringCreateMutableCopy(NULL, 0, domain); CFStringTrim(trimmed, CFSTR(".")); domain = (CFStringRef)trimmed; length = CFStringGetLength(domain); } else { CFRetain(domain); }
if (length == 0) { CFRelease(domain); domain = NULL; }
return domain;}
CFStringRef_SC_hw_model(Boolean trim){ static CFStringRef model = NULL; static CFStringRef model_trimmed = NULL; static dispatch_once_t once;
dispatch_once(&once, ^{ char *cp; char hwModel[64]; int mib[] = { CTL_HW, HW_MODEL }; size_t n = sizeof(hwModel); int ret;
// get HW model name memset(&hwModel, 0, sizeof(hwModel)); ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &hwModel, &n, NULL, 0); if (ret != 0) { SC_log(LOG_NOTICE, "sysctl() CTL_HW/HW_MODEL failed: %s", strerror(errno)); return; } hwModel[sizeof(hwModel) - 1] = '\0'; model = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII);
// and the "trimmed" name // ... remove everything after (and including) a comma // ... and then any trailing digits cp = index(hwModel, ','); if (cp != NULL) { *cp = '\0'; } n = strlen(hwModel) - 1; while (n > 0) { if (!isdigit(hwModel[n])) { break; } hwModel[n--] = '\0'; } model_trimmed = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII); });
return trim ? model_trimmed : model;}
#pragma mark -#pragma mark Serialization
static kern_return_t__CFDataCopyVMData(CFDataRef data, void **dataRef, CFIndex *dataLen){ kern_return_t kr;
vm_address_t vm_address; vm_size_t vm_size;
vm_address = (vm_address_t)CFDataGetBytePtr(data); vm_size = (vm_size_t)CFDataGetLength(data); kr = vm_allocate(mach_task_self(), &vm_address, vm_size, VM_FLAGS_ANYWHERE); if (kr != KERN_SUCCESS) { *dataRef = NULL; *dataLen = 0; return kr; }
memcpy((void *)vm_address, (char *)CFDataGetBytePtr(data), vm_size); *dataRef = (void *)vm_address; *dataLen = vm_size;
return kr;}
Boolean_SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dataLen){ CFDataRef myXml;
if ((xml == NULL) && ((dataRef == NULL) || (dataLen == NULL))) { /* if not keeping track of allocated space */ return FALSE; }
myXml = CFPropertyListCreateData(NULL, obj, kCFPropertyListBinaryFormat_v1_0, 0, NULL); if (myXml == NULL) { SC_log(LOG_NOTICE, "CFPropertyListCreateData() failed"); if (xml != NULL) { *xml = NULL; } if ((dataRef != NULL) && (dataLen != NULL)) { *dataLen = 0; *dataRef = NULL; } return FALSE; }
if (xml != NULL) { *xml = myXml; if ((dataRef != NULL) && (dataLen != NULL)) { *dataRef = (void *)CFDataGetBytePtr(myXml); *dataLen = CFDataGetLength(myXml); } } else { kern_return_t kr;
kr = __CFDataCopyVMData(myXml, dataRef, dataLen); CFRelease(myXml); if (kr != KERN_SUCCESS) { SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr)); return FALSE; } }
return TRUE;}
Boolean_SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen){ CFErrorRef error = NULL;
if (xml == NULL) { kern_return_t status;
xml = CFDataCreateWithBytesNoCopy(NULL, (void *)dataRef, dataLen, kCFAllocatorNull); *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error); CFRelease(xml);
status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen); if (status != KERN_SUCCESS) { SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status)); /* non-fatal???, proceed */ } } else { *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error); }
if (*obj == NULL) { if (error != NULL) { SC_log(LOG_NOTICE, "CFPropertyListCreateWithData() failed: %@", error); CFRelease(error); } _SCErrorSet(kSCStatusFailed); return FALSE; }
return TRUE;}
Boolean_SCSerializeString(CFStringRef str, CFDataRef *data, void **dataRef, CFIndex *dataLen){ CFDataRef myData;
if (!isA_CFString(str)) { /* if not a CFString */ return FALSE; }
if ((data == NULL) && ((dataRef == NULL) || (dataLen == NULL))) { /* if not keeping track of allocated space */ return FALSE; }
myData = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0); if (myData == NULL) { SC_log(LOG_NOTICE, "CFStringCreateExternalRepresentation() failed"); if (data != NULL) { *data = NULL; } if ((dataRef != NULL) && (dataLen != NULL)) { *dataRef = NULL; *dataLen = 0; } return FALSE; }
if (data != NULL) { *data = myData; if ((dataRef != NULL) && (dataLen != NULL)) { *dataRef = (void *)CFDataGetBytePtr(myData); *dataLen = CFDataGetLength(myData); } } else { kern_return_t kr;
kr = __CFDataCopyVMData(myData, dataRef, dataLen); CFRelease(myData); if (kr != KERN_SUCCESS) { SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr)); return FALSE; } }
return TRUE;}
Boolean_SCUnserializeString(CFStringRef *str, CFDataRef utf8, void *dataRef, CFIndex dataLen){ if (utf8 == NULL) { kern_return_t status;
utf8 = CFDataCreateWithBytesNoCopy(NULL, dataRef, dataLen, kCFAllocatorNull); *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8); CFRelease(utf8);
status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen); if (status != KERN_SUCCESS) { SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status)); /* non-fatal???, proceed */ } } else { *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8); }
if (*str == NULL) { SC_log(LOG_NOTICE, "CFStringCreateFromExternalRepresentation() failed"); return FALSE; }
return TRUE;}
Boolean_SCSerializeData(CFDataRef data, void **dataRef, CFIndex *dataLen){ kern_return_t kr;
if (!isA_CFData(data)) { /* if not a CFData */ return FALSE; }
kr = __CFDataCopyVMData(data, dataRef, dataLen); if (kr != KERN_SUCCESS) { SC_log(LOG_NOTICE, "__CFDataCreateVMData() failed: %s", mach_error_string(kr)); return FALSE; }
return TRUE;}
Boolean_SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen){ kern_return_t status;
*data = CFDataCreate(NULL, dataRef, dataLen); status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen); if (status != KERN_SUCCESS) { SC_log(LOG_NOTICE, "vm_deallocate() failed: %s", mach_error_string(status)); _SCErrorSet(kSCStatusFailed); return FALSE; }
return TRUE;}
CF_RETURNS_RETAINED CFDictionaryRef_SCSerializeMultiple(CFDictionaryRef dict){ CFIndex i; const void * keys_q[N_QUICK]; const void ** keys = keys_q; CFIndex nElements; CFDictionaryRef newDict = NULL; const void * pLists_q[N_QUICK]; const void ** pLists = pLists_q; const void * values_q[N_QUICK]; const void ** values = values_q;
nElements = CFDictionaryGetCount(dict); if (nElements > 0) { if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFDataRef), 0); } memset(pLists, 0, nElements * sizeof(CFDataRef));
CFDictionaryGetKeysAndValues(dict, keys, values); for (i = 0; i < nElements; i++) { pLists[i] = NULL; if (!_SCSerialize((CFPropertyListRef)values[i], (CFDataRef *)&pLists[i], NULL, NULL)) { goto done; } } }
newDict = CFDictionaryCreate(NULL, keys, pLists, nElements, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
done :
if (nElements > 0) { for (i = 0; i < nElements; i++) { if (pLists[i] != NULL) CFRelease((CFDataRef)pLists[i]); }
if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, values); CFAllocatorDeallocate(NULL, pLists); } }
return newDict;}
CF_RETURNS_RETAINEDCFDictionaryRef_SCUnserializeMultiple(CFDictionaryRef dict){ const void * keys_q[N_QUICK]; const void ** keys = keys_q; CFIndex nElements; CFDictionaryRef newDict = NULL; const void * pLists_q[N_QUICK]; const void ** pLists = pLists_q; const void * values_q[N_QUICK]; const void ** values = values_q;
nElements = CFDictionaryGetCount(dict); if (nElements > 0) { CFIndex i;
if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) { keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0); } memset(pLists, 0, nElements * sizeof(CFTypeRef));
CFDictionaryGetKeysAndValues(dict, keys, values); for (i = 0; i < nElements; i++) { if (!_SCUnserialize((CFPropertyListRef *)&pLists[i], values[i], NULL, 0)) { goto done; } } }
newDict = CFDictionaryCreate(NULL, keys, pLists, nElements, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
done :
if (nElements > 0) { CFIndex i;
for (i = 0; i < nElements; i++) { if (pLists[i]) CFRelease(pLists[i]); }
if (keys != keys_q) { CFAllocatorDeallocate(NULL, keys); CFAllocatorDeallocate(NULL, values); CFAllocatorDeallocate(NULL, pLists); } }
return newDict;}
#pragma mark -
CFPropertyListRef_SCCreatePropertyListFromResource(CFURLRef url){ CFDictionaryRef dict = NULL; SInt64 fileLen = 0; Boolean ok; CFReadStreamRef readStream; CFNumberRef val = NULL;
if (!CFURLCopyResourcePropertyForKey(url, kCFURLFileSizeKey, &val, NULL) || (val == NULL)) { // if size not available SC_log(LOG_NOTICE, "CFURLCopyResourcePropertyForKey() size not available: %@", url); return NULL; }
ok = CFNumberGetValue(val, kCFNumberSInt64Type, &fileLen); CFRelease(val); if (!ok || (fileLen == 0)) { // if empty or size too large SC_log(LOG_INFO, "_SCCreatePropertyListFromResource() improper size: %@", url); return NULL; }
readStream = CFReadStreamCreateWithFile(NULL, url); if (readStream != NULL) { if (CFReadStreamOpen(readStream)) { UInt8 *buffer; CFIndex dataLen;
buffer = CFAllocatorAllocate(NULL, (CFIndex)fileLen, 0); dataLen = CFReadStreamRead(readStream, buffer, (CFIndex)fileLen); if (dataLen == (CFIndex)fileLen) { CFDataRef data;
data = CFDataCreateWithBytesNoCopy(NULL, buffer, (CFIndex)fileLen, kCFAllocatorNull); if (data != NULL) { dict = CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable, NULL, NULL); CFRelease(data); } } CFAllocatorDeallocate(NULL, buffer); CFReadStreamClose(readStream); } CFRelease(readStream); }
return dict;}
#pragma mark -#pragma mark CFRunLoop scheduling
__private_extern__ void_SC_signalRunLoop(CFTypeRef obj, CFRunLoopSourceRef rls, CFArrayRef rlList){ CFRunLoopRef rl = NULL; CFRunLoopRef rl1 = NULL; CFIndex i; CFIndex n = CFArrayGetCount(rlList);
if (n == 0) { return; }
/* get first runLoop for this object */ for (i = 0; i < n; i += 3) { if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) { continue; }
rl1 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1); break; }
if (rl1 == NULL) { /* if not scheduled */ return; }
/* check if we have another runLoop for this object */ rl = rl1; for (i = i+3; i < n; i += 3) { CFRunLoopRef rl2;
if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) { continue; }
rl2 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1); if (!CFEqual(rl1, rl2)) { /* we've got more than one runLoop */ rl = NULL; break; } }
if (rl != NULL) { /* if we only have one runLoop */ CFRunLoopWakeUp(rl); return; }
/* more than one different runLoop, so we must pick one */ for (i = 0; i < n; i+=3) { CFStringRef rlMode;
if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) { continue; }
rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1); rlMode = CFRunLoopCopyCurrentMode(rl); if (rlMode != NULL) { Boolean waiting;
waiting = (CFRunLoopIsWaiting(rl) && CFRunLoopContainsSource(rl, rls, rlMode)); CFRelease(rlMode); if (waiting) { /* we've found a runLoop that's "ready" */ CFRunLoopWakeUp(rl); return; } } }
/* didn't choose one above, so choose first */ CFRunLoopWakeUp(rl1); return;}
__private_extern__ Boolean_SC_isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList){ CFIndex i; CFIndex n = CFArrayGetCount(rlList);
for (i = 0; i < n; i += 3) { if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) { continue; } if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) { continue; } if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) { continue; } return TRUE; }
return FALSE;}
__private_extern__ void_SC_schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList){ CFArrayAppendValue(rlList, obj); CFArrayAppendValue(rlList, runLoop); CFArrayAppendValue(rlList, runLoopMode);
return;}
__private_extern__ Boolean_SC_unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all){ CFIndex i = 0; Boolean found = FALSE; CFIndex n = CFArrayGetCount(rlList);
while (i < n) { if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) { i += 3; continue; } if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) { i += 3; continue; } if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) { i += 3; continue; }
found = TRUE;
CFArrayRemoveValueAtIndex(rlList, i + 2); CFArrayRemoveValueAtIndex(rlList, i + 1); CFArrayRemoveValueAtIndex(rlList, i);
if (!all) { return found; }
n -= 3; }
return found;}
#pragma mark -#pragma mark Bundle
#define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")#define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
#define SUFFIX_SYM "~sym"#define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
#define SUFFIX_DST "~dst"
CFBundleRef_SC_CFBundleGet(void){ static CFBundleRef bundle = NULL; char *env; size_t len; CFURLRef url;
if (bundle != NULL) { goto done; }
bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID); if (bundle != NULL) { CFRetain(bundle); // we want to hold a reference to the bundle goto done; } else { SC_log(LOG_NOTICE, "could not get CFBundle for \"%@\". Trying harder...", SYSTEMCONFIGURATION_BUNDLE_ID); }
// if appropriate (e.g. when debugging), try a bit harder
env = getenv("DYLD_FRAMEWORK_PATH"); len = (env != NULL) ? strlen(env) : 0;
if (len > 0) { /* We are debugging */
// trim any trailing slashes while (len > 1) { if (env[len - 1] != '/') { break; } len--; }
// if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst" if ((len > SUFFIX_SYM_LEN) && (strncmp(&env[len - SUFFIX_SYM_LEN], SUFFIX_SYM, SUFFIX_SYM_LEN) == 0) && ((len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN) < MAXPATHLEN)) { char path[MAXPATHLEN];
strlcpy(path, env, sizeof(path)); strlcpy(&path[len - SUFFIX_SYM_LEN], SUFFIX_DST, sizeof(path) - (len - SUFFIX_SYM_LEN)); strlcat(&path[len], SYSTEMCONFIGURATION_FRAMEWORK_PATH, sizeof(path) - len);
url = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)path, len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN, TRUE); bundle = CFBundleCreate(NULL, url); CFRelease(url); } }
if (bundle == NULL) { /* Try a more "direct" route to get the bundle */
url = CFURLCreateWithFileSystemPath(NULL, CFSTR(SYSTEMCONFIGURATION_FRAMEWORK_PATH), kCFURLPOSIXPathStyle, TRUE);
bundle = CFBundleCreate(NULL, url); CFRelease(url); }
if (bundle == NULL) { SC_log(LOG_ERR, "could not get CFBundle for \"%@\"", SYSTEMCONFIGURATION_BUNDLE_ID); }
done: return bundle;}
/* * cachedInfo * <dict> * <key>bundleID-tableName</key> * <dict> * ... property list from non-localized bundle URL * </dict> * </dict> */static CFMutableDictionaryRef cachedInfo = NULL;
static dispatch_queue_t_SC_CFBundleCachedInfoQueue(){ static dispatch_once_t once; static dispatch_queue_t q;
dispatch_once(&once, ^{ q = dispatch_queue_create("_SC_CFBundleCachedInfo", NULL); });
return q;}
static CFStringRef_SC_CFBundleCachedInfoCopyTableKey(CFBundleRef bundle, CFStringRef tableName){ CFStringRef bundleID; CFStringRef tableKey;
bundleID = CFBundleGetIdentifier(bundle); tableKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@: %@"), bundleID, tableName); return tableKey;}
static CFDictionaryRef_SC_CFBundleCachedInfoCopyTable(CFBundleRef bundle, CFStringRef tableName){ __block CFDictionaryRef dict = NULL;
dispatch_sync(_SC_CFBundleCachedInfoQueue(), ^{ if (cachedInfo != NULL) { CFStringRef tableKey;
tableKey = _SC_CFBundleCachedInfoCopyTableKey(bundle, tableName); dict = CFDictionaryGetValue(cachedInfo, tableKey); if (dict != NULL) { CFRetain(dict); } CFRelease(tableKey); } });
return dict;}
static void_SC_CFBundleCachedInfoSaveTable(CFBundleRef bundle, CFStringRef tableName, CFDictionaryRef table){
dispatch_sync(_SC_CFBundleCachedInfoQueue(), ^{ CFStringRef tableKey;
tableKey = _SC_CFBundleCachedInfoCopyTableKey(bundle, tableName); SC_log(LOG_DEBUG, "Caching %@", tableKey);
if (cachedInfo == NULL) { cachedInfo = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } CFDictionarySetValue(cachedInfo, tableKey, table); CFRelease(tableKey); });
return;}
CFStringRef_SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName){ CFStringRef str = NULL; CFDictionaryRef table = NULL; CFURLRef url;
if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) { tableName = CFSTR("Localizable"); }
table = _SC_CFBundleCachedInfoCopyTable(bundle, tableName); if (table == NULL) { url = CFBundleCopyResourceURLForLocalization(bundle, tableName, CFSTR("strings"), NULL, CFSTR("en")); if (url != NULL) { table = _SCCreatePropertyListFromResource(url); CFRelease(url); if (table != NULL) { _SC_CFBundleCachedInfoSaveTable(bundle, tableName, table); } } else { SC_log(LOG_ERR, "failed to get resource url: {bundle:%@, table: %@}", bundle, tableName); } }
if (table != NULL) { if (isA_CFDictionary(table)) { str = CFDictionaryGetValue(table, key); if (str != NULL) { CFRetain(str); } }
CFRelease(table); }
if (str == NULL) { str = CFRetain(value); }
return str;}
#pragma mark -#pragma mark Mach port / CFMachPort management
CFMachPortRef_SC_CFMachPortCreateWithPort(const char *portDescription, mach_port_t portNum, CFMachPortCallBack callout, CFMachPortContext *context){ CFMachPortRef port; Boolean shouldFree = FALSE;
port = CFMachPortCreateWithPort(NULL, portNum, callout, context, &shouldFree); if ((port == NULL) || shouldFree) { char *crash_info; CFStringRef err;
SC_log(LOG_NOTICE, "%s: CFMachPortCreateWithPort() failed , port = %p", portDescription, (void *)(uintptr_t)portNum); if (port != NULL) { err = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"), portDescription, port); } else { err = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s: CFMachPortCreateWithPort returned NULL"), portDescription); } crash_info = _SC_cfstring_to_cstring(err, NULL, 0, kCFStringEncodingASCII); CFRelease(err);
err = CFStringCreateWithFormat(NULL, NULL, CFSTR("A recycled mach_port has been detected by \"%s\"."), getprogname()); _SC_crash(crash_info, CFSTR("CFMachPort error"), err); CFAllocatorDeallocate(NULL, crash_info); CFRelease(err); }
return port;}
#pragma mark -#pragma mark DOS encoding/codepage
#if !TARGET_OS_IPHONEvoid_SC_dos_encoding_and_codepage(CFStringEncoding macEncoding, UInt32 macRegion, CFStringEncoding *dosEncoding, UInt32 *dosCodepage){ switch (macEncoding) { case kCFStringEncodingMacRoman: if (macRegion != 0) /* anything non-zero is not US */ *dosEncoding = kCFStringEncodingDOSLatin1; else /* US region */ *dosEncoding = kCFStringEncodingDOSLatinUS; break;
case kCFStringEncodingMacJapanese: *dosEncoding = kCFStringEncodingDOSJapanese; break;
case kCFStringEncodingMacChineseTrad: *dosEncoding = kCFStringEncodingDOSChineseTrad; break;
case kCFStringEncodingMacKorean: *dosEncoding = kCFStringEncodingDOSKorean; break;
case kCFStringEncodingMacArabic: *dosEncoding = kCFStringEncodingDOSArabic; break;
case kCFStringEncodingMacHebrew: *dosEncoding = kCFStringEncodingDOSHebrew; break;
case kCFStringEncodingMacGreek: *dosEncoding = kCFStringEncodingDOSGreek; break;
case kCFStringEncodingMacCyrillic: *dosEncoding = kCFStringEncodingDOSCyrillic; break;
case kCFStringEncodingMacThai: *dosEncoding = kCFStringEncodingDOSThai; break;
case kCFStringEncodingMacChineseSimp: *dosEncoding = kCFStringEncodingDOSChineseSimplif; break;
case kCFStringEncodingMacCentralEurRoman: *dosEncoding = kCFStringEncodingDOSLatin2; break;
case kCFStringEncodingMacTurkish: *dosEncoding = kCFStringEncodingDOSTurkish; break;
case kCFStringEncodingMacCroatian: *dosEncoding = kCFStringEncodingDOSLatin2; break;
case kCFStringEncodingMacIcelandic: *dosEncoding = kCFStringEncodingDOSIcelandic; break;
case kCFStringEncodingMacRomanian: *dosEncoding = kCFStringEncodingDOSLatin2; break;
case kCFStringEncodingMacFarsi: *dosEncoding = kCFStringEncodingDOSArabic; break;
case kCFStringEncodingMacUkrainian: *dosEncoding = kCFStringEncodingDOSCyrillic; break;
default: *dosEncoding = kCFStringEncodingDOSLatin1; break; }
*dosCodepage = CFStringConvertEncodingToWindowsCodepage(*dosEncoding); return;}#endif // !TARGET_OS_IPHONE
#pragma mark -#pragma mark Debugging
/* * print status of in-use mach ports */void_SC_logMachPortStatus(void){ kern_return_t status; mach_port_name_array_t ports; mach_port_type_array_t types; mach_msg_type_number_t pi, pn, tn; CFMutableStringRef str;
SC_log(LOG_DEBUG, "----------");
/* report on ALL mach ports associated with this task */ status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn); if (status == MACH_MSG_SUCCESS) { str = CFStringCreateMutable(NULL, 0); for (pi = 0; pi < pn; pi++) { char rights[16], *rp = &rights[0];
if (types[pi] != MACH_PORT_TYPE_NONE) { *rp++ = ' '; *rp++ = '('; if (types[pi] & MACH_PORT_TYPE_SEND) *rp++ = 'S'; if (types[pi] & MACH_PORT_TYPE_RECEIVE) *rp++ = 'R'; if (types[pi] & MACH_PORT_TYPE_SEND_ONCE) *rp++ = 'O'; if (types[pi] & MACH_PORT_TYPE_PORT_SET) *rp++ = 'P'; if (types[pi] & MACH_PORT_TYPE_DEAD_NAME) *rp++ = 'D'; *rp++ = ')'; } *rp = '\0'; CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights); } SC_log(LOG_DEBUG, "Task ports (n=%d):%@", pn, str); CFRelease(str); }
return;}
__private_extern__kern_return_t_SC_getMachPortReferences(mach_port_t port, mach_port_type_t *pt, mach_port_urefs_t *refs_send, mach_port_urefs_t *refs_recv, mach_port_status_t *recv_status, mach_port_urefs_t *refs_once, mach_port_urefs_t *refs_pset, mach_port_urefs_t *refs_dead, const char *err_prefix){ kern_return_t status;
status = mach_port_type(mach_task_self(), port, pt); if (status != KERN_SUCCESS) { SC_log(LOG_DEBUG, "%smach_port_type(..., 0x%x): %s", err_prefix, port, mach_error_string(status)); return status; }
if ((refs_send != NULL) && ((*pt & MACH_PORT_TYPE_SEND) != 0)) { status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, refs_send); if (status != KERN_SUCCESS) { SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s", err_prefix, port, mach_error_string(status)); return status; } }
if ((refs_recv != NULL) && (recv_status != NULL) && ((*pt & MACH_PORT_TYPE_RECEIVE) != 0)) { mach_msg_type_number_t count;
status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, refs_recv); if (status != KERN_SUCCESS) { SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s", err_prefix, port, mach_error_string(status)); return status; }
count = MACH_PORT_RECEIVE_STATUS_COUNT; status = mach_port_get_attributes(mach_task_self(), port, MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)recv_status, &count); if (status != KERN_SUCCESS) { SC_log(LOG_DEBUG, "%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s", err_prefix, port, mach_error_string(status)); return status; } }
if ((refs_once != NULL) && ((*pt & MACH_PORT_TYPE_SEND_ONCE) != 0)) { status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, refs_once); if (status != KERN_SUCCESS) { SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s", err_prefix, port, mach_error_string(status)); return status; } }
if ((refs_pset != NULL) && ((*pt & MACH_PORT_TYPE_PORT_SET) != 0)) { status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, refs_pset); if (status != KERN_SUCCESS) { SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s", err_prefix, port, mach_error_string(status)); return status; } }
if ((refs_dead != NULL) && ((*pt & MACH_PORT_TYPE_DEAD_NAME) != 0)) { status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, refs_dead); if (status != KERN_SUCCESS) { SC_log(LOG_DEBUG, "%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s", err_prefix, port, mach_error_string(status)); return status; } }
return KERN_SUCCESS;}
void_SC_logMachPortReferences(const char *str, mach_port_t port){ const char *blanks = " "; char buf[60]; mach_port_type_t pt; mach_port_status_t recv_status = { .mps_nsrequest = 0, }; mach_port_urefs_t refs_send = 0; mach_port_urefs_t refs_recv = 0; mach_port_urefs_t refs_once = 0; mach_port_urefs_t refs_pset = 0; mach_port_urefs_t refs_dead = 0; kern_return_t status;
buf[0] = '\0'; if (str != NULL) { static int is_configd = -1;
if (is_configd == -1) { is_configd = (strcmp(getprogname(), _SC_SERVER_PROG) == 0); } if (is_configd == 1) { // if "configd", add indication if this is the M[ain] or [P]lugin thread strlcpy(buf, (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ", sizeof(buf)); }
// add provided string strlcat(buf, str, sizeof(buf));
// fill strlcat(buf, blanks, sizeof(buf)); if (strcmp(&buf[sizeof(buf) - 3], " ") == 0) { buf[sizeof(buf) - 3] = ':'; } }
status = _SC_getMachPortReferences(port, &pt, &refs_send, &refs_recv, &recv_status, &refs_once, &refs_pset, &refs_dead, buf); if (status != KERN_SUCCESS) { return; }
SC_log(LOG_DEBUG, "%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s", buf, port, port, refs_send, refs_recv, refs_once, refs_pset, refs_dead, recv_status.mps_nsrequest ? ", no more senders" : "", ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) ? ", dead name request" : "");
return;}
CFStringRef_SC_copyBacktrace(){ int n; void *stack[64]; char **symbols; CFMutableStringRef trace;
n = backtrace(stack, sizeof(stack)/sizeof(stack[0])); if (n == -1) { SC_log(LOG_NOTICE, "backtrace() failed: %s", strerror(errno)); return NULL; }
trace = CFStringCreateMutable(NULL, 0);
symbols = backtrace_symbols(stack, n); if (symbols != NULL) { int i;
for (i = 0; i < n; i++) { CFStringAppendFormat(trace, NULL, CFSTR("%s\n"), symbols[i]); }
free(symbols); }
return trace;}
static void_SC_ReportCrash(CFStringRef notifyHeader, CFStringRef notifyMessage){#if !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR#pragma unused(notifyHeader)#pragma unused(notifyMessage)#endif // !TARGET_OS_IPHONE || TARGET_OS_SIMULATOR static Boolean warned = FALSE;
if (!warned) {#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR CFStringRef displayMessage;
displayMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\n\nPlease collect the crash report and file a Radar."), notifyMessage); CFUserNotificationDisplayNotice(0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, notifyHeader, displayMessage, NULL); CFRelease(displayMessage);#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR warned = TRUE; }
return;}
void_SC_crash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage){ if (_SC_isAppleInternal()) { if (crash_info != NULL) { CRSetCrashLogMessage(crash_info); SC_log(LOG_NOTICE, "%s", crash_info); }
// simulate a crash report os_log_with_type(SC_LOG_HANDLE(), OS_LOG_TYPE_FAULT, "%s", crash_info);
// report the crash to the user if ((notifyHeader != NULL) && (notifyMessage != NULL)) { _SC_ReportCrash(notifyHeader, notifyMessage); }
if (crash_info != NULL) { CRSetCrashLogMessage(NULL); } }
return;}
Boolean_SC_getconninfo(int socket, struct sockaddr_storage *src_addr, struct sockaddr_storage *dest_addr, int *if_index, uint32_t *flags){ struct so_cinforeq request;
memset(&request, 0, sizeof(request));
if (src_addr != NULL) { memset(src_addr, 0, sizeof(*src_addr)); request.scir_src = (struct sockaddr *)src_addr; request.scir_src_len = sizeof(*src_addr); }
if (dest_addr != NULL) { memset(dest_addr, 0, sizeof(*dest_addr)); request.scir_dst = (struct sockaddr *)dest_addr; request.scir_dst_len = sizeof(*dest_addr); }
if (ioctl(socket, SIOCGCONNINFO, &request) != 0) { SC_log(LOG_NOTICE, "SIOCGCONNINFO failed: %s", strerror(errno)); return FALSE; }
if (if_index != NULL) { *if_index = 0; *if_index = request.scir_ifindex; }
if (flags != NULL) { *flags = 0; *flags = request.scir_flags; }
return TRUE;}