Commit | Line | Data |
---|---|---|
009ee3c6 | 1 | /* |
be997540 | 2 | * Copyright (c) 2003-2008 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) { | |
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 | } | |
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 | { | |
136 | if (geteuid() == 0) { | |
137 | prefs = SCPreferencesCreate(NULL, name, prefsID); | |
138 | } else { | |
a40a14f8 | 139 | #if !TARGET_OS_IPHONE |
edebe297 | 140 | authorization = _createAuthorization(); |
a40a14f8 A |
141 | #else /* !TARGET_OS_IPHONE */ |
142 | authorization = NULL; | |
143 | #endif /* !TARGET_OS_IPHONE */ | |
edebe297 A |
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() | |
009ee3c6 A |
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 | ||
edebe297 A |
175 | _prefs_changed = FALSE; |
176 | ||
009ee3c6 A |
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 | ||
edebe297 A |
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) { | |
a40a14f8 | 200 | #if !TARGET_OS_IPHONE |
edebe297 A |
201 | AuthorizationFree(authorization, kAuthorizationFlagDefaults); |
202 | // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights); | |
a40a14f8 A |
203 | #else /* !TARGET_OS_IPHONE */ |
204 | // Uh...if authorization isn't NULL, something went horribly wrong. | |
205 | #endif /* !TARGET_OS_IPHONE */ | |
edebe297 A |
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 | ||
009ee3c6 A |
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 | ||
d6c893b2 | 260 | utf8 = CFStringCreateWithBytes(NULL, (UInt8 *)buf, len, kCFStringEncodingUTF8, TRUE); |
009ee3c6 A |
261 | return utf8; |
262 | } | |
263 | ||
264 | ||
265 | static void | |
266 | get_ComputerName(int argc, char **argv) | |
267 | { | |
268 | CFStringEncoding encoding; | |
269 | CFStringRef hostname; | |
009ee3c6 A |
270 | |
271 | hostname = SCDynamicStoreCopyComputerName(NULL, &encoding); | |
edebe297 | 272 | if (hostname == NULL) { |
009ee3c6 A |
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 | ||
edebe297 | 291 | SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname); |
009ee3c6 | 292 | CFRelease(hostname); |
edebe297 | 293 | |
009ee3c6 A |
294 | exit(0); |
295 | } | |
296 | ||
297 | ||
298 | static void | |
299 | set_ComputerName(int argc, char **argv) | |
300 | { | |
009ee3c6 | 301 | CFStringRef hostname; |
edebe297 A |
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 | } | |
009ee3c6 A |
312 | |
313 | if (argc == 0) { | |
314 | hostname = _copyStringFromSTDIN(); | |
009ee3c6 | 315 | } else { |
a40a14f8 | 316 | hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); |
009ee3c6 A |
317 | } |
318 | ||
a40a14f8 | 319 | ok = SCPreferencesSetComputerName(prefs, hostname, kCFStringEncodingUTF8); |
edebe297 A |
320 | if (hostname != NULL) CFRelease(hostname); |
321 | if (!ok) { | |
009ee3c6 A |
322 | SCPrint(TRUE, |
323 | stdout, | |
edebe297 | 324 | CFSTR("Could not open prefs: %s\n"), |
009ee3c6 | 325 | SCErrorString(SCError())); |
edebe297 | 326 | _prefs_close(); |
009ee3c6 A |
327 | exit (1); |
328 | } | |
edebe297 A |
329 | |
330 | _prefs_save(); | |
331 | _prefs_close(); | |
009ee3c6 A |
332 | exit(0); |
333 | } | |
334 | ||
335 | ||
dbf6a266 A |
336 | static void |
337 | get_HostName(int argc, char **argv) | |
338 | { | |
339 | CFStringRef hostname; | |
edebe297 A |
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 | } | |
dbf6a266 | 350 | |
dbf6a266 A |
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 | } | |
edebe297 | 368 | _prefs_close(); |
dbf6a266 A |
369 | exit (1); |
370 | } | |
371 | ||
372 | SCPrint(TRUE, stdout, CFSTR("%@\n"), hostname); | |
edebe297 | 373 | _prefs_close(); |
dbf6a266 A |
374 | exit(0); |
375 | } | |
376 | ||
377 | ||
378 | static void | |
379 | set_HostName(int argc, char **argv) | |
380 | { | |
edebe297 A |
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 | } | |
dbf6a266 A |
392 | |
393 | if (argc == 0) { | |
394 | hostname = _copyStringFromSTDIN(); | |
395 | } else { | |
a40a14f8 | 396 | hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); |
dbf6a266 A |
397 | } |
398 | ||
edebe297 A |
399 | ok = SCPreferencesSetHostName(prefs, hostname); |
400 | if (hostname != NULL) CFRelease(hostname); | |
401 | if (!ok) { | |
dbf6a266 A |
402 | SCPrint(TRUE, |
403 | stderr, | |
404 | CFSTR("SCPreferencesSetHostName() failed: %s\n"), | |
405 | SCErrorString(SCError())); | |
edebe297 | 406 | _prefs_close(); |
dbf6a266 A |
407 | exit (1); |
408 | } | |
edebe297 A |
409 | |
410 | _prefs_save(); | |
411 | _prefs_close(); | |
dbf6a266 A |
412 | exit(0); |
413 | } | |
414 | ||
415 | ||
009ee3c6 A |
416 | static void |
417 | get_LocalHostName(int argc, char **argv) | |
418 | { | |
419 | CFStringRef hostname; | |
420 | ||
421 | hostname = SCDynamicStoreCopyLocalHostName(NULL); | |
edebe297 | 422 | if (hostname == NULL) { |
009ee3c6 A |
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); | |
be997540 | 443 | |
009ee3c6 A |
444 | exit(0); |
445 | } | |
446 | ||
447 | ||
448 | static void | |
449 | set_LocalHostName(int argc, char **argv) | |
450 | { | |
edebe297 A |
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 | } | |
009ee3c6 A |
462 | |
463 | if (argc == 0) { | |
464 | hostname = _copyStringFromSTDIN(); | |
465 | } else { | |
a40a14f8 | 466 | hostname = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); |
009ee3c6 A |
467 | } |
468 | ||
edebe297 A |
469 | ok = SCPreferencesSetLocalHostName(prefs, hostname); |
470 | if (hostname != NULL) CFRelease(hostname); | |
471 | if (!ok) { | |
009ee3c6 A |
472 | SCPrint(TRUE, |
473 | stderr, | |
474 | CFSTR("SCPreferencesSetLocalHostName() failed: %s\n"), | |
475 | SCErrorString(SCError())); | |
edebe297 | 476 | _prefs_close(); |
009ee3c6 A |
477 | exit (1); |
478 | } | |
edebe297 A |
479 | |
480 | _prefs_save(); | |
481 | _prefs_close(); | |
009ee3c6 A |
482 | exit(0); |
483 | } | |
484 | ||
485 | ||
edebe297 A |
486 | /* -------------------- */ |
487 | ||
488 | ||
009ee3c6 A |
489 | typedef void (*pref_func) (int argc, char **argv); |
490 | ||
dbf6a266 | 491 | static const struct { |
009ee3c6 A |
492 | char *pref; |
493 | pref_func get; | |
494 | pref_func set; | |
dbf6a266 | 495 | } pref_keys[] = { |
009ee3c6 | 496 | { "ComputerName", get_ComputerName, set_ComputerName }, |
dbf6a266 | 497 | { "HostName", get_HostName, set_HostName }, |
009ee3c6 A |
498 | { "LocalHostName", get_LocalHostName, set_LocalHostName } |
499 | }; | |
dbf6a266 | 500 | #define N_PREF_KEYS (sizeof(pref_keys) / sizeof(pref_keys[0])) |
009ee3c6 A |
501 | |
502 | ||
dbf6a266 | 503 | __private_extern__ |
009ee3c6 A |
504 | int |
505 | findPref(char *pref) | |
506 | { | |
507 | int i; | |
508 | ||
dbf6a266 A |
509 | for (i = 0; i < (int)N_PREF_KEYS; i++) { |
510 | if (strcmp(pref, pref_keys[i].pref) == 0) { | |
009ee3c6 A |
511 | return i; |
512 | } | |
513 | } | |
514 | ||
515 | return -1; | |
516 | } | |
517 | ||
518 | ||
dbf6a266 | 519 | __private_extern__ |
009ee3c6 A |
520 | void |
521 | do_getPref(char *pref, int argc, char **argv) | |
522 | { | |
523 | int i; | |
524 | ||
525 | i = findPref(pref); | |
526 | if (i >= 0) { | |
dbf6a266 | 527 | (*pref_keys[i].get)(argc, argv); |
009ee3c6 A |
528 | } |
529 | return; | |
530 | } | |
531 | ||
532 | ||
dbf6a266 | 533 | __private_extern__ |
009ee3c6 A |
534 | void |
535 | do_setPref(char *pref, int argc, char **argv) | |
536 | { | |
537 | int i; | |
538 | ||
539 | i = findPref(pref); | |
540 | if (i >= 0) { | |
dbf6a266 | 541 | (*pref_keys[i].set)(argc, argv); |
009ee3c6 A |
542 | } |
543 | return; | |
544 | } | |
edebe297 A |
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 | ||
6d034b4e A |
673 | __private_extern__ |
674 | void | |
675 | do_prefs_synchronize(int argc, char **argv) | |
676 | { | |
677 | SCPreferencesSynchronize(prefs); | |
678 | return; | |
679 | } | |
680 | ||
681 | ||
edebe297 A |
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 | } |