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