]> git.saurik.com Git - apple/configd.git/blame - scutil.tproj/cache.c
configd-802.20.7.tar.gz
[apple/configd.git] / scutil.tproj / cache.c
CommitLineData
5958d7c0 1/*
17d3ee29 2 * Copyright (c) 2000-2005, 2011 Apple Inc. All rights reserved.
5958d7c0
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
009ee3c6 5 *
009ee3c6
A
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
5958d7c0
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
009ee3c6
A
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 *
5958d7c0
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
0fae82ee
A
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
5958d7c0
A
34#include <sys/types.h>
35
36#include "scutil.h"
009ee3c6 37#include "cache.h"
5958d7c0 38
0fae82ee 39
17d3ee29
A
40#pragma mark -
41#pragma mark SCDynamicStore "cache"
42
43
44static Boolean use_cache = FALSE;
45
46static CFMutableDictionaryRef cached_keys = NULL;
47static CFMutableDictionaryRef cached_set = NULL;
48static CFMutableArrayRef cached_removals = NULL;
49static CFMutableArrayRef cached_notifys = NULL;
50
51
52static void
53cache_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
80static CFPropertyListRef
81cache_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
114static void
115cache_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
132static void
133cache_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
147static void
148cache_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
160static void
161cache_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__
179void
180cache_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__
201void
202do_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
0fae82ee
A
260static CFComparisonResult
261sort_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
17d3ee29
A
268#define N_QUICK 64
269
270
dbf6a266 271__private_extern__
5958d7c0
A
272void
273do_list(int argc, char **argv)
274{
0fae82ee
A
275 int i;
276 CFStringRef pattern;
5958d7c0
A
277 CFArrayRef list;
278 CFIndex listCnt;
0fae82ee 279 CFMutableArrayRef sortedList;
5958d7c0 280
0fae82ee
A
281 pattern = CFStringCreateWithCString(NULL,
282 (argc >= 1) ? argv[0] : ".*",
dbf6a266 283 kCFStringEncodingUTF8);
5958d7c0 284
0fae82ee
A
285 list = SCDynamicStoreCopyKeyList(store, pattern);
286 CFRelease(pattern);
edebe297 287 if (list == NULL) {
a5f60add
A
288 if (SCError() != kSCStatusOK) {
289 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
17d3ee29 290 return;
a5f60add 291 } else {
17d3ee29 292 if (!use_cache) {
a5f60add 293 SCPrint(TRUE, stdout, CFSTR(" no keys.\n"));
17d3ee29
A
294 return;
295 } else {
296 CFIndex n;
297
298 n = CFDictionaryGetCount(cached_set);
5e9ce69e 299 if (n > 0) {
17d3ee29
A
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 }
a5f60add 316 }
17d3ee29
A
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"));
5958d7c0
A
321 }
322
323 listCnt = CFArrayGetCount(list);
0fae82ee
A
324 sortedList = CFArrayCreateMutableCopy(NULL, listCnt, list);
325 CFRelease(list);
326 CFArraySortValues(sortedList,
327 CFRangeMake(0, listCnt),
328 sort_keys,
329 NULL);
330
5958d7c0 331 if (listCnt > 0) {
009ee3c6 332 for (i = 0; i < listCnt; i++) {
0fae82ee
A
333 SCPrint(TRUE,
334 stdout,
335 CFSTR(" subKey [%d] = %@\n"),
336 i,
337 CFArrayGetValueAtIndex(sortedList, i));
5958d7c0
A
338 }
339 } else {
a5f60add 340 SCPrint(TRUE, stdout, CFSTR(" no keys.\n"));
5958d7c0 341 }
0fae82ee 342 CFRelease(sortedList);
5958d7c0
A
343
344 return;
345}
346
347
dbf6a266 348__private_extern__
5958d7c0
A
349void
350do_add(int argc, char **argv)
351{
352 CFStringRef key;
5958d7c0 353
dbf6a266 354 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
5958d7c0
A
355
356 if (argc < 2) {
17d3ee29
A
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 }
5958d7c0
A
371 }
372 } else {
17d3ee29
A
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 }
5958d7c0
A
392 }
393 }
394
395 CFRelease(key);
396 return;
397}
398
399
dbf6a266 400__private_extern__
5958d7c0
A
401void
402do_get(int argc, char **argv)
403{
0fae82ee
A
404 CFStringRef key;
405 CFPropertyListRef newValue;
5958d7c0 406
dbf6a266 407 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
17d3ee29
A
408 if (!use_cache) {
409 newValue = SCDynamicStoreCopyValue(store, key);
410 } else {
411 newValue = cache_SCDynamicStoreCopyValue(store, key);
412 }
5958d7c0 413 CFRelease(key);
edebe297 414 if (newValue == NULL) {
0fae82ee 415 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
5958d7c0
A
416 return;
417 }
418
0fae82ee
A
419 if (value != NULL) {
420 CFRelease(value); /* we have new information, release the old */
5958d7c0 421 }
0fae82ee 422 value = newValue;
5958d7c0
A
423
424 return;
425}
426
427
dbf6a266 428__private_extern__
5958d7c0
A
429void
430do_set(int argc, char **argv)
431{
5958d7c0
A
432 CFStringRef key;
433
edebe297 434 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
17d3ee29
A
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);
0fae82ee
A
441 }
442 CFRelease(key);
443 return;
444}
445
446
dbf6a266 447__private_extern__
0fae82ee
A
448void
449do_show(int argc, char **argv)
450{
451 CFStringRef key;
452 CFPropertyListRef newValue;
453
dbf6a266 454 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
009ee3c6
A
455
456 if (argc == 1) {
17d3ee29
A
457 if (!use_cache) {
458 newValue = SCDynamicStoreCopyValue(store, key);
459 } else {
460 newValue = cache_SCDynamicStoreCopyValue(store, key);
461 }
009ee3c6
A
462 } else {
463 CFArrayRef patterns;
464
465 patterns = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
17d3ee29
A
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 }
009ee3c6
A
502 CFRelease(patterns);
503 }
504
5958d7c0 505 CFRelease(key);
edebe297 506 if (newValue == NULL) {
0fae82ee
A
507 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
508 return;
5958d7c0 509 }
0fae82ee
A
510
511 SCPrint(TRUE, stdout, CFSTR("%@\n"), newValue);
512 CFRelease(newValue);
5958d7c0
A
513 return;
514}
515
516
dbf6a266 517__private_extern__
5958d7c0
A
518void
519do_remove(int argc, char **argv)
520{
5958d7c0
A
521 CFStringRef key;
522
edebe297 523 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
17d3ee29
A
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);
0fae82ee 530 }
5958d7c0 531 CFRelease(key);
0fae82ee
A
532 return;
533}
534
535
dbf6a266 536__private_extern__
0fae82ee
A
537void
538do_notify(int argc, char **argv)
539{
540 CFStringRef key;
541
edebe297 542 key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
17d3ee29
A
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);
5958d7c0 549 }
0fae82ee 550 CFRelease(key);
5958d7c0
A
551 return;
552}