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