]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/prefs.c
configd-395.10.tar.gz
[apple/configd.git] / scutil.tproj / prefs.c
1 /*
2 * Copyright (c) 2003-2008, 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 * May 29, 2003 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <unistd.h>
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <dlfcn.h>
36
37 #include <SystemConfiguration/SCPreferencesSetSpecific.h>
38 #if !TARGET_OS_IPHONE
39 #include <Security/Authorization.h>
40 #endif /* !TARGET_OS_IPHONE */
41
42 #include "scutil.h"
43 #include "commands.h"
44 #include "prefs.h"
45
46
47 /* -------------------- */
48
49
50 #if !TARGET_OS_IPHONE
51 static void *
52 __loadSecurity(void) {
53 static void *image = NULL;
54 if (NULL == image) {
55 const char *framework = "/System/Library/Frameworks/Security.framework/Versions/A/Security";
56 struct stat statbuf;
57 const char *suffix = getenv("DYLD_IMAGE_SUFFIX");
58 char path[MAXPATHLEN];
59
60 strlcpy(path, framework, sizeof(path));
61 if (suffix) strlcat(path, suffix, sizeof(path));
62 if (0 <= stat(path, &statbuf)) {
63 image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
64 } else {
65 image = dlopen(framework, RTLD_LAZY | RTLD_LOCAL);
66 }
67 }
68 return (void *)image;
69 }
70
71
72 __private_extern__ OSStatus
73 _AuthorizationCreate(const AuthorizationRights *rights, const AuthorizationEnvironment *environment, AuthorizationFlags flags, AuthorizationRef *authorization)
74 {
75 #undef AuthorizationCreate
76 static typeof (AuthorizationCreate) *dyfunc = NULL;
77 if (dyfunc == NULL) {
78 void *image = __loadSecurity();
79 if (image) dyfunc = dlsym(image, "AuthorizationCreate");
80 }
81 return dyfunc ? dyfunc(rights, environment, flags, authorization) : -1;
82 }
83 #define AuthorizationCreate _AuthorizationCreate
84
85
86 __private_extern__ OSStatus
87 _AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags flags)
88 {
89 #undef AuthorizationFree
90 static typeof (AuthorizationFree) *dyfunc = NULL;
91 if (dyfunc == NULL) {
92 void *image = __loadSecurity();
93 if (image) dyfunc = dlsym(image, "AuthorizationFree");
94 }
95 return dyfunc ? dyfunc(authorization, flags) : -1;
96 }
97 #define AuthorizationFree _AuthorizationFree
98
99
100 /* -------------------- */
101
102
103 static AuthorizationRef
104 _createAuthorization()
105 {
106 AuthorizationRef authorization = NULL;
107 AuthorizationFlags flags = kAuthorizationFlagDefaults;
108 OSStatus status;
109
110 status = AuthorizationCreate(NULL,
111 kAuthorizationEmptyEnvironment,
112 flags,
113 &authorization);
114 if (status != errAuthorizationSuccess) {
115 SCPrint(TRUE,
116 stdout,
117 CFSTR("AuthorizationCreate() failed: status = %d\n"),
118 status);
119 return NULL;
120 }
121
122 return authorization;
123 }
124 #endif /* !TARGET_OS_IPHONE */
125
126 /* -------------------- */
127
128
129 __private_extern__ Boolean _prefs_changed = FALSE;
130
131
132 __private_extern__
133 Boolean
134 _prefs_open(CFStringRef name, CFStringRef prefsID)
135 {
136 CFMutableDictionaryRef options = NULL;
137 Boolean useHelper = FALSE;
138 Boolean useOptions = FALSE;
139
140 authorization = NULL;
141
142 if (geteuid() != 0) {
143 // if we need to use a helper
144 useHelper = TRUE;
145
146 #if !TARGET_OS_IPHONE
147 authorization = _createAuthorization();
148 #endif /* !TARGET_OS_IPHONE */
149 }
150
151 if (getenv("SCPREFERENCES_REMOVE_WHEN_EMPTY") != NULL) {
152 // if we have options
153 useOptions = TRUE;
154
155 if (options == NULL) {
156 options = CFDictionaryCreateMutable(NULL,
157 0,
158 &kCFTypeDictionaryKeyCallBacks,
159 &kCFTypeDictionaryValueCallBacks);
160 }
161 CFDictionarySetValue(options, kSCPreferencesOptionRemoveWhenEmpty, kCFBooleanTrue);
162 }
163
164 if (!useHelper && !useOptions) {
165 // if no helper/options needed
166 prefs = SCPreferencesCreate(NULL, name, prefsID);
167 } else if (!useOptions) {
168 // if no options needed
169 prefs = SCPreferencesCreateWithAuthorization(NULL, name, prefsID, authorization);
170 } else {
171 prefs = SCPreferencesCreateWithOptions(NULL, name, prefsID, authorization, options);
172 CFRelease(options);
173 }
174
175 if (prefs == NULL) {
176 return FALSE;
177 }
178
179 _prefs_changed = FALSE;
180 return TRUE;
181 }
182
183
184 __private_extern__
185 void
186 _prefs_save()
187 {
188 if (!SCPreferencesCommitChanges(prefs)) {
189 switch (SCError()) {
190 case kSCStatusAccessError :
191 SCPrint(TRUE, stderr, CFSTR("Permission denied.\n"));
192 break;
193 default :
194 SCPrint(TRUE,
195 stdout,
196 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
197 SCErrorString(SCError()));
198 break;
199 }
200 exit (1);
201 }
202
203 _prefs_changed = FALSE;
204
205 if (!SCPreferencesApplyChanges(prefs)) {
206 SCPrint(TRUE,
207 stdout,
208 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
209 SCErrorString(SCError()));
210 exit (1);
211 }
212
213 return;
214 }
215
216
217 __private_extern__
218 void
219 _prefs_close()
220 {
221 if (prefs != NULL) {
222 CFRelease(prefs);
223 prefs = NULL;
224 _prefs_changed = FALSE;
225 }
226
227 if (authorization != NULL) {
228 #if !TARGET_OS_IPHONE
229 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
230 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
231 #else /* !TARGET_OS_IPHONE */
232 // Uh...if authorization isn't NULL, something went horribly wrong.
233 #endif /* !TARGET_OS_IPHONE */
234 authorization = NULL;
235 }
236
237 return;
238 }
239
240
241 __private_extern__
242 Boolean
243 _prefs_commitRequired(int argc, char **argv, const char *command)
244 {
245 if (_prefs_changed) {
246 if ((currentInput != NULL) &&
247 isatty(fileno(currentInput->fp)) &&
248 ((argc < 1) || (strcmp(argv[0], "!") != 0))
249 ) {
250 SCPrint(TRUE, stdout,
251 CFSTR("preference changes have not been committed\n"
252 "use \"commit\" to save changes"));
253 if (command != NULL) {
254 SCPrint(TRUE, stdout,
255 CFSTR(" or \"%s !\" to abandon changes"),
256 command);
257 }
258 SCPrint(TRUE, stdout, CFSTR("\n"));
259 return TRUE;
260 }
261
262 SCPrint(TRUE, stdout, CFSTR("preference changes abandoned\n"));
263 }
264
265 return FALSE;
266 }
267
268
269 /* -------------------- */
270
271
272 static void
273 get_ComputerName(int argc, char **argv)
274 {
275 CFStringEncoding encoding;
276 CFStringRef hostname;
277
278 hostname = SCDynamicStoreCopyComputerName(NULL, &encoding);
279 if (hostname == NULL) {
280 int sc_status = SCError();
281
282 switch (sc_status) {
283 case kSCStatusNoKey :
284 SCPrint(TRUE,
285 stderr,
286 CFSTR("ComputerName: not set\n"));
287 break;
288 default :
289 SCPrint(TRUE,
290 stderr,
291 CFSTR("SCDynamicStoreCopyComputerName() failed: %s\n"),
292 SCErrorString(SCError()));
293 break;
294 }
295 exit (1);
296 }
297
298 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
299 CFRelease(hostname);
300
301 exit(0);
302 }
303
304
305 static void
306 set_ComputerName(int argc, char **argv)
307 {
308 CFStringRef hostname;
309 Boolean ok;
310
311 ok = _prefs_open(CFSTR("scutil --set ComputerName"), NULL);
312 if (!ok) {
313 SCPrint(TRUE,
314 stdout,
315 CFSTR("Could not open prefs: %s\n"),
316 SCErrorString(SCError()));
317 exit(1);
318 }
319
320 if (argc == 0) {
321 hostname = _copyStringFromSTDIN();
322 } else {
323 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
324 }
325
326 ok = SCPreferencesSetComputerName(prefs, hostname, kCFStringEncodingUTF8);
327 if (hostname != NULL) CFRelease(hostname);
328 if (!ok) {
329 SCPrint(TRUE,
330 stdout,
331 CFSTR("Could not open prefs: %s\n"),
332 SCErrorString(SCError()));
333 _prefs_close();
334 exit (1);
335 }
336
337 _prefs_save();
338 _prefs_close();
339 exit(0);
340 }
341
342
343 static void
344 get_HostName(int argc, char **argv)
345 {
346 CFStringRef hostname;
347 Boolean ok;
348
349 ok = _prefs_open(CFSTR("scutil --get HostName"), NULL);
350 if (!ok) {
351 SCPrint(TRUE,
352 stdout,
353 CFSTR("SCPreferencesCreate() failed: %s\n"),
354 SCErrorString(SCError()));
355 exit(1);
356 }
357
358 hostname = SCPreferencesGetHostName(prefs);
359 if (hostname == NULL) {
360 int sc_status = SCError();
361
362 switch (sc_status) {
363 case kSCStatusNoKey :
364 SCPrint(TRUE,
365 stderr,
366 CFSTR("HostName: not set\n"));
367 break;
368 default :
369 SCPrint(TRUE,
370 stderr,
371 CFSTR("SCPreferencesGetHostName() failed: %s\n"),
372 SCErrorString(SCError()));
373 break;
374 }
375 _prefs_close();
376 exit (1);
377 }
378
379 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
380 _prefs_close();
381 exit(0);
382 }
383
384
385 static void
386 set_HostName(int argc, char **argv)
387 {
388 CFStringRef hostname = NULL;
389 Boolean ok;
390
391 ok = _prefs_open(CFSTR("scutil --set HostName"), NULL);
392 if (!ok) {
393 SCPrint(TRUE,
394 stdout,
395 CFSTR("Could not open prefs: %s\n"),
396 SCErrorString(SCError()));
397 exit(1);
398 }
399
400 if (argc == 0) {
401 hostname = _copyStringFromSTDIN();
402 } else {
403 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
404 }
405
406 ok = SCPreferencesSetHostName(prefs, hostname);
407 if (hostname != NULL) CFRelease(hostname);
408 if (!ok) {
409 SCPrint(TRUE,
410 stderr,
411 CFSTR("SCPreferencesSetHostName() failed: %s\n"),
412 SCErrorString(SCError()));
413 _prefs_close();
414 exit (1);
415 }
416
417 _prefs_save();
418 _prefs_close();
419 exit(0);
420 }
421
422
423 static void
424 get_LocalHostName(int argc, char **argv)
425 {
426 CFStringRef hostname;
427
428 hostname = SCDynamicStoreCopyLocalHostName(NULL);
429 if (hostname == NULL) {
430 int sc_status = SCError();
431
432 switch (sc_status) {
433 case kSCStatusNoKey :
434 SCPrint(TRUE,
435 stderr,
436 CFSTR("LocalHostName: not set\n"));
437 break;
438 default :
439 SCPrint(TRUE,
440 stderr,
441 CFSTR("SCDynamicStoreCopyLocalHostName() failed: %s\n"),
442 SCErrorString(SCError()));
443 break;
444 }
445 exit (1);
446 }
447
448 SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname);
449 CFRelease(hostname);
450
451 exit(0);
452 }
453
454
455 static void
456 set_LocalHostName(int argc, char **argv)
457 {
458 CFStringRef hostname = NULL;
459 Boolean ok;
460
461 ok = _prefs_open(CFSTR("scutil --set LocalHostName"), NULL);
462 if (!ok) {
463 SCPrint(TRUE,
464 stdout,
465 CFSTR("Could not open prefs: %s\n"),
466 SCErrorString(SCError()));
467 exit(1);
468 }
469
470 if (argc == 0) {
471 hostname = _copyStringFromSTDIN();
472 } else {
473 hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
474 }
475
476 ok = SCPreferencesSetLocalHostName(prefs, hostname);
477 if (hostname != NULL) CFRelease(hostname);
478 if (!ok) {
479 SCPrint(TRUE,
480 stderr,
481 CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"),
482 SCErrorString(SCError()));
483 _prefs_close();
484 exit (1);
485 }
486
487 _prefs_save();
488 _prefs_close();
489 exit(0);
490 }
491
492
493 /* -------------------- */
494
495
496 typedef void (*pref_func) (int argc, char **argv);
497
498 static const struct {
499 char *pref;
500 pref_func get;
501 pref_func set;
502 } pref_keys[] = {
503 { "ComputerName", get_ComputerName, set_ComputerName },
504 { "HostName", get_HostName, set_HostName },
505 { "LocalHostName", get_LocalHostName, set_LocalHostName }
506 };
507 #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0]))
508
509
510 __private_extern__
511 int
512 findPref(char *pref)
513 {
514 int i;
515
516 for (i = 0; i < (int)N_PREF_KEYS; i++) {
517 if (strcmp(pref, pref_keys[i].pref) == 0) {
518 return i;
519 }
520 }
521
522 return -1;
523 }
524
525
526 __private_extern__
527 void
528 do_getPref(char *pref, int argc, char **argv)
529 {
530 int i;
531
532 i = findPref(pref);
533 if (i >= 0) {
534 (*pref_keys[i].get)(argc, argv);
535 }
536 return;
537 }
538
539
540 __private_extern__
541 void
542 do_setPref(char *pref, int argc, char **argv)
543 {
544 int i;
545
546 i = findPref(pref);
547 if (i >= 0) {
548 (*pref_keys[i].set)(argc, argv);
549 }
550 return;
551 }
552
553
554 /* -------------------- */
555
556
557 __private_extern__
558 void
559 do_prefs_init()
560 {
561 return;
562 }
563
564
565 __private_extern__
566 void
567 do_prefs_open(int argc, char **argv)
568 {
569 Boolean ok;
570 CFStringRef prefsID = NULL;
571
572 if (prefs != NULL) {
573 if (_prefs_commitRequired(argc, argv, "close")) {
574 return;
575 }
576
577 do_prefs_close(0, NULL);
578 }
579
580 if (argc > 0) {
581 prefsID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
582 }
583
584 ok = _prefs_open(CFSTR("scutil --prefs"), prefsID);
585 if (prefsID != NULL) CFRelease(prefsID);
586 if (!ok) {
587 SCPrint(TRUE,
588 stdout,
589 CFSTR("Could not open prefs: %s\n"),
590 SCErrorString(SCError()));
591 return;
592 }
593
594 return;
595 }
596
597
598 __private_extern__
599 void
600 do_prefs_lock(int argc, char **argv)
601 {
602 Boolean wait = (argc > 0) ? TRUE : FALSE;
603
604 if (!SCPreferencesLock(prefs, wait)) {
605 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
606 return;
607 }
608
609 return;
610 }
611
612
613 __private_extern__
614 void
615 do_prefs_unlock(int argc, char **argv)
616 {
617 if (!SCPreferencesUnlock(prefs)) {
618 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
619 return;
620 }
621
622 return;
623 }
624
625
626 __private_extern__
627 void
628 do_prefs_commit(int argc, char **argv)
629 {
630 if (!SCPreferencesCommitChanges(prefs)) {
631 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
632 return;
633 }
634
635 _prefs_changed = FALSE;
636 return;
637 }
638
639
640 __private_extern__
641 void
642 do_prefs_apply(int argc, char **argv)
643 {
644 if (!SCPreferencesApplyChanges(prefs)) {
645 SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
646 }
647
648 return;
649 }
650
651
652 __private_extern__
653 void
654 do_prefs_close(int argc, char **argv)
655 {
656 if (_prefs_commitRequired(argc, argv, "close")) {
657 return;
658 }
659
660 _prefs_close();
661 return;
662 }
663
664
665 __private_extern__
666 void
667 do_prefs_quit(int argc, char **argv)
668 {
669 if (_prefs_commitRequired(argc, argv, "quit")) {
670 return;
671 }
672
673 _prefs_close();
674
675 termRequested = TRUE;
676 return;
677 }
678
679
680 __private_extern__
681 void
682 do_prefs_synchronize(int argc, char **argv)
683 {
684 SCPreferencesSynchronize(prefs);
685 return;
686 }
687
688
689 static CFComparisonResult
690 sort_paths(const void *p1, const void *p2, void *context) {
691 CFStringRef path1 = (CFStringRef)p1;
692 CFStringRef path2 = (CFStringRef)p2;
693 return CFStringCompare(path1, path2, 0);
694 }
695
696
697 __private_extern__
698 void
699 do_prefs_list(int argc, char **argv)
700 {
701 int i;
702 CFIndex n;
703 CFMutableArrayRef paths = NULL;
704 CFStringRef prefix;
705 CFDictionaryRef entity;
706
707 prefix = CFStringCreateWithCString(NULL,
708 (argc >= 1) ? argv[0] : "/",
709 kCFStringEncodingUTF8);
710
711 entity = SCPreferencesPathGetValue(prefs, prefix);
712 if (entity == NULL) {
713 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
714 goto done;
715 }
716
717 paths = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
718
719 n = isA_CFDictionary(entity) ? CFDictionaryGetCount(entity) : 0;
720 if (n > 0) {
721 CFIndex i;
722 const void ** keys;
723 const void ** vals;
724
725 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
726 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
727 CFDictionaryGetKeysAndValues(entity, keys, vals);
728 for (i = 0; i < n; i++) {
729 if (isA_CFDictionary(vals[i])) {
730 CFArrayAppendValue(paths, keys[i]);
731 }
732 }
733 CFAllocatorDeallocate(NULL, keys);
734 CFAllocatorDeallocate(NULL, vals);
735 }
736
737 n = CFArrayGetCount(paths);
738 CFArraySortValues(paths,
739 CFRangeMake(0, n),
740 sort_paths,
741 NULL);
742
743 if (n > 0) {
744 for (i = 0; i < n; i++) {
745 SCPrint(TRUE,
746 stdout,
747 CFSTR(" path [%d] = %@/%@\n"),
748 i,
749 CFEqual(prefix, CFSTR("/")) ? CFSTR("") : prefix,
750 CFArrayGetValueAtIndex(paths, i));
751 }
752 } else {
753 SCPrint(TRUE, stdout, CFSTR(" no paths.\n"));
754 }
755
756 CFRelease(paths);
757
758 done :
759
760 CFRelease(prefix);
761 return;
762 }
763
764
765 __private_extern__
766 void
767 do_prefs_get(int argc, char **argv)
768 {
769 CFDictionaryRef dict;
770 CFStringRef link;
771 CFIndex n;
772 CFMutableDictionaryRef newDict;
773 CFStringRef path;
774
775 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
776
777 link = SCPreferencesPathGetLink(prefs, path);
778 if (link != NULL) {
779 SCPrint(TRUE, stdout, CFSTR(" --> %@\n"), link);
780 }
781
782 dict = SCPreferencesPathGetValue(prefs, path);
783 CFRelease(path);
784 if (dict == NULL) {
785 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
786 return;
787 }
788
789 newDict = CFDictionaryCreateMutable(NULL,
790 0,
791 &kCFTypeDictionaryKeyCallBacks,
792 &kCFTypeDictionaryValueCallBacks);
793
794 // remove [path] children
795 n = isA_CFDictionary(dict) ? CFDictionaryGetCount(dict) : 0;
796 if (n > 0) {
797 CFIndex i;
798 const void ** keys;
799 const void ** vals;
800
801 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
802 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
803 CFDictionaryGetKeysAndValues(dict, keys, vals);
804 for (i = 0; i < n; i++) {
805 if (!isA_CFDictionary(vals[i])) {
806 CFDictionaryAddValue(newDict, keys[i], vals[i]);
807 }
808 }
809 CFAllocatorDeallocate(NULL, keys);
810 CFAllocatorDeallocate(NULL, vals);
811 }
812
813 if (value != NULL) {
814 CFRelease(value); /* we have new information, release the old */
815 }
816
817 value = newDict;
818
819 return;
820 }
821
822
823 __private_extern__
824 void
825 do_prefs_set(int argc, char **argv)
826 {
827 CFDictionaryRef dict;
828 CFMutableDictionaryRef newDict = NULL;
829 CFStringRef path;
830
831 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
832 newDict = CFDictionaryCreateMutableCopy(NULL, 0, value);
833
834 dict = SCPreferencesPathGetValue(prefs, path);
835 if (dict != NULL) {
836 CFIndex n;
837
838 // retain [path] children
839 n = CFDictionaryGetCount(dict);
840 if (n > 0) {
841 CFIndex i;
842 const void ** keys;
843 const void ** vals;
844
845 keys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
846 vals = CFAllocatorAllocate(NULL, n * sizeof(CFPropertyListRef), 0);
847 CFDictionaryGetKeysAndValues(dict, keys, vals);
848 for (i = 0; i < n; i++) {
849 if (isA_CFDictionary(vals[i])) {
850 if (CFDictionaryContainsKey(newDict, keys[i])) {
851 SCPrint(TRUE, stdout, CFSTR(" key %@ is already a path component and cannot be replaced\n"), keys[i]);
852 goto done;
853 }
854 CFDictionaryAddValue(newDict, keys[i], vals[i]);
855 }
856 }
857 CFAllocatorDeallocate(NULL, keys);
858 CFAllocatorDeallocate(NULL, vals);
859 }
860 } else if (SCError() == kSCStatusInvalidArgument) {
861 SCPrint(TRUE, stdout, CFSTR(" a path component is not a dictionary\n"));
862 goto done;
863 } else if (SCError() != kSCStatusNoKey) {
864 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
865 goto done;
866 }
867
868 if (argc > 1) {
869 CFStringRef link;
870 Boolean ok;
871
872 // set link
873 link = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8);
874 ok = SCPreferencesPathSetLink(prefs, path, link);
875 CFRelease(link);
876 if (!ok) {
877 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
878 goto done;
879 }
880 } else {
881 // set value
882 if (!SCPreferencesPathSetValue(prefs, path, newDict)) {
883 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
884 goto done;
885 }
886 }
887
888 _prefs_changed = TRUE;
889
890 done :
891
892 CFRelease(newDict);
893 CFRelease(path);
894 return;
895 }
896
897
898 __private_extern__
899 void
900 do_prefs_remove(int argc, char **argv)
901 {
902 CFStringRef path;
903
904 path = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
905
906 if (!SCPreferencesPathRemoveValue(prefs, path)) {
907 SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
908 goto done;
909 }
910
911 _prefs_changed = TRUE;
912
913 done :
914
915 CFRelease(path);
916 return;
917 }