]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCD.c
797571d2b14acd69a89246dcc1d542e9e21b2301
[apple/configd.git] / SystemConfiguration.fproj / SCD.c
1 /*
2 * Copyright (c) 2000-2007 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 * March 24, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <mach/mach.h>
35 #include <mach/mach_error.h>
36 #include <servers/bootstrap.h>
37 #include <pthread.h>
38 #include <sys/time.h>
39
40 #include <SystemConfiguration/SystemConfiguration.h>
41 #include <SystemConfiguration/SCPrivate.h>
42 #include "SCDynamicStoreInternal.h"
43 #include "config.h" /* MiG generated file */
44
45 /* framework variables */
46 Boolean _sc_debug = FALSE; /* TRUE if debugging enabled */
47 Boolean _sc_verbose = FALSE; /* TRUE if verbose logging enabled */
48 Boolean _sc_log = TRUE; /* TRUE if SCLog() output goes to syslog */
49
50 static const struct sc_errmsg {
51 int status;
52 char *message;
53 } sc_errmsgs[] = {
54 { kSCStatusAccessError, "Permission denied" },
55 { kSCStatusFailed, "Failed!" },
56 { kSCStatusInvalidArgument, "Invalid argument" },
57 { kSCStatusKeyExists, "Key already defined" },
58 { kSCStatusLocked, "Lock already held" },
59 { kSCStatusMaxLink, "Maximum link count exceeded" },
60 { kSCStatusNeedLock, "Lock required for this operation" },
61 { kSCStatusNoStoreServer, "Configuration daemon not (no longer) available" },
62 { kSCStatusNoStoreSession, "Configuration daemon session not active" },
63 { kSCStatusNoConfigFile, "Configuration file not found" },
64 { kSCStatusNoKey, "No such key" },
65 { kSCStatusNoLink, "No such link" },
66 { kSCStatusNoPrefsSession, "Preference session not active" },
67 { kSCStatusNotifierActive, "Notifier is currently active" },
68 { kSCStatusOK, "Success!" },
69 { kSCStatusPrefsBusy, "Preferences update currently in progress" },
70 { kSCStatusReachabilityUnknown, "Network reachability cannot be determined" },
71 { kSCStatusStale, "Write attempted on stale version of object" },
72 };
73 #define nSC_ERRMSGS (sizeof(sc_errmsgs)/sizeof(struct sc_errmsg))
74
75
76 #define USE_SCCOPYDESCRIPTION
77 #ifdef USE_SCCOPYDESCRIPTION
78
79 // from <CoreFoundation/CFVeryPrivate.h>
80 extern CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(void *, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments);
81
82 #define N_QUICK 32
83
84 static CFStringRef
85 _SCCopyDescription(void *info, CFDictionaryRef formatOptions)
86 {
87 CFMutableDictionaryRef nFormatOptions;
88 CFStringRef prefix1;
89 CFStringRef prefix2;
90 CFTypeID type = CFGetTypeID(info);
91
92 if (!formatOptions ||
93 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX1"), (const void **)&prefix1)) {
94 prefix1 = CFSTR("");
95 }
96
97 if (type == CFStringGetTypeID()) {
98 return CFStringCreateWithFormat(NULL,
99 formatOptions,
100 CFSTR("%@%@"),
101 prefix1,
102 info);
103 }
104
105 if (type == CFBooleanGetTypeID()) {
106 return CFStringCreateWithFormat(NULL,
107 formatOptions,
108 CFSTR("%@%s"),
109 prefix1,
110 CFBooleanGetValue(info) ? "TRUE" : "FALSE");
111 }
112
113 if (type == CFDataGetTypeID()) {
114 const uint8_t *data;
115 CFIndex dataLen;
116 CFIndex i;
117 CFMutableStringRef str;
118
119 str = CFStringCreateMutable(NULL, 0);
120 CFStringAppendFormat(str, formatOptions, CFSTR("%@<data> 0x"), prefix1);
121
122 data = CFDataGetBytePtr(info);
123 dataLen = CFDataGetLength(info);
124 for (i = 0; i < dataLen; i++) {
125 CFStringAppendFormat(str, NULL, CFSTR("%02x"), data[i]);
126 }
127
128 return str;
129 }
130
131 if (type == CFNumberGetTypeID()) {
132 return CFStringCreateWithFormat(NULL,
133 formatOptions,
134 CFSTR("%@%@"),
135 prefix1,
136 info);
137 }
138
139 if (type == CFDateGetTypeID()) {
140 CFGregorianDate gDate;
141 CFStringRef str;
142 CFTimeZoneRef tZone;
143
144 tZone = CFTimeZoneCopySystem();
145 gDate = CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(info), tZone);
146 str = CFStringCreateWithFormat(NULL,
147 formatOptions,
148 CFSTR("%@%02d/%02d/%04d %02d:%02d:%02.0f %@"),
149 prefix1,
150 gDate.month,
151 gDate.day,
152 gDate.year,
153 gDate.hour,
154 gDate.minute,
155 gDate.second,
156 CFTimeZoneGetName(tZone));
157 CFRelease(tZone);
158 return str;
159 }
160
161 if (!formatOptions ||
162 !CFDictionaryGetValueIfPresent(formatOptions, CFSTR("PREFIX2"), (const void **)&prefix2)) {
163 prefix2 = CFStringCreateCopy(NULL, prefix1);
164 }
165
166 if (formatOptions) {
167 nFormatOptions = CFDictionaryCreateMutableCopy(NULL, 0, formatOptions);
168 } else {
169 nFormatOptions = CFDictionaryCreateMutable(NULL,
170 0,
171 &kCFTypeDictionaryKeyCallBacks,
172 &kCFTypeDictionaryValueCallBacks);
173 }
174
175 if (type == CFArrayGetTypeID()) {
176 const void * elements_q[32];
177 const void ** elements = elements_q;
178 CFIndex i;
179 CFIndex nElements;
180 CFMutableStringRef str;
181
182 str = CFStringCreateMutable(NULL, 0);
183 CFStringAppendFormat(str, formatOptions, CFSTR("%@<array> {"), prefix1);
184
185 nElements = CFArrayGetCount(info);
186 if (nElements > 0) {
187 if (nElements > (CFIndex)(sizeof(elements_q)/sizeof(CFTypeRef)))
188 elements = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
189 CFArrayGetValues(info, CFRangeMake(0, nElements), elements);
190 for (i = 0; i < nElements; i++) {
191 CFMutableStringRef nPrefix1;
192 CFMutableStringRef nPrefix2;
193 CFStringRef nStr;
194 CFStringRef vStr;
195
196 nStr = CFStringCreateWithFormat(NULL, NULL, CFSTR("%u"), i);
197
198 nPrefix1 = CFStringCreateMutable(NULL, 0);
199 CFStringAppendFormat(nPrefix1,
200 formatOptions,
201 CFSTR("%@ %@ : "),
202 prefix2,
203 nStr);
204 nPrefix2 = CFStringCreateMutable(NULL, 0);
205 CFStringAppendFormat(nPrefix2,
206 formatOptions,
207 CFSTR("%@ "),
208 prefix2);
209
210 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
211 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
212 CFRelease(nPrefix1);
213 CFRelease(nPrefix2);
214 CFRelease(nStr);
215
216 vStr = _SCCopyDescription((void *)elements[i], nFormatOptions);
217 CFStringAppendFormat(str,
218 formatOptions,
219 CFSTR("\n%@"),
220 vStr);
221 CFRelease(vStr);
222 }
223 if (elements != elements_q) CFAllocatorDeallocate(NULL, elements);
224 }
225 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
226
227 CFRelease(nFormatOptions);
228 return str;
229 }
230
231 if (type == CFDictionaryGetTypeID()) {
232 const void * keys_q[N_QUICK];
233 const void ** keys = keys_q;
234 CFIndex i;
235 CFIndex nElements;
236 CFMutableStringRef nPrefix1;
237 CFMutableStringRef nPrefix2;
238 CFMutableStringRef str;
239 const void * values_q[N_QUICK];
240 const void ** values = values_q;
241
242 str = CFStringCreateMutable(NULL, 0);
243 CFStringAppendFormat(str, formatOptions, CFSTR("%@<dictionary> {"), prefix1);
244
245 nElements = CFDictionaryGetCount(info);
246 if (nElements > 0) {
247 if (nElements > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
248 keys = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
249 values = CFAllocatorAllocate(NULL, nElements * sizeof(CFTypeRef), 0);
250 }
251 CFDictionaryGetKeysAndValues(info, keys, values);
252 for (i = 0; i < nElements; i++) {
253 CFStringRef kStr;
254 CFStringRef vStr;
255
256 kStr = _SCCopyDescription((void *)keys[i], NULL);
257
258 nPrefix1 = CFStringCreateMutable(NULL, 0);
259 CFStringAppendFormat(nPrefix1,
260 formatOptions,
261 CFSTR("%@ %@ : "),
262 prefix2,
263 kStr);
264 nPrefix2 = CFStringCreateMutable(NULL, 0);
265 CFStringAppendFormat(nPrefix2,
266 formatOptions,
267 CFSTR("%@ "),
268 prefix2);
269
270 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX1"), nPrefix1);
271 CFDictionarySetValue(nFormatOptions, CFSTR("PREFIX2"), nPrefix2);
272 CFRelease(nPrefix1);
273 CFRelease(nPrefix2);
274 CFRelease(kStr);
275
276 vStr = _SCCopyDescription((void *)values[i], nFormatOptions);
277 CFStringAppendFormat(str,
278 formatOptions,
279 CFSTR("\n%@"),
280 vStr);
281 CFRelease(vStr);
282 }
283 if (keys != keys_q) {
284 CFAllocatorDeallocate(NULL, keys);
285 CFAllocatorDeallocate(NULL, values);
286 }
287 }
288 CFStringAppendFormat(str, formatOptions, CFSTR("\n%@}"), prefix2);
289
290 CFRelease(nFormatOptions);
291 return str;
292 }
293
294 CFRelease(nFormatOptions);
295
296 {
297 CFStringRef cfStr;
298 CFStringRef str;
299
300 cfStr = CFCopyDescription(info);
301 str = CFStringCreateWithFormat(NULL,
302 formatOptions,
303 CFSTR("%@%@"),
304 prefix1,
305 cfStr);
306 CFRelease(cfStr);
307 return str;
308 }
309 }
310
311 #endif /* USE_SCCOPYDESCRIPTION */
312
313
314 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
315
316
317 static void
318 __SCLog(int level, CFStringRef formatString, va_list formatArguments)
319 {
320 CFArrayRef lines;
321 CFStringRef str;
322
323 #ifdef USE_SCCOPYDESCRIPTION
324 str = _CFStringCreateWithFormatAndArgumentsAux(NULL,
325 _SCCopyDescription,
326 NULL,
327 formatString,
328 formatArguments);
329 #else /* USE_SCCOPYDESCRIPTION */
330 str = CFStringCreateWithFormatAndArguments (NULL,
331 NULL,
332 formatString,
333 formatArguments);
334 #endif /* !USE_SCCOPYDESCRIPTION */
335
336 lines = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR("\n"));
337 CFRelease(str);
338
339 if (lines) {
340 int i;
341 int n = CFArrayGetCount(lines);
342
343 pthread_mutex_lock(&lock);
344 for (i = 0; i < n; i++) {
345 CFDataRef line;
346
347 line = CFStringCreateExternalRepresentation(NULL,
348 CFArrayGetValueAtIndex(lines, i),
349 kCFStringEncodingUTF8,
350 (UInt8)'?');
351 if (line) {
352 syslog (level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line));
353 CFRelease(line);
354 }
355 }
356 pthread_mutex_unlock(&lock);
357 CFRelease(lines);
358 }
359
360 return;
361 }
362
363
364 static void
365 __SCPrint(FILE *stream, CFStringRef formatString, va_list formatArguments, Boolean trace, Boolean addNL)
366 {
367 CFDataRef line;
368 CFStringRef str;
369
370 #ifdef USE_SCCOPYDESCRIPTION
371 str = _CFStringCreateWithFormatAndArgumentsAux(NULL,
372 _SCCopyDescription,
373 NULL,
374 formatString,
375 formatArguments);
376 #else /* USE_SCCOPYDESCRIPTION */
377 str = CFStringCreateWithFormatAndArguments (NULL,
378 NULL,
379 formatString,
380 formatArguments);
381 #endif /* !USE_SCCOPYDESCRIPTION */
382
383 line = CFStringCreateExternalRepresentation(NULL,
384 str,
385 kCFStringEncodingUTF8,
386 (UInt8)'?');
387 CFRelease(str);
388 if (!line) {
389 return;
390 }
391
392 pthread_mutex_lock(&lock);
393 if (trace) {
394 struct tm tm_now;
395 struct timeval tv_now;
396
397 (void)gettimeofday(&tv_now, NULL);
398 (void)localtime_r(&tv_now.tv_sec, &tm_now);
399 (void)fprintf(stream, "%2d:%02d:%02d.%03d ",
400 tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000);
401 }
402 (void)fwrite((const void *)CFDataGetBytePtr(line), (size_t)CFDataGetLength(line), 1, stream);
403 if (addNL) {
404 (void)fputc('\n', stream);
405 }
406 fflush (stream);
407 pthread_mutex_unlock(&lock);
408 CFRelease(line);
409
410 return;
411 }
412
413
414 void
415 SCLog(Boolean condition, int level, CFStringRef formatString, ...)
416 {
417 va_list formatArguments;
418
419 if (!condition) {
420 return;
421 }
422
423 va_start(formatArguments, formatString);
424 if (_sc_log > 0) {
425 __SCLog(level, formatString, formatArguments);
426 }
427 if (_sc_log != 1) {
428 __SCPrint((LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout,
429 formatString,
430 formatArguments,
431 (_sc_log > 0), // trace
432 TRUE); // add newline
433 }
434 va_end(formatArguments);
435
436 return;
437 }
438
439
440 void
441 SCPrint(Boolean condition, FILE *stream, CFStringRef formatString, ...)
442 {
443 va_list formatArguments;
444
445 if (!condition) {
446 return;
447 }
448
449 va_start(formatArguments, formatString);
450 __SCPrint(stream, formatString, formatArguments, FALSE, FALSE);
451 va_end(formatArguments);
452
453 return;
454 }
455
456
457 void
458 SCTrace(Boolean condition, FILE *stream, CFStringRef formatString, ...)
459 {
460 va_list formatArguments;
461
462 if (!condition) {
463 return;
464 }
465
466 va_start(formatArguments, formatString);
467 __SCPrint(stream, formatString, formatArguments, TRUE, FALSE);
468 va_end(formatArguments);
469
470 return;
471 }
472
473
474 typedef struct {
475 int _sc_error;
476 } __SCThreadSpecificData, *__SCThreadSpecificDataRef;
477
478
479 static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT;
480 static pthread_key_t tsDataKey;
481
482
483 static void
484 __SCThreadSpecificDataFinalize(void *arg)
485 {
486 __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg;
487
488 if (!tsd) return;
489
490 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
491 return;
492 }
493
494
495 static void
496 __SCThreadSpecificKeyInitialize()
497 {
498 pthread_key_create(&tsDataKey, __SCThreadSpecificDataFinalize);
499 return;
500 }
501
502
503 const CFStringRef kCFErrorDomainSystemConfiguration = CFSTR("com.apple.SystemConfiguration");
504
505
506 void
507 _SCErrorSet(int error)
508 {
509 __SCThreadSpecificDataRef tsd;
510
511 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
512
513 tsd = pthread_getspecific(tsDataKey);
514 if (!tsd) {
515 tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0);
516 bzero(tsd, sizeof(__SCThreadSpecificData));
517 pthread_setspecific(tsDataKey, tsd);
518 }
519
520 tsd->_sc_error = error;
521 return;
522 }
523
524
525 CFErrorRef
526 SCCopyLastError(void)
527 {
528 CFStringRef domain;
529 CFErrorRef error;
530 int i;
531 int code;
532 __SCThreadSpecificDataRef tsd;
533 CFMutableDictionaryRef userInfo = NULL;
534
535 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
536
537 tsd = pthread_getspecific(tsDataKey);
538 code = tsd ? tsd->_sc_error : kSCStatusOK;
539
540 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
541 if (sc_errmsgs[i].status == code) {
542 CFStringRef str;
543
544 domain = kCFErrorDomainSystemConfiguration;
545 userInfo = CFDictionaryCreateMutable(NULL,
546 0,
547 &kCFCopyStringDictionaryKeyCallBacks,
548 &kCFTypeDictionaryValueCallBacks);
549 str = CFStringCreateWithCString(NULL,
550 sc_errmsgs[i].message,
551 kCFStringEncodingASCII);
552 CFDictionarySetValue(userInfo, kCFErrorDescriptionKey, str);
553 CFRelease(str);
554 goto done;
555 }
556 }
557
558 if ((code > 0) && (code <= ELAST)) {
559 domain = kCFErrorDomainPOSIX;
560 goto done;
561 }
562
563 domain = kCFErrorDomainMach;
564
565 done :
566
567 error = CFErrorCreate(NULL, domain, code, userInfo);
568 if (userInfo != NULL) CFRelease(userInfo);
569 return error;
570 }
571
572
573 int
574 SCError(void)
575 {
576 __SCThreadSpecificDataRef tsd;
577
578 pthread_once(&tsKeyInitialized, __SCThreadSpecificKeyInitialize);
579
580 tsd = pthread_getspecific(tsDataKey);
581 return tsd ? tsd->_sc_error : kSCStatusOK;
582 }
583
584
585 const char *
586 SCErrorString(int status)
587 {
588 int i;
589
590 for (i = 0; i < (int)nSC_ERRMSGS; i++) {
591 if (sc_errmsgs[i].status == status) {
592 return sc_errmsgs[i].message;
593 }
594 }
595
596 if ((status > 0) && (status <= ELAST)) {
597 return strerror(status);
598 }
599
600 if ((status >= BOOTSTRAP_SUCCESS) && (status <= BOOTSTRAP_NO_MEMORY)) {
601 return bootstrap_strerror(status);
602 }
603
604 return mach_error_string(status);
605 }