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