]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDPrivate.c
configd-84.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDPrivate.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Modification History
28 *
29 * June 1, 2001 Allan Nathanson <ajn@apple.com>
30 * - public API conversion
31 *
32 * November 9, 2000 Allan Nathanson <ajn@apple.com>
33 * - initial revision
34 */
35
36 #include <SystemConfiguration/SystemConfiguration.h>
37 #include <SystemConfiguration/SCValidation.h>
38 #include <SystemConfiguration/SCPrivate.h>
39
40 #include <mach/mach.h>
41 #include <mach/notify.h>
42 #include <mach/mach_error.h>
43 #include <pthread.h>
44
45 #define N_QUICK 32
46
47
48 char *
49 _SC_cfstring_to_cstring(CFStringRef cfstr, char *buf, int bufLen, CFStringEncoding encoding)
50 {
51 CFIndex last;
52 CFIndex len = CFStringGetLength(cfstr);
53
54 /* how much buffer space will we really need? */
55 (void)CFStringGetBytes(cfstr,
56 CFRangeMake(0, len),
57 encoding,
58 0,
59 FALSE,
60 NULL,
61 0,
62 &len);
63
64 if (!buf) {
65 bufLen = len + 1;
66 buf = CFAllocatorAllocate(NULL, bufLen, 0);
67 if (!buf) {
68 return NULL;
69 }
70 }
71
72 if (len >= bufLen) {
73 len = bufLen - 1;
74 }
75
76 (void)CFStringGetBytes(cfstr,
77 CFRangeMake(0, len),
78 encoding,
79 0,
80 FALSE,
81 buf,
82 bufLen,
83 &last);
84 buf[last] = '\0';
85
86 return buf;
87 }
88
89
90 Boolean
91 _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dataLen)
92 {
93 CFDataRef myXml;
94
95 if (!xml && !(dataRef && dataLen)) {
96 /* if not keeping track of allocated space */
97 return FALSE;
98 }
99
100 myXml = CFPropertyListCreateXMLData(NULL, obj);
101 if (!myXml) {
102 SCLog(TRUE, LOG_ERR, CFSTR("CFPropertyListCreateXMLData() failed"));
103 if (xml) *xml = NULL;
104 if (dataRef) *dataRef = NULL;
105 if (dataLen) *dataLen = 0;
106 return FALSE;
107 }
108
109 if (xml) {
110 *xml = myXml;
111 if (dataRef) {
112 *dataRef = (void *)CFDataGetBytePtr(myXml);
113 }
114 if (dataLen) {
115 *dataLen = CFDataGetLength(myXml);
116 }
117 } else {
118 kern_return_t status;
119
120 *dataLen = CFDataGetLength(myXml);
121 status = vm_allocate(mach_task_self(), (void *)dataRef, *dataLen, TRUE);
122 if (status != KERN_SUCCESS) {
123 SCLog(TRUE,
124 LOG_ERR,
125 CFSTR("vm_allocate(): %s"),
126 mach_error_string(status));
127 CFRelease(myXml);
128 *dataRef = NULL;
129 *dataLen = 0;
130 return FALSE;
131 }
132
133 bcopy((char *)CFDataGetBytePtr(myXml), *dataRef, *dataLen);
134 CFRelease(myXml);
135 }
136
137 return TRUE;
138 }
139
140
141 Boolean
142 _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen)
143 {
144 CFStringRef xmlError;
145
146 if (!xml) {
147 kern_return_t status;
148
149 xml = CFDataCreateWithBytesNoCopy(NULL, (void *)dataRef, dataLen, kCFAllocatorNull);
150 *obj = CFPropertyListCreateFromXMLData(NULL,
151 xml,
152 kCFPropertyListImmutable,
153 &xmlError);
154 CFRelease(xml);
155
156 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
157 if (status != KERN_SUCCESS) {
158 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
159 /* non-fatal???, proceed */
160 }
161 } else {
162 *obj = CFPropertyListCreateFromXMLData(NULL,
163 xml,
164 kCFPropertyListImmutable,
165 &xmlError);
166 }
167
168 if (*obj == NULL) {
169 if (xmlError) {
170 SCLog(TRUE,
171 LOG_ERR,
172 CFSTR("CFPropertyListCreateFromXMLData() failed: %@"),
173 xmlError);
174 CFRelease(xmlError);
175 }
176 _SCErrorSet(kSCStatusFailed);
177 return FALSE;
178 }
179
180 return TRUE;
181 }
182
183
184 Boolean
185 _SCSerializeString(CFStringRef str, CFDataRef *data, void **dataRef, CFIndex *dataLen)
186 {
187 CFDataRef myData;
188
189 if (!isA_CFString(str)) {
190 /* if not a CFString */
191 return FALSE;
192 }
193
194 if (!data && !(dataRef && dataLen)) {
195 /* if not keeping track of allocated space */
196 return FALSE;
197 }
198
199 myData = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0);
200 if (!myData) {
201 SCLog(TRUE, LOG_ERR, CFSTR("CFStringCreateExternalRepresentation() failed"));
202 if (data) *data = NULL;
203 if (dataRef) *dataRef = NULL;
204 if (dataLen) *dataLen = 0;
205 return FALSE;
206 }
207
208 if (data) {
209 *data = myData;
210 if (dataRef) {
211 *dataRef = (void *)CFDataGetBytePtr(myData);
212 }
213 if (dataLen) {
214 *dataLen = CFDataGetLength(myData);
215 }
216 } else {
217 kern_return_t status;
218
219 *dataLen = CFDataGetLength(myData);
220 status = vm_allocate(mach_task_self(), (void *)dataRef, *dataLen, TRUE);
221 if (status != KERN_SUCCESS) {
222 SCLog(TRUE,
223 LOG_ERR,
224 CFSTR("vm_allocate(): %s"),
225 mach_error_string(status));
226 CFRelease(myData);
227 *dataRef = NULL;
228 *dataLen = 0;
229 return FALSE;
230 }
231
232 bcopy((char *)CFDataGetBytePtr(myData), *dataRef, *dataLen);
233 CFRelease(myData);
234 }
235
236 return TRUE;
237 }
238
239
240 Boolean
241 _SCUnserializeString(CFStringRef *str, CFDataRef utf8, void *dataRef, CFIndex dataLen)
242 {
243 if (!utf8) {
244 kern_return_t status;
245
246 utf8 = CFDataCreateWithBytesNoCopy(NULL, dataRef, dataLen, kCFAllocatorNull);
247 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
248 CFRelease(utf8);
249
250 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
251 if (status != KERN_SUCCESS) {
252 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
253 /* non-fatal???, proceed */
254 }
255 } else {
256 *str = CFStringCreateFromExternalRepresentation(NULL, utf8, kCFStringEncodingUTF8);
257 }
258
259 if (*str == NULL) {
260 SCLog(TRUE, LOG_ERR, CFSTR("CFStringCreateFromExternalRepresentation() failed"));
261 return FALSE;
262 }
263
264 return TRUE;
265 }
266
267
268 Boolean
269 _SCSerializeData(CFDataRef data, void **dataRef, CFIndex *dataLen)
270 {
271 kern_return_t status;
272
273 if (!isA_CFData(data)) {
274 /* if not a CFData */
275 return FALSE;
276 }
277
278 *dataLen = CFDataGetLength(data);
279 status = vm_allocate(mach_task_self(), (void *)dataRef, *dataLen, TRUE);
280 if (status != KERN_SUCCESS) {
281 SCLog(TRUE,
282 LOG_ERR,
283 CFSTR("vm_allocate(): %s"),
284 mach_error_string(status));
285 *dataRef = NULL;
286 *dataLen = 0;
287 return FALSE;
288 }
289
290 bcopy((char *)CFDataGetBytePtr(data), *dataRef, *dataLen);
291
292 return TRUE;
293 }
294
295
296 Boolean
297 _SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen)
298 {
299 kern_return_t status;
300
301 *data = CFDataCreate(NULL, dataRef, dataLen);
302 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
303 if (status != KERN_SUCCESS) {
304 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
305 _SCErrorSet(kSCStatusFailed);
306 return FALSE;
307 }
308
309 return TRUE;
310 }
311
312
313 CFDictionaryRef
314 _SCSerializeMultiple(CFDictionaryRef dict)
315 {
316 const void * keys_q[N_QUICK];
317 const void ** keys = keys_q;
318 CFIndex nElements;
319 CFDictionaryRef newDict = NULL;
320 const void * pLists_q[N_QUICK];
321 const void ** pLists = pLists_q;
322 const void * values_q[N_QUICK];
323 const void ** values = values_q;
324
325 nElements = CFDictionaryGetCount(dict);
326 if (nElements > 0) {
327 CFIndex i;
328
329 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
330 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
331 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
332 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
333 }
334 bzero(pLists, nElements * sizeof(CFTypeRef));
335
336 CFDictionaryGetKeysAndValues(dict, keys, values);
337 for (i = 0; i < nElements; i++) {
338 if (!_SCSerialize((CFPropertyListRef)values[i], (CFDataRef *)&pLists[i], NULL, NULL)) {
339 goto done;
340 }
341 }
342 }
343
344 newDict = CFDictionaryCreate(NULL,
345 keys,
346 pLists,
347 nElements,
348 &kCFTypeDictionaryKeyCallBacks,
349 &kCFTypeDictionaryValueCallBacks);
350
351 done :
352
353 if (nElements > 0) {
354 CFIndex i;
355
356 for (i = 0; i < nElements; i++) {
357 if (pLists[i]) CFRelease(pLists[i]);
358 }
359
360 if (keys != keys_q) {
361 CFAllocatorDeallocate(NULL, keys);
362 CFAllocatorDeallocate(NULL, values);
363 CFAllocatorDeallocate(NULL, pLists);
364 }
365 }
366
367 return newDict;
368 }
369
370
371 CFDictionaryRef
372 _SCUnserializeMultiple(CFDictionaryRef dict)
373 {
374 const void * keys_q[N_QUICK];
375 const void ** keys = keys_q;
376 CFIndex nElements;
377 CFDictionaryRef newDict = NULL;
378 const void * pLists_q[N_QUICK];
379 const void ** pLists = pLists_q;
380 const void * values_q[N_QUICK];
381 const void ** values = values_q;
382
383 nElements = CFDictionaryGetCount(dict);
384 if (nElements > 0) {
385 CFIndex i;
386
387 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
388 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
389 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
390 pLists = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
391 }
392 bzero(pLists, nElements * sizeof(CFTypeRef));
393
394 CFDictionaryGetKeysAndValues(dict, keys, values);
395 for (i = 0; i < nElements; i++) {
396 if (!_SCUnserialize((CFPropertyListRef *)&pLists[i], values[i], NULL, NULL)) {
397 goto done;
398 }
399 }
400 }
401
402 newDict = CFDictionaryCreate(NULL,
403 keys,
404 pLists,
405 nElements,
406 &kCFTypeDictionaryKeyCallBacks,
407 &kCFTypeDictionaryValueCallBacks);
408
409 done :
410
411 if (nElements > 0) {
412 CFIndex i;
413
414 for (i = 0; i < nElements; i++) {
415 if (pLists[i]) CFRelease(pLists[i]);
416 }
417
418 if (keys != keys_q) {
419 CFAllocatorDeallocate(NULL, keys);
420 CFAllocatorDeallocate(NULL, values);
421 CFAllocatorDeallocate(NULL, pLists);
422 }
423 }
424
425 return newDict;
426 }
427
428
429 void
430 __showMachPortStatus()
431 {
432 #ifdef DEBUG
433 /* print status of in-use mach ports */
434 if (_sc_debug) {
435 kern_return_t status;
436 mach_port_name_array_t ports;
437 mach_port_type_array_t types;
438 int pi, pn, tn;
439 CFMutableStringRef str;
440
441 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("----------"));
442
443 /* report on ALL mach ports associated with this task */
444 status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn);
445 if (status == MACH_MSG_SUCCESS) {
446 str = CFStringCreateMutable(NULL, 0);
447 for (pi = 0; pi < pn; pi++) {
448 char rights[16], *rp = &rights[0];
449
450 if (types[pi] != MACH_PORT_TYPE_NONE) {
451 *rp++ = ' ';
452 *rp++ = '(';
453 if (types[pi] & MACH_PORT_TYPE_SEND)
454 *rp++ = 'S';
455 if (types[pi] & MACH_PORT_TYPE_RECEIVE)
456 *rp++ = 'R';
457 if (types[pi] & MACH_PORT_TYPE_SEND_ONCE)
458 *rp++ = 'O';
459 if (types[pi] & MACH_PORT_TYPE_PORT_SET)
460 *rp++ = 'P';
461 if (types[pi] & MACH_PORT_TYPE_DEAD_NAME)
462 *rp++ = 'D';
463 *rp++ = ')';
464 }
465 *rp = '\0';
466 CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights);
467 }
468 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("Task ports (n=%d):%@"), pn, str);
469 CFRelease(str);
470 } else {
471 /* log (but ignore) errors */
472 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("mach_port_names(): %s"), mach_error_string(status));
473 }
474 }
475 #endif /* DEBUG */
476 return;
477 }
478
479
480 void
481 __showMachPortReferences(mach_port_t port)
482 {
483 #ifdef DEBUG
484 kern_return_t status;
485 mach_port_urefs_t refs_send = 0;
486 mach_port_urefs_t refs_recv = 0;
487 mach_port_urefs_t refs_once = 0;
488 mach_port_urefs_t refs_pset = 0;
489 mach_port_urefs_t refs_dead = 0;
490
491 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("user references for mach port %d"), port);
492
493 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs_send);
494 if (status != KERN_SUCCESS) {
495 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_SEND): %s"), mach_error_string(status));
496 return;
497 }
498
499 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, &refs_recv);
500 if (status != KERN_SUCCESS) {
501 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_RECEIVE): %s"), mach_error_string(status));
502 return;
503 }
504
505 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once);
506 if (status != KERN_SUCCESS) {
507 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_SEND_ONCE): %s"), mach_error_string(status));
508 return;
509 }
510
511 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, &refs_pset);
512 if (status != KERN_SUCCESS) {
513 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_PORT_SET): %s"), mach_error_string(status));
514 return;
515 }
516
517 status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead);
518 if (status != KERN_SUCCESS) {
519 SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_DEAD_NAME): %s"), mach_error_string(status));
520 return;
521 }
522
523 SCLog(_sc_verbose, LOG_DEBUG,
524 CFSTR(" send = %d, receive = %d, send once = %d, port set = %d, dead name = %d"),
525 refs_send,
526 refs_recv,
527 refs_once,
528 refs_pset,
529 refs_dead);
530
531 #endif /* DEBUG */
532 return;
533 }