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