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