]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDPrivate.c
configd-293.4.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDPrivate.c
1 /*
2 * Copyright (c) 2000-2009 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 #include <SystemConfiguration/SystemConfiguration.h>
35 #include <SystemConfiguration/SCValidation.h>
36 #include <SystemConfiguration/SCPrivate.h>
37
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <net/if_dl.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45
46 #include <mach/mach.h>
47 #include <mach/notify.h>
48 #include <mach/mach_error.h>
49 #include <pthread.h>
50
51 #include <execinfo.h>
52 #include <libproc.h>
53 #include <unistd.h>
54
55 #define N_QUICK 32
56
57
58 #pragma mark -
59 #pragma mark Miscellaneous
60
61
62 char *
63 _SC_cfstring_to_cstring(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEncoding encoding)
64 {
65 CFIndex converted;
66 CFIndex last = 0;
67 CFIndex len;
68
69 if (cfstr == NULL) {
70 cfstr = CFSTR("");
71 }
72 len = CFStringGetLength(cfstr);
73
74 /* how much buffer space will we really need? */
75 converted = CFStringGetBytes(cfstr,
76 CFRangeMake(0, len),
77 encoding,
78 0,
79 FALSE,
80 NULL,
81 0,
82 &last);
83 if (converted < len) {
84 /* if full string could not be converted */
85 if (buf != NULL) {
86 buf[0] = '\0';
87 }
88 return NULL;
89 }
90
91 if (buf != NULL) {
92 if (bufLen < (last + 1)) {
93 /* if the size of the provided buffer is too small */
94 buf[0] = '\0';
95 return NULL;
96 }
97 } else {
98 /* allocate a buffer */
99 bufLen = last + 1;
100 buf = CFAllocatorAllocate(NULL, bufLen, 0);
101 if (buf == NULL) {
102 return NULL;
103 }
104 }
105
106 (void)CFStringGetBytes(cfstr,
107 CFRangeMake(0, len),
108 encoding,
109 0,
110 FALSE,
111 (UInt8 *)buf,
112 bufLen,
113 &last);
114 buf[last] = '\0';
115
116 return buf;
117 }
118
119
120 void
121 _SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen)
122 {
123 bzero(buf, bufLen);
124 switch (address->sa_family) {
125 case AF_INET :
126 (void)inet_ntop(((struct sockaddr_in *)address)->sin_family,
127 &((struct sockaddr_in *)address)->sin_addr,
128 buf,
129 bufLen);
130 break;
131 case AF_INET6 : {
132 (void)inet_ntop(((struct sockaddr_in6 *)address)->sin6_family,
133 &((struct sockaddr_in6 *)address)->sin6_addr,
134 buf,
135 bufLen);
136 if (((struct sockaddr_in6 *)address)->sin6_scope_id != 0) {
137 int n;
138
139 n = strlen(buf);
140 if ((n+IF_NAMESIZE+1) <= (int)bufLen) {
141 buf[n++] = '%';
142 if_indextoname(((struct sockaddr_in6 *)address)->sin6_scope_id, &buf[n]);
143 }
144 }
145 break;
146 }
147 case AF_LINK :
148 if (((struct sockaddr_dl *)address)->sdl_len < bufLen) {
149 bufLen = ((struct sockaddr_dl *)address)->sdl_len;
150 } else {
151 bufLen = bufLen - 1;
152 }
153
154 bcopy(((struct sockaddr_dl *)address)->sdl_data, buf, bufLen);
155 break;
156 default :
157 snprintf(buf, bufLen, "unexpected address family %d", address->sa_family);
158 break;
159 }
160
161 return;
162 }
163
164
165 void
166 _SC_sendMachMessage(mach_port_t port, mach_msg_id_t msg_id)
167 {
168 mach_msg_empty_send_t msg;
169 mach_msg_option_t options;
170 kern_return_t status;
171
172 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
173 msg.header.msgh_size = sizeof(msg);
174 msg.header.msgh_remote_port = port;
175 msg.header.msgh_local_port = MACH_PORT_NULL;
176 msg.header.msgh_id = msg_id;
177 options = MACH_SEND_TIMEOUT;
178 status = mach_msg(&msg.header, /* msg */
179 MACH_SEND_MSG|options, /* options */
180 msg.header.msgh_size, /* send_size */
181 0, /* rcv_size */
182 MACH_PORT_NULL, /* rcv_name */
183 0, /* timeout */
184 MACH_PORT_NULL); /* notify */
185 if (status == MACH_SEND_TIMED_OUT) {
186 mach_msg_destroy(&msg.header);
187 }
188
189 return;
190 }
191
192
193 #pragma mark -
194 #pragma mark Serialization
195
196
197 Boolean
198 _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dataLen)
199 {
200 CFDataRef myXml;
201 CFWriteStreamRef stream;
202
203 if ((xml == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
204 /* if not keeping track of allocated space */
205 return FALSE;
206 }
207
208 stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL);
209 CFWriteStreamOpen(stream);
210 CFPropertyListWriteToStream(obj, stream, kCFPropertyListBinaryFormat_v1_0, NULL);
211 CFWriteStreamClose(stream);
212 myXml = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten);
213 CFRelease(stream);
214 if (myXml == NULL) {
215 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerialize() failed"));
216 if (xml != NULL) {
217 *xml = NULL;
218 }
219 if ((dataRef != NULL) && (dataLen != NULL)) {
220 *dataLen = 0;
221 *dataRef = NULL;
222 }
223 return FALSE;
224 }
225
226 if (xml != NULL) {
227 *xml = myXml;
228 if ((dataRef != NULL) && (dataLen != NULL)) {
229 *dataRef = (void *)CFDataGetBytePtr(myXml);
230 *dataLen = CFDataGetLength(myXml);
231 }
232 } else {
233 mach_msg_type_number_t len;
234 kern_return_t status;
235
236 status = vm_read(mach_task_self(),
237 (vm_address_t)CFDataGetBytePtr(myXml), // address
238 (vm_size_t) CFDataGetLength(myXml), // size
239 (void *)dataRef,
240 &len);
241 if (status != KERN_SUCCESS) {
242 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerialize(): %s"), mach_error_string(status));
243 CFRelease(myXml);
244 *dataRef = NULL;
245 *dataLen = 0;
246 return FALSE;
247 }
248
249 *dataLen = len;
250 CFRelease(myXml);
251 }
252
253 return TRUE;
254 }
255
256
257 Boolean
258 _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen)
259 {
260 CFStringRef xmlError;
261
262 if (xml == NULL) {
263 kern_return_t status;
264
265 xml = CFDataCreateWithBytesNoCopy(NULL, (void *)dataRef, dataLen, kCFAllocatorNull);
266 *obj = CFPropertyListCreateFromXMLData(NULL,
267 xml,
268 kCFPropertyListImmutable,
269 &xmlError);
270 CFRelease(xml);
271
272 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
273 if (status != KERN_SUCCESS) {
274 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserialize(): %s"), mach_error_string(status));
275 /* non-fatal???, proceed */
276 }
277 } else {
278 *obj = CFPropertyListCreateFromXMLData(NULL,
279 xml,
280 kCFPropertyListImmutable,
281 &xmlError);
282 }
283
284 if (*obj == NULL) {
285 if (xmlError != NULL) {
286 SCLog(TRUE, LOG_ERR, CFSTR("_SCUnserialize(): %@"), xmlError);
287 CFRelease(xmlError);
288 }
289 _SCErrorSet(kSCStatusFailed);
290 return FALSE;
291 }
292
293 return TRUE;
294 }
295
296
297 Boolean
298 _SCSerializeString(CFStringRef str, CFDataRef *data, void **dataRef, CFIndex *dataLen)
299 {
300 CFDataRef myData;
301
302 if (!isA_CFString(str)) {
303 /* if not a CFString */
304 return FALSE;
305 }
306
307 if ((data == NULL) && ((dataRef == NULL) || (dataLen == NULL))) {
308 /* if not keeping track of allocated space */
309 return FALSE;
310 }
311
312 myData = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
313 if (myData == NULL) {
314 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeString() failed"));
315 if (data != NULL) {
316 *data = NULL;
317 }
318 if ((dataRef != NULL) && (dataLen != NULL)) {
319 *dataRef = NULL;
320 *dataLen = 0;
321 }
322 return FALSE;
323 }
324
325 if (data != NULL) {
326 *data = myData;
327 if ((dataRef != NULL) && (dataLen != NULL)) {
328 *dataRef = (void *)CFDataGetBytePtr(myData);
329 *dataLen = CFDataGetLength(myData);
330 }
331 } else {
332 mach_msg_type_number_t len;
333 kern_return_t status;
334
335 *dataLen = CFDataGetLength(myData);
336 status = vm_read(mach_task_self(),
337 (vm_address_t)CFDataGetBytePtr(myData), // address
338 *dataLen, // size
339 (void *)dataRef,
340 &len);
341 if (status != KERN_SUCCESS) {
342 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeString(): %s"), mach_error_string(status));
343 CFRelease(myData);
344 *dataRef = NULL;
345 *dataLen = 0;
346 return FALSE;
347 }
348
349 *dataLen = len;
350 CFRelease(myData);
351 }
352
353 return TRUE;
354 }
355
356
357 Boolean
358 _SCUnserializeString(CFStringRef *str, CFDataRef utf8, void *dataRef, CFIndex dataLen)
359 {
360 if (utf8 == NULL) {
361 kern_return_t status;
362
363 utf8 = CFDataCreateWithBytesNoCopy(NULL, dataRef, dataLen, kCFAllocatorNull);
364 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
365 CFRelease(utf8);
366
367 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
368 if (status != KERN_SUCCESS) {
369 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserializeString(): %s"), mach_error_string(status));
370 /* non-fatal???, proceed */
371 }
372 } else {
373 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
374 }
375
376 if (*str == NULL) {
377 SCLog(TRUE, LOG_ERR, CFSTR("_SCUnserializeString() failed"));
378 return FALSE;
379 }
380
381 return TRUE;
382 }
383
384
385 Boolean
386 _SCSerializeData(CFDataRef data, void **dataRef, CFIndex *dataLen)
387 {
388 mach_msg_type_number_t len;
389 kern_return_t status;
390
391 if (!isA_CFData(data)) {
392 /* if not a CFData */
393 return FALSE;
394 }
395
396 *dataLen = CFDataGetLength(data);
397 status = vm_read(mach_task_self(),
398 (vm_address_t)CFDataGetBytePtr(data), // address
399 *dataLen, // size
400 (void *)dataRef,
401 &len);
402 if (status != KERN_SUCCESS) {
403 SCLog(TRUE, LOG_ERR, CFSTR("_SCSerializeData(): %s"), mach_error_string(status));
404 *dataRef = NULL;
405 *dataLen = 0;
406 return FALSE;
407 }
408
409 *dataLen = len;
410
411 return TRUE;
412 }
413
414
415 Boolean
416 _SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen)
417 {
418 kern_return_t status;
419
420 *data = CFDataCreate(NULL, dataRef, dataLen);
421 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
422 if (status != KERN_SUCCESS) {
423 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCUnserializeData(): %s"), mach_error_string(status));
424 _SCErrorSet(kSCStatusFailed);
425 return FALSE;
426 }
427
428 return TRUE;
429 }
430
431
432 CFDictionaryRef
433 _SCSerializeMultiple(CFDictionaryRef dict)
434 {
435 const void * keys_q[N_QUICK];
436 const void ** keys = keys_q;
437 CFIndex nElements;
438 CFDictionaryRef newDict = NULL;
439 const void * pLists_q[N_QUICK];
440 const void ** pLists = pLists_q;
441 const void * values_q[N_QUICK];
442 const void ** values = values_q;
443
444 nElements = CFDictionaryGetCount(dict);
445 if (nElements > 0) {
446 CFIndex i;
447
448 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
449 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
450 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
451 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
452 }
453 bzero(pLists, nElements * sizeof(CFTypeRef));
454
455 CFDictionaryGetKeysAndValues(dict, keys, values);
456 for (i = 0; i < nElements; i++) {
457 if (!_SCSerialize((CFPropertyListRef)values[i], (CFDataRef *)&pLists[i], NULL, NULL)) {
458 goto done;
459 }
460 }
461 }
462
463 newDict = CFDictionaryCreate(NULL,
464 keys,
465 pLists,
466 nElements,
467 &kCFTypeDictionaryKeyCallBacks,
468 &kCFTypeDictionaryValueCallBacks);
469
470 done :
471
472 if (nElements > 0) {
473 CFIndex i;
474
475 for (i = 0; i < nElements; i++) {
476 if (pLists[i]) CFRelease(pLists[i]);
477 }
478
479 if (keys != keys_q) {
480 CFAllocatorDeallocate(NULL, keys);
481 CFAllocatorDeallocate(NULL, values);
482 CFAllocatorDeallocate(NULL, pLists);
483 }
484 }
485
486 return newDict;
487 }
488
489
490 CFDictionaryRef
491 _SCUnserializeMultiple(CFDictionaryRef dict)
492 {
493 const void * keys_q[N_QUICK];
494 const void ** keys = keys_q;
495 CFIndex nElements;
496 CFDictionaryRef newDict = NULL;
497 const void * pLists_q[N_QUICK];
498 const void ** pLists = pLists_q;
499 const void * values_q[N_QUICK];
500 const void ** values = values_q;
501
502 nElements = CFDictionaryGetCount(dict);
503 if (nElements > 0) {
504 CFIndex i;
505
506 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
507 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
508 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
509 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
510 }
511 bzero(pLists, nElements * sizeof(CFTypeRef));
512
513 CFDictionaryGetKeysAndValues(dict, keys, values);
514 for (i = 0; i < nElements; i++) {
515 if (!_SCUnserialize((CFPropertyListRef *)&pLists[i], values[i], NULL, 0)) {
516 goto done;
517 }
518 }
519 }
520
521 newDict = CFDictionaryCreate(NULL,
522 keys,
523 pLists,
524 nElements,
525 &kCFTypeDictionaryKeyCallBacks,
526 &kCFTypeDictionaryValueCallBacks);
527
528 done :
529
530 if (nElements > 0) {
531 CFIndex i;
532
533 for (i = 0; i < nElements; i++) {
534 if (pLists[i]) CFRelease(pLists[i]);
535 }
536
537 if (keys != keys_q) {
538 CFAllocatorDeallocate(NULL, keys);
539 CFAllocatorDeallocate(NULL, values);
540 CFAllocatorDeallocate(NULL, pLists);
541 }
542 }
543
544 return newDict;
545 }
546
547
548 #pragma mark -
549 #pragma mark CFRunLoop scheduling
550
551
552 __private_extern__ void
553 _SC_signalRunLoop(CFTypeRef obj, CFRunLoopSourceRef rls, CFArrayRef rlList)
554 {
555 CFRunLoopRef rl = NULL;
556 CFRunLoopRef rl1 = NULL;
557 CFIndex i;
558 CFIndex n = CFArrayGetCount(rlList);
559
560 if (n == 0) {
561 return;
562 }
563
564 /* get first runLoop for this object */
565 for (i = 0; i < n; i += 3) {
566 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
567 continue;
568 }
569
570 rl1 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
571 break;
572 }
573
574 if (rl1 == NULL) {
575 /* if not scheduled */
576 return;
577 }
578
579 /* check if we have another runLoop for this object */
580 rl = rl1;
581 for (i = i+3; i < n; i += 3) {
582 CFRunLoopRef rl2;
583
584 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
585 continue;
586 }
587
588 rl2 = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
589 if (!CFEqual(rl1, rl2)) {
590 /* we've got more than one runLoop */
591 rl = NULL;
592 break;
593 }
594 }
595
596 if (rl != NULL) {
597 /* if we only have one runLoop */
598 CFRunLoopWakeUp(rl);
599 return;
600 }
601
602 /* more than one different runLoop, so we must pick one */
603 for (i = 0; i < n; i+=3) {
604 CFStringRef rlMode;
605
606 if (!CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
607 continue;
608 }
609
610 rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlList, i+1);
611 rlMode = CFRunLoopCopyCurrentMode(rl);
612 if (rlMode != NULL) {
613 Boolean waiting;
614
615 waiting = (CFRunLoopIsWaiting(rl) && CFRunLoopContainsSource(rl, rls, rlMode));
616 CFRelease(rlMode);
617 if (waiting) {
618 /* we've found a runLoop that's "ready" */
619 CFRunLoopWakeUp(rl);
620 return;
621 }
622 }
623 }
624
625 /* didn't choose one above, so choose first */
626 CFRunLoopWakeUp(rl1);
627 return;
628 }
629
630
631 __private_extern__ Boolean
632 _SC_isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
633 {
634 CFIndex i;
635 CFIndex n = CFArrayGetCount(rlList);
636
637 for (i = 0; i < n; i += 3) {
638 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
639 continue;
640 }
641 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
642 continue;
643 }
644 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
645 continue;
646 }
647 return TRUE;
648 }
649
650 return FALSE;
651 }
652
653
654 __private_extern__ void
655 _SC_schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
656 {
657 CFArrayAppendValue(rlList, obj);
658 CFArrayAppendValue(rlList, runLoop);
659 CFArrayAppendValue(rlList, runLoopMode);
660
661 return;
662 }
663
664
665 __private_extern__ Boolean
666 _SC_unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all)
667 {
668 CFIndex i = 0;
669 Boolean found = FALSE;
670 CFIndex n = CFArrayGetCount(rlList);
671
672 while (i < n) {
673 if ((obj != NULL) && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
674 i += 3;
675 continue;
676 }
677 if ((runLoop != NULL) && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
678 i += 3;
679 continue;
680 }
681 if ((runLoopMode != NULL) && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
682 i += 3;
683 continue;
684 }
685
686 found = TRUE;
687
688 CFArrayRemoveValueAtIndex(rlList, i + 2);
689 CFArrayRemoveValueAtIndex(rlList, i + 1);
690 CFArrayRemoveValueAtIndex(rlList, i);
691
692 if (!all) {
693 return found;
694 }
695
696 n -= 3;
697 }
698
699 return found;
700 }
701
702
703 #pragma mark -
704 #pragma mark Bundle
705
706
707 #define SYSTEMCONFIGURATION_BUNDLE_ID CFSTR("com.apple.SystemConfiguration")
708 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH "/System/Library/Frameworks/SystemConfiguration.framework"
709 #define SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN (sizeof(SYSTEMCONFIGURATION_FRAMEWORK_PATH) - 1)
710
711 #define SUFFIX_SYM "~sym"
712 #define SUFFIX_SYM_LEN (sizeof(SUFFIX_SYM) - 1)
713
714 #define SUFFIX_DST "~dst"
715
716
717 CFBundleRef
718 _SC_CFBundleGet(void)
719 {
720 static CFBundleRef bundle = NULL;
721 char *env;
722 size_t len;
723
724 if (bundle != NULL) {
725 return bundle;
726 }
727
728 bundle = CFBundleGetBundleWithIdentifier(SYSTEMCONFIGURATION_BUNDLE_ID);
729 if (bundle != NULL) {
730 CFRetain(bundle); // we want to hold a reference to the bundle
731 return bundle;
732 }
733
734 // if appropriate (e.g. when debugging), try a bit harder
735
736 env = getenv("DYLD_FRAMEWORK_PATH");
737 len = (env != NULL) ? strlen(env) : 0;
738
739 // trim any trailing slashes
740 while (len > 1) {
741 if (env[len - 1] != '/') {
742 break;
743 }
744 len--;
745 }
746
747 // if DYLD_FRAMEWORK_PATH is ".../xxx~sym" than try ".../xxx~dst"
748 if ((len > SUFFIX_SYM_LEN) &&
749 (strncmp(&env[len - SUFFIX_SYM_LEN], SUFFIX_SYM, SUFFIX_SYM_LEN) == 0) &&
750 ((len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN) < MAXPATHLEN)) {
751 char path[MAXPATHLEN];
752 CFURLRef url;
753
754 strlcpy(path, env, sizeof(path));
755 strlcpy(&path[len - SUFFIX_SYM_LEN], SUFFIX_DST, sizeof(path) - (len - SUFFIX_SYM_LEN));
756 strlcat(&path[len], SYSTEMCONFIGURATION_FRAMEWORK_PATH, sizeof(path) - len);
757
758 url = CFURLCreateFromFileSystemRepresentation(NULL,
759 (UInt8 *)path,
760 len + SYSTEMCONFIGURATION_FRAMEWORK_PATH_LEN,
761 TRUE);
762 bundle = CFBundleCreate(NULL, url);
763 CFRelease(url);
764 }
765
766 if (bundle == NULL) {
767 static Boolean warned = FALSE;
768
769 SCLog(!warned, LOG_WARNING,
770 CFSTR("_SC_CFBundleGet(), could not get CFBundle for \"%@\""),
771 SYSTEMCONFIGURATION_BUNDLE_ID);
772 warned = TRUE;
773 }
774
775 return bundle;
776 }
777
778
779 CFStringRef
780 _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName)
781 {
782 CFStringRef str = NULL;
783 CFURLRef url;
784
785 if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) tableName = CFSTR("Localizable");
786
787 url = CFBundleCopyResourceURLForLocalization(bundle,
788 tableName,
789 CFSTR("strings"),
790 NULL,
791 CFSTR("English"));
792 if (url != NULL) {
793 CFDataRef data = NULL;
794 SInt32 errCode = 0;
795
796 if (CFURLCreateDataAndPropertiesFromResource(NULL,
797 url,
798 &data,
799 NULL,
800 NULL,
801 &errCode)) {
802 CFDictionaryRef table;
803
804 table = (CFDictionaryRef)CFPropertyListCreateFromXMLData(NULL,
805 data,
806 kCFPropertyListImmutable,
807 NULL);
808 if (table != NULL) {
809 if (isA_CFDictionary(table)) {
810 str = CFDictionaryGetValue(table, key);
811 if (str != NULL) {
812 CFRetain(str);
813 }
814 }
815
816 CFRelease(table);
817 }
818
819 CFRelease(data);
820 }
821
822 CFRelease(url);
823 }
824
825 if (str == NULL) {
826 str = CFRetain(value);
827 }
828
829 return str;
830 }
831
832
833 #pragma mark -
834 #pragma mark DOS encoding/codepage
835
836
837 #if !TARGET_OS_IPHONE
838 void
839 _SC_dos_encoding_and_codepage(CFStringEncoding macEncoding,
840 UInt32 macRegion,
841 CFStringEncoding *dosEncoding,
842 UInt32 *dosCodepage)
843 {
844 switch (macEncoding) {
845 case kCFStringEncodingMacRoman:
846 if (macRegion != 0) /* anything non-zero is not US */
847 *dosEncoding = kCFStringEncodingDOSLatin1;
848 else /* US region */
849 *dosEncoding = kCFStringEncodingDOSLatinUS;
850 break;
851
852 case kCFStringEncodingMacJapanese:
853 *dosEncoding = kCFStringEncodingDOSJapanese;
854 break;
855
856 case kCFStringEncodingMacChineseTrad:
857 *dosEncoding = kCFStringEncodingDOSChineseTrad;
858 break;
859
860 case kCFStringEncodingMacKorean:
861 *dosEncoding = kCFStringEncodingDOSKorean;
862 break;
863
864 case kCFStringEncodingMacArabic:
865 *dosEncoding = kCFStringEncodingDOSArabic;
866 break;
867
868 case kCFStringEncodingMacHebrew:
869 *dosEncoding = kCFStringEncodingDOSHebrew;
870 break;
871
872 case kCFStringEncodingMacGreek:
873 *dosEncoding = kCFStringEncodingDOSGreek;
874 break;
875
876 case kCFStringEncodingMacCyrillic:
877 *dosEncoding = kCFStringEncodingDOSCyrillic;
878 break;
879
880 case kCFStringEncodingMacThai:
881 *dosEncoding = kCFStringEncodingDOSThai;
882 break;
883
884 case kCFStringEncodingMacChineseSimp:
885 *dosEncoding = kCFStringEncodingDOSChineseSimplif;
886 break;
887
888 case kCFStringEncodingMacCentralEurRoman:
889 *dosEncoding = kCFStringEncodingDOSLatin2;
890 break;
891
892 case kCFStringEncodingMacTurkish:
893 *dosEncoding = kCFStringEncodingDOSTurkish;
894 break;
895
896 case kCFStringEncodingMacCroatian:
897 *dosEncoding = kCFStringEncodingDOSLatin2;
898 break;
899
900 case kCFStringEncodingMacIcelandic:
901 *dosEncoding = kCFStringEncodingDOSIcelandic;
902 break;
903
904 case kCFStringEncodingMacRomanian:
905 *dosEncoding = kCFStringEncodingDOSLatin2;
906 break;
907
908 case kCFStringEncodingMacFarsi:
909 *dosEncoding = kCFStringEncodingDOSArabic;
910 break;
911
912 case kCFStringEncodingMacUkrainian:
913 *dosEncoding = kCFStringEncodingDOSCyrillic;
914 break;
915
916 default:
917 *dosEncoding = kCFStringEncodingDOSLatin1;
918 break;
919 }
920
921 *dosCodepage = CFStringConvertEncodingToWindowsCodepage(*dosEncoding);
922 return;
923 }
924 #endif // !TARGET_OS_IPHONE
925
926
927 #pragma mark -
928 #pragma mark Debugging
929
930
931 /*
932 * print status of in-use mach ports
933 */
934 void
935 _SC_logMachPortStatus(void)
936 {
937 kern_return_t status;
938 mach_port_name_array_t ports;
939 mach_port_type_array_t types;
940 mach_msg_type_number_t pi, pn, tn;
941 CFMutableStringRef str;
942
943 SCLog(TRUE, LOG_DEBUG, CFSTR("----------"));
944
945 /* report on ALL mach ports associated with this task */
946 status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn);
947 if (status == MACH_MSG_SUCCESS) {
948 str = CFStringCreateMutable(NULL, 0);
949 for (pi = 0; pi < pn; pi++) {
950 char rights[16], *rp = &rights[0];
951
952 if (types[pi] != MACH_PORT_TYPE_NONE) {
953 *rp++ = ' ';
954 *rp++ = '(';
955 if (types[pi] & MACH_PORT_TYPE_SEND)
956 *rp++ = 'S';
957 if (types[pi] & MACH_PORT_TYPE_RECEIVE)
958 *rp++ = 'R';
959 if (types[pi] & MACH_PORT_TYPE_SEND_ONCE)
960 *rp++ = 'O';
961 if (types[pi] & MACH_PORT_TYPE_PORT_SET)
962 *rp++ = 'P';
963 if (types[pi] & MACH_PORT_TYPE_DEAD_NAME)
964 *rp++ = 'D';
965 *rp++ = ')';
966 }
967 *rp = '\0';
968 CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights);
969 }
970 SCLog(TRUE, LOG_DEBUG, CFSTR("Task ports (n=%d):%@"), pn, str);
971 CFRelease(str);
972 }
973
974 return;
975 }
976
977
978 void
979 _SC_logMachPortReferences(const char *str, mach_port_t port)
980 {
981 const char *blanks = " ";
982 char buf[60];
983 mach_port_type_t pt;
984 mach_port_status_t recv_status = { 0 };
985 mach_port_urefs_t refs_send = 0;
986 mach_port_urefs_t refs_recv = 0;
987 mach_port_urefs_t refs_once = 0;
988 mach_port_urefs_t refs_pset = 0;
989 mach_port_urefs_t refs_dead = 0;
990 kern_return_t status;
991
992 buf[0] = '\0';
993 if (str != NULL) {
994 static int is_configd = -1;
995
996 if (is_configd == -1) {
997 char name[64] = "";
998
999 (void) proc_name(getpid(), name, sizeof(name));
1000 is_configd = (strncmp(name, "configd", sizeof(name)) == 0);
1001 }
1002 if (is_configd == 1) {
1003 // if "configd", add indication if this is the M[ain] or [P]lugin thread
1004 strlcpy(buf,
1005 (CFRunLoopGetMain() == CFRunLoopGetCurrent()) ? "M " : "P ",
1006 sizeof(buf));
1007 }
1008
1009 // add provided string
1010 strlcat(buf, str, sizeof(buf));
1011
1012 // fill
1013 strlcat(buf, blanks, sizeof(buf));
1014 if (strcmp(&buf[sizeof(buf) - 3], " ") == 0) {
1015 buf[sizeof(buf) - 3] = ':';
1016 }
1017 }
1018
1019 status = mach_port_type(mach_task_self(), port, &pt);
1020 if (status != KERN_SUCCESS) {
1021 SCLog(TRUE, LOG_DEBUG,
1022 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"),
1023 buf,
1024 port,
1025 mach_error_string(status));
1026 }
1027
1028 if ((pt & MACH_PORT_TYPE_SEND) != 0) {
1029 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs_send);
1030 if (status != KERN_SUCCESS) {
1031 SCLog(TRUE, LOG_DEBUG,
1032 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"),
1033 buf,
1034 port,
1035 mach_error_string(status));
1036 }
1037 }
1038
1039 if ((pt & MACH_PORT_TYPE_RECEIVE) != 0) {
1040 mach_msg_type_number_t count;
1041
1042 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, &refs_recv);
1043 if (status != KERN_SUCCESS) {
1044 SCLog(TRUE, LOG_DEBUG,
1045 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_RECEIVE): %s"),
1046 buf,
1047 port,
1048 mach_error_string(status));
1049 }
1050
1051 count = MACH_PORT_RECEIVE_STATUS_COUNT;
1052 status = mach_port_get_attributes(mach_task_self(),
1053 port,
1054 MACH_PORT_RECEIVE_STATUS,
1055 (mach_port_info_t)&recv_status,
1056 &count);
1057 if (status != KERN_SUCCESS) {
1058 SCLog(TRUE, LOG_DEBUG,
1059 CFSTR("%mach_port_get_attributes(..., %d, MACH_PORT_RECEIVE_STATUS): %s"),
1060 buf,
1061 port,
1062 mach_error_string(status));
1063 }
1064 }
1065
1066 if ((pt & MACH_PORT_TYPE_SEND_ONCE) != 0) {
1067 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once);
1068 if (status != KERN_SUCCESS) {
1069 SCLog(TRUE, LOG_DEBUG,
1070 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND_ONCE): %s"),
1071 buf,
1072 port,
1073 mach_error_string(status));
1074 }
1075 }
1076
1077 if ((pt & MACH_PORT_TYPE_PORT_SET) != 0) {
1078 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, &refs_pset);
1079 if (status != KERN_SUCCESS) {
1080 SCLog(TRUE, LOG_DEBUG,
1081 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_PORT_SET): %s"),
1082 buf,
1083 port,
1084 mach_error_string(status));
1085 }
1086 }
1087
1088 if ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) {
1089 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead);
1090 if (status != KERN_SUCCESS) {
1091 SCLog(TRUE, LOG_DEBUG,
1092 CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_DEAD_NAME): %s"),
1093 buf,
1094 port,
1095 mach_error_string(status));
1096 }
1097 }
1098
1099 SCLog(TRUE, LOG_DEBUG,
1100 CFSTR("%smach port 0x%x (%d): send=%d, receive=%d, send once=%d, port set=%d, dead name=%d%s%s"),
1101 buf,
1102 port,
1103 port,
1104 refs_send,
1105 refs_recv,
1106 refs_once,
1107 refs_pset,
1108 refs_dead,
1109 recv_status.mps_nsrequest ? ", no more senders" : "",
1110 ((pt & MACH_PORT_TYPE_DEAD_NAME) != 0) ? ", dead name request" : "");
1111
1112 return;
1113 }
1114
1115
1116 CFStringRef
1117 _SC_copyBacktrace()
1118 {
1119 int n;
1120 void *stack[64];
1121 char **symbols;
1122 CFMutableStringRef trace;
1123
1124 n = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
1125 if (n == -1) {
1126 SCLog(TRUE, LOG_ERR, CFSTR("backtrace() failed: %s"), strerror(errno));
1127 return NULL;
1128 }
1129
1130 trace = CFStringCreateMutable(NULL, 0);
1131
1132 symbols = backtrace_symbols(stack, n);
1133 if (symbols != NULL) {
1134 int i;
1135
1136 for (i = 0; i < n; i++) {
1137 CFStringAppendFormat(trace, NULL, CFSTR("%s\n"), symbols[i]);
1138 }
1139
1140 free(symbols);
1141 }
1142
1143 return trace;
1144 }