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