]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/cache.c
configd-453.16.tar.gz
[apple/configd.git] / scutil.tproj / cache.c
1 /*
2 * Copyright (c) 2000-2005, 2011 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 <sys/types.h>
35
36 #include "scutil.h"
37 #include "cache.h"
38
39
40 #pragma mark -
41 #pragma mark SCDynamicStore "cache"
42
43
44 static Boolean use_cache = FALSE;
45
46 static CFMutableDictionaryRef cached_keys = NULL;
47 static CFMutableDictionaryRef cached_set = NULL;
48 static CFMutableArrayRef cached_removals = NULL;
49 static CFMutableArrayRef cached_notifys = NULL;
50
51
52 static void
53 cache_open(void)
54 {
55 if (use_cache) {
56 // if we are already using the cache
57 cache_close();
58 }
59
60 cached_keys = CFDictionaryCreateMutable(NULL,
61 0,
62 &kCFTypeDictionaryKeyCallBacks,
63 &kCFTypeDictionaryValueCallBacks);
64 cached_set = CFDictionaryCreateMutable(NULL,
65 0,
66 &kCFTypeDictionaryKeyCallBacks,
67 &kCFTypeDictionaryValueCallBacks);
68 cached_removals = CFArrayCreateMutable(NULL,
69 0,
70 &kCFTypeArrayCallBacks);
71 cached_notifys = CFArrayCreateMutable(NULL,
72 0,
73 &kCFTypeArrayCallBacks);
74
75 use_cache = TRUE;
76 return;
77 }
78
79
80 static CFPropertyListRef
81 cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
82 {
83 CFPropertyListRef value;
84
85 value = CFDictionaryGetValue(cached_set, key);
86 if (value) {
87 // if we have "set" a new value
88 return (CFRetain(value));
89 }
90
91 if (CFArrayContainsValue(cached_removals,
92 CFRangeMake(0, CFArrayGetCount(cached_removals)),
93 key)) {
94 // if we have "removed" the key
95 _SCErrorSet(kSCStatusNoKey);
96 return NULL;
97 }
98
99 value = CFDictionaryGetValue(cached_keys, key);
100 if (value) {
101 // if we have a cached value
102 return (CFRetain(value));
103 }
104
105 value = SCDynamicStoreCopyValue(store, key);
106 if (value) {
107 CFDictionarySetValue(cached_keys, key, value);
108 }
109
110 return value;
111 }
112
113
114 static void
115 cache_SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
116 {
117 CFIndex i;
118
119 i = CFArrayGetFirstIndexOfValue(cached_removals,
120 CFRangeMake(0, CFArrayGetCount(cached_removals)),
121 key);
122 if (i != kCFNotFound) {
123 // if previously "removed"
124 CFArrayRemoveValueAtIndex(cached_removals, i);
125 }
126
127 CFDictionarySetValue(cached_set, key, value);
128
129 return;
130 }
131
132 static void
133 cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
134 {
135 CFDictionaryRemoveValue(cached_set, key);
136
137 if (!CFArrayContainsValue(cached_removals,
138 CFRangeMake(0, CFArrayGetCount(cached_removals)),
139 key)) {
140 CFArrayAppendValue(cached_removals, key);
141 }
142
143 return;
144 }
145
146
147 static void
148 cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key)
149 {
150 if (!CFArrayContainsValue(cached_notifys,
151 CFRangeMake(0, CFArrayGetCount(cached_notifys)),
152 key)) {
153 CFArrayAppendValue(cached_notifys, key);
154 }
155
156 return;
157 }
158
159
160 static void
161 cache_write(SCDynamicStoreRef store)
162 {
163 if ((CFDictionaryGetCount(cached_set) > 0) ||
164 (CFArrayGetCount(cached_removals) > 0) ||
165 (CFArrayGetCount(cached_notifys) > 0)) {
166 if (!SCDynamicStoreSetMultiple(store,
167 cached_set,
168 cached_removals,
169 cached_notifys)) {
170 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
171 }
172 }
173
174 return;
175 }
176
177
178 __private_extern__
179 void
180 cache_close(void)
181 {
182 if (!use_cache) {
183 return;
184 }
185
186 CFRelease(cached_keys);
187 CFRelease(cached_set);
188 CFRelease(cached_removals);
189 CFRelease(cached_notifys);
190
191 use_cache = FALSE;
192 return;
193 }
194
195
196 #pragma mark -
197 #pragma mark SCDynamicStore operations
198
199
200 __private_extern__
201 void
202 do_block(int argc, char **argv)
203 {
204 Boolean enable = FALSE;
205
206 if (argc >= 1) {
207 if ((strcasecmp(argv[0], "begin") == 0) ||
208 (strcasecmp(argv[0], "start") == 0) ||
209 (strcasecmp(argv[0], "on" ) == 0) ||
210 (strcasecmp(argv[0], "1" ) == 0)) {
211 enable = TRUE;
212 } else if ((strcasecmp(argv[0], "end" ) == 0) ||
213 (strcasecmp(argv[0], "stop" ) == 0) ||
214 (strcasecmp(argv[0], "off" ) == 0) ||
215 (strcasecmp(argv[0], "0" ) == 0)) {
216 enable = FALSE;
217 } else {
218 SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
219 return;
220 }
221 } else {
222 enable = !use_cache; // toggle
223 }
224
225 if (enable) {
226 // begin block of SCDynamicStore operations
227 if (use_cache) {
228 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusLocked));
229 return;
230 }
231
232 SCPrint(TRUE, stdout, CFSTR("Begin block of SCDynamicStore operations\n"));
233
234 cache_open();
235 } else {
236 CFIndex n;
237
238 // end block of SCDynamicStore operations
239 if (!use_cache) {
240 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNeedLock));
241 return;
242 }
243
244 n = CFDictionaryGetCount(cached_keys) +
245 CFArrayGetCount(cached_removals) +
246 CFArrayGetCount(cached_notifys);
247 SCPrint(TRUE, stdout,
248 CFSTR("End block of SCDynamicStore operations%s\n"),
249 (n > 0) ? ", posting changes" : "");
250 if (n > 0) {
251 cache_write(store);
252 }
253 cache_close();
254 }
255
256 return;
257 }
258
259
260 static CFComparisonResult
261 sort_keys(const void *p1, const void *p2, void *context) {
262 CFStringRef key1 = (CFStringRef)p1;
263 CFStringRef key2 = (CFStringRef)p2;
264 return CFStringCompare(key1, key2, 0);
265 }
266
267
268 #define N_QUICK 64
269
270
271 __private_extern__
272 void
273 do_list(int argc, char **argv)
274 {
275 int i;
276 CFStringRef pattern;
277 CFArrayRef list;
278 CFIndex listCnt;
279 CFMutableArrayRef sortedList;
280
281 pattern = CFStringCreateWithCString(NULL,
282 (argc >= 1) ? argv[0] : ".*",
283 kCFStringEncodingUTF8);
284
285 list = SCDynamicStoreCopyKeyList(store, pattern);
286 CFRelease(pattern);
287 if (list == NULL) {
288 if (SCError() != kSCStatusOK) {
289 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
290 return;
291 } else {
292 if (!use_cache) {
293 SCPrint(TRUE, stdout, CFSTR(" no keys.\n"));
294 return;
295 } else {
296 CFIndex n;
297
298 n = CFDictionaryGetCount(cached_set);
299 if (n > 0){
300 const void * cachedKeys_q[N_QUICK];
301 const void ** cachedKeys = cachedKeys_q;
302
303 if (n > (CFIndex)(sizeof(cachedKeys_q) / sizeof(CFStringRef))) {
304 cachedKeys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
305 }
306 CFDictionaryGetKeysAndValues(cached_set, cachedKeys, NULL);
307 list = CFArrayCreate(NULL, cachedKeys, n, &kCFTypeArrayCallBacks);
308 if (cachedKeys != cachedKeys_q) {
309 CFAllocatorDeallocate(NULL, cachedKeys);
310 }
311 } else {
312 SCPrint(TRUE, stdout, CFSTR(" no keys.\n"));
313 return;
314 }
315 }
316 }
317 } else if (use_cache &&
318 ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0))) {
319 SCPrint(TRUE, stdout,
320 CFSTR(" Note: SCDynamicStore transactions in progress, key list (below) may be out of date.\n\n"));
321 }
322
323 listCnt = CFArrayGetCount(list);
324 sortedList = CFArrayCreateMutableCopy(NULL, listCnt, list);
325 CFRelease(list);
326 CFArraySortValues(sortedList,
327 CFRangeMake(0, listCnt),
328 sort_keys,
329 NULL);
330
331 if (listCnt > 0) {
332 for (i = 0; i < listCnt; i++) {
333 SCPrint(TRUE,
334 stdout,
335 CFSTR(" subKey [%d] = %@\n"),
336 i,
337 CFArrayGetValueAtIndex(sortedList, i));
338 }
339 } else {
340 SCPrint(TRUE, stdout, CFSTR(" no keys.\n"));
341 }
342 CFRelease(sortedList);
343
344 return;
345 }
346
347
348 __private_extern__
349 void
350 do_add(int argc, char **argv)
351 {
352 CFStringRef key;
353
354 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
355
356 if (argc < 2) {
357 if (!use_cache) {
358 if (!SCDynamicStoreAddValue(store, key, value)) {
359 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
360 }
361 } else {
362 CFTypeRef val;
363
364 val = cache_SCDynamicStoreCopyValue(store, key);
365 if (val != NULL) {
366 CFRelease(val);
367 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists));
368 } else {
369 cache_SCDynamicStoreSetValue(store, key, value);
370 }
371 }
372 } else {
373 if (!use_cache) {
374 if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
375 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
376 }
377 } else {
378 CFTypeRef val;
379
380 val = cache_SCDynamicStoreCopyValue(store, key);
381 if (val != NULL) {
382 CFRelease(val);
383 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists));
384 } else {
385 if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
386 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
387 } else {
388 // and save the temp value in the cache too!
389 cache_SCDynamicStoreSetValue(store, key, value);
390 }
391 }
392 }
393 }
394
395 CFRelease(key);
396 return;
397 }
398
399
400 __private_extern__
401 void
402 do_get(int argc, char **argv)
403 {
404 CFStringRef key;
405 CFPropertyListRef newValue;
406
407 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
408 if (!use_cache) {
409 newValue = SCDynamicStoreCopyValue(store, key);
410 } else {
411 newValue = cache_SCDynamicStoreCopyValue(store, key);
412 }
413 CFRelease(key);
414 if (newValue == NULL) {
415 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
416 return;
417 }
418
419 if (value != NULL) {
420 CFRelease(value); /* we have new information, release the old */
421 }
422 value = newValue;
423
424 return;
425 }
426
427
428 __private_extern__
429 void
430 do_set(int argc, char **argv)
431 {
432 CFStringRef key;
433
434 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
435 if (!use_cache) {
436 if (!SCDynamicStoreSetValue(store, key, value)) {
437 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
438 }
439 } else {
440 cache_SCDynamicStoreSetValue(store, key, value);
441 }
442 CFRelease(key);
443 return;
444 }
445
446
447 __private_extern__
448 void
449 do_show(int argc, char **argv)
450 {
451 CFStringRef key;
452 CFPropertyListRef newValue;
453
454 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
455
456 if (argc == 1) {
457 if (!use_cache) {
458 newValue = SCDynamicStoreCopyValue(store, key);
459 } else {
460 newValue = cache_SCDynamicStoreCopyValue(store, key);
461 }
462 } else {
463 CFArrayRef patterns;
464
465 patterns = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
466 if (!use_cache) {
467 newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns);
468 } else {
469 CFArrayRef keys;
470 CFMutableDictionaryRef newDict;
471
472 newDict = CFDictionaryCreateMutable(NULL,
473 0,
474 &kCFTypeDictionaryKeyCallBacks,
475 &kCFTypeDictionaryValueCallBacks);
476 keys = SCDynamicStoreCopyKeyList(store, key);
477 if (keys != NULL) {
478 CFIndex i;
479 CFIndex n;
480
481 n = CFArrayGetCount(keys);
482 for (i = 0; i < n; i++) {
483 CFStringRef storeKey;
484 CFTypeRef storeVal;
485
486 storeKey = CFArrayGetValueAtIndex(keys, i);
487 storeVal = cache_SCDynamicStoreCopyValue(store, storeKey);
488 if (storeVal != NULL) {
489 CFDictionarySetValue(newDict, storeKey, storeVal);
490 CFRelease(storeVal);
491 }
492 }
493 CFRelease(keys);
494 }
495
496 if ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0)) {
497 SCPrint(TRUE, stdout, CFSTR(" Note: SCDynamicStore locked, keys included (below) may be out of date.\n\n"));
498 }
499
500 newValue = newDict;
501 }
502 CFRelease(patterns);
503 }
504
505 CFRelease(key);
506 if (newValue == NULL) {
507 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
508 return;
509 }
510
511 SCPrint(TRUE, stdout, CFSTR("%@\n"), newValue);
512 CFRelease(newValue);
513 return;
514 }
515
516
517 __private_extern__
518 void
519 do_remove(int argc, char **argv)
520 {
521 CFStringRef key;
522
523 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
524 if (!use_cache) {
525 if (!SCDynamicStoreRemoveValue(store, key)) {
526 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
527 }
528 } else {
529 cache_SCDynamicStoreRemoveValue(store, key);
530 }
531 CFRelease(key);
532 return;
533 }
534
535
536 __private_extern__
537 void
538 do_notify(int argc, char **argv)
539 {
540 CFStringRef key;
541
542 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
543 if (!use_cache) {
544 if (!SCDynamicStoreNotifyValue(store, key)) {
545 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
546 }
547 } else {
548 cache_SCDynamicStoreNotifyValue(store, key);
549 }
550 CFRelease(key);
551 return;
552 }