]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDPrivate.c
configd-395.6.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDPrivate.c
1 /*
2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * November 9, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 //#define DO_NOT_CRASH
35 //#define DO_NOT_INFORM
36
37 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCValidation.h>
39 #include <SystemConfiguration/SCPrivate.h>
40
41 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <net/if.h>
45 #include <net/if_dl.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48
49 #include <mach/mach.h>
50 #include <mach/notify.h>
51 #include <mach/mach_error.h>
52 #include <pthread.h>
53
54 #include <execinfo.h>
55 #include <libproc.h>
56 #include <unistd.h>
57 #include <dlfcn.h>
58
59
60 #if TARGET_OS_EMBEDDED && !TARGET_OS_EMBEDDED_OTHER && !defined(DO_NOT_INFORM)
61 #include <CoreFoundation/CFUserNotification.h>
62 #endif // TARGET_OS_EMBEDDED && !TARGET_OS_EMBEDDED_OTHER && !defined(DO_NOT_INFORM)
63
64 #define N_QUICK 32
65
66
67 #pragma mark -
68 #pragma mark Miscellaneous
69
70
71 char *
72 _SC_cfstring_to_cstring(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEncoding encoding)
73 {
74 CFIndex converted;
75 CFIndex last = 0;
76 CFIndex len;
77
78 if (cfstr == NULL) {
79 cfstr = CFSTR("");
80 }
81 len = CFStringGetLength(cfstr);
82
83 /* how much buffer space will we really need? */
84 converted = CFStringGetBytes(cfstr,
85 CFRangeMake(0, len),
86 encoding,
87 0,
88 FALSE,
89 NULL,
90 0,
91 &last);
92 if (converted < len) {
93 /* if full string could not be converted */
94 if (buf != NULL) {
95 buf[0] = '\0';
96 }
97 return NULL;
98 }
99
100 if (buf != NULL) {
101 if (bufLen < (last + 1)) {
102 /* if the size of the provided buffer is too small */
103 buf[0] = '\0';
104 return NULL;
105 }
106 } else {
107 /* allocate a buffer */
108 bufLen = last + 1;
109 buf = CFAllocatorAllocate(NULL, bufLen, 0);
110 if (buf == NULL) {
111 return NULL;
112 }
113 }
114
115 (void)CFStringGetBytes(cfstr,
116 CFRangeMake(0, len),
117 encoding,
118 0,
119 FALSE,
120 (UInt8 *)buf,
121 bufLen,
122 &last);
123 buf[last] = '\0';
124
125 return buf;
126 }
127
128
129 void
130 _SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen)
131 {
132 bzero(buf, bufLen);
133 switch (address->sa_family) {
134 case AF_INET :
135 (void)inet_ntop(((struct sockaddr_in *)address)->sin_family,
136 &((struct sockaddr_in *)address)->sin_addr,
137 buf,
138 bufLen);
139 break;
140 case AF_INET6 : {
141 (void)inet_ntop(((struct sockaddr_in6 *)address)->sin6_family,
142 &((struct sockaddr_in6 *)address)->sin6_addr,
143 buf,
144 bufLen);
145 if (((struct sockaddr_in6 *)address)->sin6_scope_id != 0) {
146 int n;
147
148 n = strlen(buf);
149 if ((n+IF_NAMESIZE+1) <= (int)bufLen) {
150 buf[n++] = '%';
151 if_indextoname(((struct sockaddr_in6 *)address)->sin6_scope_id, &buf[n]);
152 }
153 }
154 break;
155 }
156 case AF_LINK :
157 if (((struct sockaddr_dl *)address)->sdl_len < bufLen) {
158 bufLen = ((struct sockaddr_dl *)address)->sdl_len;
159 } else {
160 bufLen = bufLen - 1;
161 }
162
163 bcopy(((struct sockaddr_dl *)address)->sdl_data, buf, bufLen);
164 break;
165 default :
166 snprintf(buf, bufLen, "unexpected address family %d", address->sa_family);
167 break;
168 }
169
170 return;
171 }
172
173
174 void
175 _SC_sendMachMessage(mach_port_t port, mach_msg_id_t msg_id)
176 {
177 mach_msg_empty_send_t msg;
178 mach_msg_option_t options;
179 kern_return_t status;
180
181 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
182 msg.header.msgh_size = sizeof(msg);
183 msg.header.msgh_remote_port = port;
184 msg.header.msgh_local_port = MACH_PORT_NULL;
185 msg.header.msgh_id = msg_id;
186 options = MACH_SEND_TIMEOUT;
187 status = mach_msg(&msg.header, /* msg */
188 MACH_SEND_MSG|options, /* options */
189 msg.header.msgh_size, /* send_size */
190 0, /* rcv_size */
191 MACH_PORT_NULL, /* rcv_name */
192 0, /* timeout */
193 MACH_PORT_NULL); /* notify */
194 if (status != MACH_MSG_SUCCESS) {
195 mach_msg_destroy(&msg.header);
196 }
197
198 return;
199 }
200
201
202 CFStringRef
203 _SC_trimDomain(CFStringRef domain)
204 {
205 CFIndex length;
206
207 if (!isA_CFString(domain)) {
208 return NULL;
209 }
210
211 // remove any leading/trailing dots
212 length = CFStringGetLength(domain);
213 if ((length > 0) &&
214 (CFStringFindWithOptions(domain,
215 CFSTR("."),
216 CFRangeMake(0, 1),
217 kCFCompareAnchored,
218 NULL) ||
219 CFStringFindWithOptions(domain,
220 CFSTR("."),
221 CFRangeMake(0, length),
222 kCFCompareAnchored|kCFCompareBackwards,
223 NULL))) {
224 CFMutableStringRef trimmed;
225
226 trimmed = CFStringCreateMutableCopy(NULL, 0, domain);
227 CFStringTrim(trimmed, CFSTR("."));
228 domain = (CFStringRef)trimmed;
229 length = CFStringGetLength(domain);
230 } else {
231 CFRetain(domain);
232 }
233
234 if (length == 0) {
235 CFRelease(domain);
236 domain = NULL;
237 }
238
239 return domain;
240 }
241
242
243 #pragma mark -
244 #pragma mark Serialization
245
246
247 Boolean
248 _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dataLen)
249 {
250 CFDataRef myXml;
251
252 if ((xml == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
253 /* if not keeping track of allocated space */
254 return FALSE;
255 }
256
257 myXml = CFPropertyListCreateData(NULL,
258 obj,
259 kCFPropertyListBinaryFormat_v1_0,
260 0,
261 NULL);
262 if (myXml == NULL) {
263 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerialize() failed"));
264 if (xml != NULL) {
265 *xml = NULL;
266 }
267 if ((dataRef != NULL) && (dataLen != NULL)) {
268 *dataLen = 0;
269 *dataRef = NULL;
270 }
271 return FALSE;
272 }
273
274 if (xml != NULL) {
275 *xml = myXml;
276 if ((dataRef != NULL) && (dataLen != NULL)) {
277 *dataRef = (void *)CFDataGetBytePtr(myXml);
278 *dataLen = CFDataGetLength(myXml);
279 }
280 } else {
281 mach_msg_type_number_t len;
282 kern_return_t status;
283
284 status = vm_read(mach_task_self(),
285 (vm_address_t)CFDataGetBytePtr(myXml), // address
286 (vm_size_t) CFDataGetLength(myXml), // size
287 (void *)dataRef,
288 &len);
289 if (status != KERN_SUCCESS) {
290 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerialize(): %s"), mach_error_string(status));
291 CFRelease(myXml);
292 *dataRef = NULL;
293 *dataLen = 0;
294 return FALSE;
295 }
296
297 *dataLen = len;
298 CFRelease(myXml);
299 }
300
301 return TRUE;
302 }
303
304
305 Boolean
306 _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen)
307 {
308 CFErrorRef error;
309
310 if (xml == NULL) {
311 kern_return_t status;
312
313 xml = CFDataCreateWithBytesNoCopy(NULL, (void *)dataRef, dataLen, kCFAllocatorNull);
314 *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error);
315 CFRelease(xml);
316
317 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
318 if (status != KERN_SUCCESS) {
319 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserialize(): %s"), mach_error_string(status));
320 /* non-fatal???, proceed */
321 }
322 } else {
323 *obj = CFPropertyListCreateWithData(NULL, xml, kCFPropertyListImmutable, NULL, &error);
324 }
325
326 if (*obj == NULL) {
327 if (error != NULL) {
328 SCLog(TRUE, LOG_ERR, CFSTR("_SCUnserialize(): %@"), error);
329 CFRelease(error);
330 }
331 _SCErrorSet(kSCStatusFailed);
332 return FALSE;
333 }
334
335 return TRUE;
336 }
337
338
339 Boolean
340 _SCSerializeString(CFStringRef str, CFDataRef *data, void **dataRef, CFIndex *dataLen)
341 {
342 CFDataRef myData;
343
344 if (!isA_CFString(str)) {
345 /* if not a CFString */
346 return FALSE;
347 }
348
349 if ((data == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
350 /* if not keeping track of allocated space */
351 return FALSE;
352 }
353
354 myData = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
355 if (myData == NULL) {
356 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeString() failed"));
357 if (data != NULL) {
358 *data = NULL;
359 }
360 if ((dataRef != NULL) && (dataLen != NULL)) {
361 *dataRef = NULL;
362 *dataLen = 0;
363 }
364 return FALSE;
365 }
366
367 if (data != NULL) {
368 *data = myData;
369 if ((dataRef != NULL) && (dataLen != NULL)) {
370 *dataRef = (void *)CFDataGetBytePtr(myData);
371 *dataLen = CFDataGetLength(myData);
372 }
373 } else {
374 mach_msg_type_number_t len;
375 kern_return_t status;
376
377 *dataLen = CFDataGetLength(myData);
378 status = vm_read(mach_task_self(),
379 (vm_address_t)CFDataGetBytePtr(myData), // address
380 *dataLen, // size
381 (void *)dataRef,
382 &len);
383 if (status != KERN_SUCCESS) {
384 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeString(): %s"), mach_error_string(status));
385 CFRelease(myData);
386 *dataRef = NULL;
387 *dataLen = 0;
388 return FALSE;
389 }
390
391 *dataLen = len;
392 CFRelease(myData);
393 }
394
395 return TRUE;
396 }
397
398
399 Boolean
400 _SCUnserializeString(CFStringRef *str, CFDataRef utf8, void *dataRef, CFIndex dataLen)
401 {
402 if (utf8 == NULL) {
403 kern_return_t status;
404
405 utf8 = CFDataCreateWithBytesNoCopy(NULL, dataRef, dataLen, kCFAllocatorNull);
406 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
407 CFRelease(utf8);
408
409 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
410 if (status != KERN_SUCCESS) {
411 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserializeString(): %s"), mach_error_string(status));
412 /* non-fatal???, proceed */
413 }
414 } else {
415 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
416 }
417
418 if (*str == NULL) {
419 SCLog(TRUE, LOG_ERR, CFSTR("_SCUnserializeString() failed"));
420 return FALSE;
421 }
422
423 return TRUE;
424 }
425
426
427 Boolean
428 _SCSerializeData(CFDataRef data, void **dataRef, CFIndex *dataLen)
429 {
430 mach_msg_type_number_t len;
431 kern_return_t status;
432
433 if (!isA_CFData(data)) {
434 /* if not a CFData */
435 return FALSE;
436 }
437
438 *dataLen = CFDataGetLength(data);
439 status = vm_read(mach_task_self(),
440 (vm_address_t)CFDataGetBytePtr(data), // address
441 *dataLen, // size
442 (void *)dataRef,
443 &len);
444 if (status != KERN_SUCCESS) {
445 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeData(): %s"), mach_error_string(status));
446 *dataRef = NULL;
447 *dataLen = 0;
448 return FALSE;
449 }
450
451 *dataLen = len;
452
453 return TRUE;
454 }
455
456
457 Boolean
458 _SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen)
459 {
460 kern_return_t status;
461
462 *data = CFDataCreate(NULL, dataRef, dataLen);
463 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
464 if (status != KERN_SUCCESS) {
465 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserializeData(): %s"), mach_error_string(status));
466 _SCErrorSet(kSCStatusFailed);
467 return FALSE;
468 }
469
470 return TRUE;
471 }
472
473
474 CFDictionaryRef
475 _SCSerializeMultiple(CFDictionaryRef dict)
476 {
477 const void * keys_q[N_QUICK];
478 const void ** keys = keys_q;
479 CFIndex nElements;
480 CFDictionaryRef newDict = NULL;
481 const void * pLists_q[N_QUICK];
482 const void ** pLists = pLists_q;
483 const void * values_q[N_QUICK];
484 const void ** values = values_q;
485
486 nElements = CFDictionaryGetCount(dict);
487 if (nElements > 0) {
488 CFIndex i;
489
490 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
491 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
492 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
493 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
494 }
495 bzero(pLists, nElements * sizeof(CFTypeRef));
496
497 CFDictionaryGetKeysAndValues(dict, keys, values);
498 for (i = 0; i < nElements; i++) {
499 if (!_SCSerialize((CFPropertyListRef)values[i], (CFDataRef *)&pLists[i], NULL, NULL)) {
500 goto done;
501 }
502 }
503 }
504
505 newDict = CFDictionaryCreate(NULL,
506 keys,
507 pLists,
508 nElements,
509 &kCFTypeDictionaryKeyCallBacks,
510 &kCFTypeDictionaryValueCallBacks);
511
512 done :
513
514 if (nElements > 0) {
515 CFIndex i;
516
517 for (i = 0; i < nElements; i++) {
518 if (pLists[i]) CFRelease(pLists[i]);
519 }
520
521 if (keys != keys_q) {
522 CFAllocatorDeallocate(NULL, keys);
523 CFAllocatorDeallocate(NULL, values);
524 CFAllocatorDeallocate(NULL, pLists);
525 }
526 }
527
528 return newDict;
529 }
530
531
532 CFDictionaryRef
533 _SCUnserializeMultiple(CFDictionaryRef dict)
534 {
535 const void * keys_q[N_QUICK];
536 const void ** keys = keys_q;
537 CFIndex nElements;
538 CFDictionaryRef newDict = NULL;
539 const void * pLists_q[N_QUICK];
540 const void ** pLists = pLists_q;
541 const void * values_q[N_QUICK];
542 const void ** values = values_q;
543
544 nElements = CFDictionaryGetCount(dict);
545 if (nElements > 0) {
546 CFIndex i;
547
548 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
549 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
550 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
551 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
552 }
553 bzero(pLists, nElements * sizeof(CFTypeRef));
554
555 CFDictionaryGetKeysAndValues(dict, keys, values);
556 for (i = 0; i < nElements; i++) {
557 if (!_SCUnserialize((CFPropertyListRef *)&pLists[i], values[i], NULL, 0)) {
558 goto done;
559 }
560 }
561 }
562
563 newDict = CFDictionaryCreate(NULL,
564 keys,
565 pLists,
566 nElements,
567 &kCFTypeDictionaryKeyCallBacks,
568 &kCFTypeDictionaryValueCallBacks);
569
570 done :
571
572 if (nElements > 0) {
573 CFIndex i;
574
575 for (i = 0; i < nElements; i++) {
576 if (pLists[i]) CFRelease(pLists[i]);
577 }
578
579 if (keys != keys_q) {
580 CFAllocatorDeallocate(NULL, keys);
581 CFAllocatorDeallocate(NULL, values);
582 CFAllocatorDeallocate(NULL, pLists);
583 }
584 }
585
586 return newDict;
587 }
588
589
590 #pragma mark -
591 #pragma mark CFRunLoop scheduling
592
593
594 __private_extern__ void
595 _SC_signalRunLoop(CFTypeRef obj, CFRunLoopSourceRef rls, CFArrayRef rlList)
596 {
597 CFRunLoopRef rl = NULL;
598 CFRunLoopRef rl1 = NULL;
599 CFIndex i;
600 CFIndex n = CFArrayGetCount(rlList);
601
602 if (n == 0) {
603 return;
604 }
605
606 /* get first runLoop for this object */
607 for (i = 0; i < n; i += 3) {
608 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
609 continue;
610 }
611
612 rl1 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
613 break;
614 }
615
616 if (rl1 == NULL) {
617 /* if not scheduled */
618 return;
619 }
620
621 /* check if we have another runLoop for this object */
622 rl = rl1;
623 for (i = i+3; i < n; i += 3) {
624 CFRunLoopRef rl2;
625
626 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
627 continue;
628 }
629
630 rl2 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
631 if (!CFEqual(rl1, rl2)) {
632 /* we've got more than one runLoop */
633 rl = NULL;
634 break;
635 }
636 }
637
638 if (rl != NULL) {
639 /* if we only have one runLoop */
640 CFRunLoopWakeUp(rl);
641 return;
642 }
643
644 /* more than one different runLoop, so we must pick one */
645 for (i = 0; i < n; i+=3) {
646 CFStringRef rlMode;
647
648 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
649 continue;
650 }
651
652 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
653 rlMode = CFRunLoopCopyCurrentMode(rl);
654 if (rlMode != NULL) {
655 Boolean waiting;
656
657 waiting = (CFRunLoopIsWaiting(rl) && CFRunLoopContainsSource(rl, rls, rlMode));
658 CFRelease(rlMode);
659 if (waiting) {
660 /* we've found a runLoop that's "ready" */
661 CFRunLoopWakeUp(rl);
662 return;
663 }
664 }
665 }
666
667 /* didn't choose one above, so choose first */
668 CFRunLoopWakeUp(rl1);
669 return;
670 }
671
672
673 __private_extern__ Boolean
674 _SC_isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
675 {
676 CFIndex i;
677 CFIndex n = CFArrayGetCount(rlList);
678
679 for (i = 0; i < n; i += 3) {
680 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
681 continue;
682 }
683 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
684 continue;
685 }
686 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
687 continue;
688 }
689 return TRUE;
690 }
691
692 return FALSE;
693 }
694
695
696 __private_extern__ void
697 _SC_schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
698 {
699 CFArrayAppendValue(rlList, obj);
700 CFArrayAppendValue(rlList, runLoop);
701 CFArrayAppendValue(rlList, runLoopMode);
702
703 return;
704 }
705
706
707 __private_extern__ Boolean
708 _SC_unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all)
709 {
710 CFIndex i = 0;
711 Boolean found = FALSE;
712 CFIndex n = CFArrayGetCount(rlList);
713
714 while (i < n) {
715 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
716 i += 3;
717 continue;
718 }
719 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
720 i += 3;
721 continue;
722 }
723 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
724 i += 3;
725 continue;
726 }
727
728 found = TRUE;
729
730 CFArrayRemoveValueAtIndex(rlList, i + 2);
731 CFArrayRemoveValueAtIndex(rlList, i + 1);
732 CFArrayRemoveValueAtIndex(rlList, i);
733
734 if (!all) {
735 return found;
736 }
737
738 n -= 3;
739 }
740
741 return found;
742 }
743
744
745 #pragma mark -
746 #pragma mark Bundle
747
748
749 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
750 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH "/System/Library/Frameworks/SystemConfiguration.framework"
751 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
752
753 #define SUFFIX_SYM "~sym"
754 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
755
756 #define SUFFIX_DST "~dst"
757
758
759 CFBundleRef
760 _SC_CFBundleGet(void)
761 {
762 static CFBundleRef bundle = NULL;
763 char *env;
764 size_t len;
765
766 if (bundle != NULL) {
767 return bundle;
768 }
769
770 bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID);
771 if (bundle != NULL) {
772 CFRetain(bundle); // we want to hold a reference to the bundle
773 return bundle;
774 }
775
776 // if appropriate (e.g. when debugging), try a bit harder
777
778 env = getenv("DYLD_FRAMEWORK_PATH");
779 len = (env != NULL) ? strlen(env) : 0;
780
781 // trim any trailing slashes
782 while (len > 1) {
783 if (env[len - 1] != '/') {
784 break;
785 }
786 len--;
787 }
788
789 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst"
790 if ((len > SUFFIX_SYM_LEN) &&
791 (strncmp(&env[len - SUFFIX_SYM_LEN], SUFFIX_SYM, SUFFIX_SYM_LEN) == 0) &&
792 ((len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN) < MAXPATHLEN)) {
793 char path[MAXPATHLEN];
794 CFURLRef url;
795
796 strlcpy(path, env, sizeof(path));
797 strlcpy(&path[len - SUFFIX_SYM_LEN], SUFFIX_DST, sizeof(path) - (len - SUFFIX_SYM_LEN));
798 strlcat(&path[len], SYSTEMCONFIGURATION_FRAMEWORK_PATH, sizeof(path) - len);
799
800 url = CFURLCreateFromFileSystemRepresentation(NULL,
801 (UInt8 *)path,
802 len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN,
803 TRUE);
804 bundle = CFBundleCreate(NULL, url);
805 CFRelease(url);
806 }
807
808 if (bundle == NULL) {
809 static Boolean warned = FALSE;
810
811 SCLog(!warned, LOG_WARNING,
812 CFSTR("_SC_CFBundleGet(), could not get CFBundle for \"%@\""),
813 SYSTEMCONFIGURATION_BUNDLE_ID);
814 warned = TRUE;
815 }
816
817 return bundle;
818 }
819
820
821 CFStringRef
822 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName)
823 {
824 CFStringRef str = NULL;
825 CFURLRef url;
826
827 if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) tableName = CFSTR("Localizable");
828
829 url = CFBundleCopyResourceURLForLocalization(bundle,
830 tableName,
831 CFSTR("strings"),
832 NULL,
833 CFSTR("English"));
834 if (url != NULL) {
835 CFDataRef data = NULL;
836 SInt32 errCode = 0;
837
838 if (CFURLCreateDataAndPropertiesFromResource(NULL,
839 url,
840 &data,
841 NULL,
842 NULL,
843 &errCode)) {
844 CFDictionaryRef table;
845
846 table = CFPropertyListCreateWithData(NULL,
847 data,
848 kCFPropertyListImmutable,
849 NULL,
850 NULL);
851 if (table != NULL) {
852 if (isA_CFDictionary(table)) {
853 str = CFDictionaryGetValue(table, key);
854 if (str != NULL) {
855 CFRetain(str);
856 }
857 }
858
859 CFRelease(table);
860 }
861
862 CFRelease(data);
863 }
864
865 CFRelease(url);
866 }
867
868 if (str == NULL) {
869 str = CFRetain(value);
870 }
871
872 return str;
873 }
874
875
876 #pragma mark -
877 #pragma mark Mach port / CFMachPort management
878
879
880 CFMachPortRef
881 _SC_CFMachPortCreateWithPort(const char *portDescription,
882 mach_port_t portNum,
883 CFMachPortCallBack callout,
884 CFMachPortContext *context)
885 {
886 CFMachPortRef port;
887 Boolean shouldFree = FALSE;
888
889 port = CFMachPortCreateWithPort(NULL, portNum, callout, context, &shouldFree);
890 if ((port == NULL) || shouldFree) {
891 CFStringRef err;
892 char *crash_info = NULL;
893 char name[64] = "";
894
895 SCLog(TRUE, LOG_ERR,
896 CFSTR("%s: CFMachPortCreateWithPort() failed , port = %p"),
897 portDescription,
898 portNum);
899 if (port != NULL) {
900 err = CFStringCreateWithFormat(NULL, NULL,
901 CFSTR("%s: CFMachPortCreateWithPort recycled, [old] port = %@"),
902 portDescription, port);
903 } else {
904 err = CFStringCreateWithFormat(NULL, NULL,
905 CFSTR("%s: CFMachPortCreateWithPort returned NULL"),
906 portDescription);
907 }
908 crash_info = _SC_cfstring_to_cstring(err, NULL, 0, kCFStringEncodingASCII);
909 CFRelease(err);
910
911 (void) proc_name(getpid(), name, sizeof(name));
912 err = CFStringCreateWithFormat(NULL,
913 NULL,
914 CFSTR("A recycled mach_port has been detected by \"%s\"."),
915 name);
916 _SC_crash(crash_info, CFSTR("CFMachPort error"), err);
917 CFAllocatorDeallocate(NULL, crash_info);
918 CFRelease(err);
919 }
920
921 return port;
922 }
923
924
925 #pragma mark -
926 #pragma mark DOS encoding/codepage
927
928
929 #if !TARGET_OS_IPHONE
930 void
931 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding,
932 UInt32 macRegion,
933 CFStringEncoding *dosEncoding,
934 UInt32 *dosCodepage)
935 {
936 switch (macEncoding) {
937 case kCFStringEncodingMacRoman:
938 if (macRegion != 0) /* anything non-zero is not US */
939 *dosEncoding = kCFStringEncodingDOSLatin1;
940 else /* US region */
941 *dosEncoding = kCFStringEncodingDOSLatinUS;
942 break;
943
944 case kCFStringEncodingMacJapanese:
945 *dosEncoding = kCFStringEncodingDOSJapanese;
946 break;
947
948 case kCFStringEncodingMacChineseTrad:
949 *dosEncoding = kCFStringEncodingDOSChineseTrad;
950 break;
951
952 case kCFStringEncodingMacKorean:
953 *dosEncoding = kCFStringEncodingDOSKorean;
954 break;
955
956 case kCFStringEncodingMacArabic:
957 *dosEncoding = kCFStringEncodingDOSArabic;
958 break;
959
960 case kCFStringEncodingMacHebrew:
961 *dosEncoding = kCFStringEncodingDOSHebrew;
962 break;
963
964 case kCFStringEncodingMacGreek:
965 *dosEncoding = kCFStringEncodingDOSGreek;
966 break;
967
968 case kCFStringEncodingMacCyrillic:
969 *dosEncoding = kCFStringEncodingDOSCyrillic;
970 break;
971
972 case kCFStringEncodingMacThai:
973 *dosEncoding = kCFStringEncodingDOSThai;
974 break;
975
976 case kCFStringEncodingMacChineseSimp:
977 *dosEncoding = kCFStringEncodingDOSChineseSimplif;
978 break;
979
980 case kCFStringEncodingMacCentralEurRoman:
981 *dosEncoding = kCFStringEncodingDOSLatin2;
982 break;
983
984 case kCFStringEncodingMacTurkish:
985 *dosEncoding = kCFStringEncodingDOSTurkish;
986 break;
987
988 case kCFStringEncodingMacCroatian:
989 *dosEncoding = kCFStringEncodingDOSLatin2;
990 break;
991
992 case kCFStringEncodingMacIcelandic:
993 *dosEncoding = kCFStringEncodingDOSIcelandic;
994 break;
995
996 case kCFStringEncodingMacRomanian:
997 *dosEncoding = kCFStringEncodingDOSLatin2;
998 break;
999
1000 case kCFStringEncodingMacFarsi:
1001 *dosEncoding = kCFStringEncodingDOSArabic;
1002 break;
1003
1004 case kCFStringEncodingMacUkrainian:
1005 *dosEncoding = kCFStringEncodingDOSCyrillic;
1006 break;
1007
1008 default:
1009 *dosEncoding = kCFStringEncodingDOSLatin1;
1010 break;
1011 }
1012
1013 *dosCodepage = CFStringConvertEncodingToWindowsCodepage(*dosEncoding);
1014 return;
1015 }
1016 #endif // !TARGET_OS_IPHONE
1017
1018
1019 #pragma mark -
1020 #pragma mark Debugging
1021
1022
1023 /*
1024 * print status of in-use mach ports
1025 */
1026 void
1027 _SC_logMachPortStatus(void)
1028 {
1029 kern_return_t status;
1030 mach_port_name_array_t ports;
1031 mach_port_type_array_t types;
1032 mach_msg_type_number_t pi, pn, tn;
1033 CFMutableStringRef str;
1034
1035 SCLog(TRUE, LOG_NOTICE, CFSTR("----------"));
1036
1037 /* report on ALL mach ports associated with this task */
1038 status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn);
1039 if (status == MACH_MSG_SUCCESS) {
1040 str = CFStringCreateMutable(NULL, 0);
1041 for (pi = 0; pi < pn; pi++) {
1042 char rights[16], *rp = &rights[0];
1043
1044 if (types[pi] != MACH_PORT_TYPE_NONE) {
1045 *rp++ = ' ';
1046 *rp++ = '(';
1047 if (types[pi] & MACH_PORT_TYPE_SEND)
1048 *rp++ = 'S';
1049 if (types[pi] & MACH_PORT_TYPE_RECEIVE)
1050 *rp++ = 'R';
1051 if (types[pi] & MACH_PORT_TYPE_SEND_ONCE)
1052 *rp++ = 'O';
1053 if (types[pi] & MACH_PORT_TYPE_PORT_SET)
1054 *rp++ = 'P';
1055 if (types[pi] & MACH_PORT_TYPE_DEAD_NAME)
1056 *rp++ = 'D';
1057 *rp++ = ')';
1058 }
1059 *rp = '\0';
1060 CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights);
1061 }
1062 SCLog(TRUE, LOG_NOTICE, CFSTR("Task ports (n=%d):%@"), pn, str);
1063 CFRelease(str);
1064 }
1065
1066 return;
1067 }
1068
1069
1070 void
1071 _SC_logMachPortReferences(const char *str, mach_port_t port)
1072 {
1073 const char *blanks = " ";
1074 char buf[60];
1075 mach_port_type_t pt;
1076 mach_port_status_t recv_status = { 0 };
1077 mach_port_urefs_t refs_send = 0;
1078 mach_port_urefs_t refs_recv = 0;
1079 mach_port_urefs_t refs_once = 0;
1080 mach_port_urefs_t refs_pset = 0;
1081 mach_port_urefs_t refs_dead = 0;
1082 kern_return_t status;
1083
1084 buf[0] = '\0';
1085 if (str != NULL) {
1086 static int is_configd = -1;
1087
1088 if (is_configd == -1) {
1089 char name[64] = "";
1090
1091 (void) proc_name(getpid(), name, sizeof(name));
1092 is_configd = (strncmp(name, "configd", sizeof(name)) == 0);
1093 }
1094 if (is_configd == 1) {
1095 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1096 strlcpy(buf,
1097 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1098 sizeof(buf));
1099 }
1100
1101 // add provided string
1102 strlcat(buf, str, sizeof(buf));
1103
1104 // fill
1105 strlcat(buf, blanks, sizeof(buf));
1106 if (strcmp(&buf[sizeof(buf) - 3], " ") == 0) {
1107 buf[sizeof(buf) - 3] = ':';
1108 }
1109 }
1110
1111 status = mach_port_type(mach_task_self(), port, &pt);
1112 if (status != KERN_SUCCESS) {
1113 SCLog(TRUE, LOG_NOTICE,
1114 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"),
1115 buf,
1116 port,
1117 mach_error_string(status));
1118 }
1119
1120 if ((pt & MACH_PORT_TYPE_SEND) != 0) {
1121 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs_send);
1122 if (status != KERN_SUCCESS) {
1123 SCLog(TRUE, LOG_NOTICE,
1124 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"),
1125 buf,
1126 port,
1127 mach_error_string(status));
1128 }
1129 }
1130
1131 if ((pt & MACH_PORT_TYPE_RECEIVE) != 0) {
1132 mach_msg_type_number_t count;
1133
1134 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, &refs_recv);
1135 if (status != KERN_SUCCESS) {
1136 SCLog(TRUE, LOG_NOTICE,
1137 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_RECEIVE): %s"),
1138 buf,
1139 port,
1140 mach_error_string(status));
1141 }
1142
1143 count = MACH_PORT_RECEIVE_STATUS_COUNT;
1144 status = mach_port_get_attributes(mach_task_self(),
1145 port,
1146 MACH_PORT_RECEIVE_STATUS,
1147 (mach_port_info_t)&recv_status,
1148 &count);
1149 if (status != KERN_SUCCESS) {
1150 SCLog(TRUE, LOG_NOTICE,
1151 CFSTR("%mach_port_get_attributes(..., %d, MACH_PORT_RECEIVE_STATUS): %s"),
1152 buf,
1153 port,
1154 mach_error_string(status));
1155 }
1156 }
1157
1158 if ((pt & MACH_PORT_TYPE_SEND_ONCE) != 0) {
1159 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once);
1160 if (status != KERN_SUCCESS) {
1161 SCLog(TRUE, LOG_NOTICE,
1162 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND_ONCE): %s"),
1163 buf,
1164 port,
1165 mach_error_string(status));
1166 }
1167 }
1168
1169 if ((pt & MACH_PORT_TYPE_PORT_SET) != 0) {
1170 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, &refs_pset);
1171 if (status != KERN_SUCCESS) {
1172 SCLog(TRUE, LOG_NOTICE,
1173 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_PORT_SET): %s"),
1174 buf,
1175 port,
1176 mach_error_string(status));
1177 }
1178 }
1179
1180 if ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) {
1181 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead);
1182 if (status != KERN_SUCCESS) {
1183 SCLog(TRUE, LOG_NOTICE,
1184 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_DEAD_NAME): %s"),
1185 buf,
1186 port,
1187 mach_error_string(status));
1188 }
1189 }
1190
1191 SCLog(TRUE, LOG_NOTICE,
1192 CFSTR("%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s"),
1193 buf,
1194 port,
1195 port,
1196 refs_send,
1197 refs_recv,
1198 refs_once,
1199 refs_pset,
1200 refs_dead,
1201 recv_status.mps_nsrequest ? ", no more senders" : "",
1202 ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) ? ", dead name request" : "");
1203
1204 return;
1205 }
1206
1207
1208 CFStringRef
1209 _SC_copyBacktrace()
1210 {
1211 int n;
1212 void *stack[64];
1213 char **symbols;
1214 CFMutableStringRef trace;
1215
1216 n = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
1217 if (n == -1) {
1218 SCLog(TRUE, LOG_ERR, CFSTR("backtrace() failed: %s"), strerror(errno));
1219 return NULL;
1220 }
1221
1222 trace = CFStringCreateMutable(NULL, 0);
1223
1224 symbols = backtrace_symbols(stack, n);
1225 if (symbols != NULL) {
1226 int i;
1227
1228 for (i = 0; i < n; i++) {
1229 CFStringAppendFormat(trace, NULL, CFSTR("%s\n"), symbols[i]);
1230 }
1231
1232 free(symbols);
1233 }
1234
1235 return trace;
1236 }
1237
1238
1239 /* CrashReporter info */
1240 const char *__crashreporter_info__ = NULL;
1241 asm(".desc ___crashreporter_info__, 0x10");
1242
1243
1244 static Boolean
1245 _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1246 {
1247 static bool (*dyfunc_SimulateCrash)(pid_t, mach_exception_data_type_t, CFStringRef) = NULL;
1248 static void *image = NULL;
1249 Boolean ok = FALSE;
1250
1251 if ((dyfunc_SimulateCrash == NULL) && (image == NULL)) {
1252 const char *framework = "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/"
1253 #if !TARGET_OS_EMBEDDED
1254 "Versions/A/"
1255 #endif // !TARGET_OS_EMBEDDED
1256 "CrashReporterSupport";
1257 struct stat statbuf;
1258 const char *suffix = getenv("DYLD_IMAGE_SUFFIX");
1259 char path[MAXPATHLEN];
1260
1261 strlcpy(path, framework, sizeof(path));
1262 if (suffix) strlcat(path, suffix, sizeof(path));
1263 if (0 <= stat(path, &statbuf)) {
1264 image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
1265 } else {
1266 image = dlopen(framework, RTLD_LAZY | RTLD_LOCAL);
1267 }
1268
1269 if (image != NULL) {
1270 dyfunc_SimulateCrash = dlsym(image, "SimulateCrash");
1271 } else {
1272 image = (void *)0x1; // to ensure that we only dlopen() once
1273 }
1274 }
1275
1276 if (dyfunc_SimulateCrash != NULL) {
1277 CFStringRef str;
1278
1279 str = CFStringCreateWithCString(NULL, crash_info, kCFStringEncodingUTF8);
1280 ok = dyfunc_SimulateCrash(getpid(), 0xbad0005cull, str);
1281 CFRelease(str);
1282 }
1283
1284 #if TARGET_OS_EMBEDDED && !TARGET_OS_EMBEDDED_OTHER && !defined(DO_NOT_INFORM)
1285 if (ok) {
1286 static Boolean warned = FALSE;
1287
1288 if (!warned) {
1289 notifyMessage = CFStringCreateWithFormat(NULL,
1290 NULL,
1291 CFSTR("%@\n\nPlease collect the crash report and file a Radar."),
1292 notifyMessage);
1293 CFUserNotificationDisplayNotice(0,
1294 kCFUserNotificationStopAlertLevel,
1295 NULL,
1296 NULL,
1297 NULL,
1298 notifyHeader,
1299 notifyMessage,
1300 NULL);
1301 CFRelease(notifyMessage);
1302 warned = TRUE;
1303 }
1304 }
1305 #endif // TARGET_OS_EMBEDDED && !TARGET_OS_EMBEDDED_OTHER && !defined(DO_NOT_INFORM)
1306
1307 return ok;
1308 }
1309
1310
1311 void
1312 _SC_crash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage)
1313 {
1314 Boolean ok = FALSE;
1315
1316 if (crash_info != NULL) {
1317 __crashreporter_info__ = crash_info;
1318
1319 SCLog(TRUE, LOG_ERR, CFSTR("%s"), crash_info);
1320 }
1321
1322 if (_SC_isAppleInternal()) {
1323 // simulate a crash report
1324 ok = _SC_SimulateCrash(crash_info, notifyHeader, notifyMessage);
1325 #ifndef DO_NOT_CRASH
1326 if (!ok) {
1327 // if we could not simulate a crash report, crash for real
1328 __builtin_trap();
1329 }
1330 #endif // DO_NOT_CRASH
1331 }
1332
1333 __crashreporter_info__ = NULL;
1334 return;
1335 }