]>
Commit | Line | Data |
---|---|---|
5958d7c0 A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
23 | #include <SystemConfiguration/SystemConfiguration.h> | |
24 | #include <unistd.h> | |
25 | ||
26 | ||
27 | boolean_t apply = TRUE; | |
28 | ||
29 | ||
30 | void | |
31 | usage(const char *command) | |
32 | { | |
33 | SCDLog(LOG_ERR, CFSTR("usage: %s [-n] new-set-name"), command); | |
34 | return; | |
35 | } | |
36 | ||
37 | ||
38 | int | |
39 | main(int argc, char **argv) | |
40 | { | |
41 | const char *command = argv[0]; | |
42 | extern int optind; | |
43 | int opt; | |
44 | CFStringRef current = NULL; | |
45 | int currentMatched = 0; | |
46 | CFStringRef newSet = NULL; /* set key */ | |
47 | CFStringRef newSetUDN = NULL; /* user defined name */ | |
48 | CFStringRef prefix; | |
49 | SCPStatus status; | |
50 | SCPSessionRef session; | |
51 | CFDictionaryRef sets; | |
52 | CFIndex nSets; | |
53 | void **setKeys; | |
54 | void **setVals; | |
55 | CFIndex i; | |
56 | ||
57 | /* process any arguments */ | |
58 | ||
59 | SCDOptionSet(NULL, kSCDOptionUseSyslog, FALSE); | |
60 | ||
61 | while ((opt = getopt(argc, argv, "dvn")) != -1) | |
62 | switch(opt) { | |
63 | case 'd': | |
64 | SCDOptionSet(NULL, kSCDOptionDebug, TRUE); | |
65 | break; | |
66 | case 'v': | |
67 | SCDOptionSet(NULL, kSCDOptionVerbose, TRUE); | |
68 | break; | |
69 | case 'n': | |
70 | apply = FALSE; | |
71 | break; | |
72 | case '?': | |
73 | default : | |
74 | usage(command); | |
75 | } | |
76 | argc -= optind; | |
77 | argv += optind; | |
78 | ||
79 | prefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("/%@/"), kSCPrefSets); | |
80 | ||
81 | newSet = (argc == 1) | |
82 | ? CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman) | |
83 | : CFSTR(""); | |
84 | ||
85 | status = SCPOpen(&session, CFSTR("Select Set Command"), NULL, 0); | |
86 | if (status != SCP_OK) { | |
87 | SCDLog(LOG_ERR, | |
88 | CFSTR("SCPOpen() failed: %s"), | |
89 | SCPError(status)); | |
90 | exit (1); | |
91 | } | |
92 | ||
93 | /* check if a full path to the new "set" was specified */ | |
94 | if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) { | |
95 | CFRange range; | |
96 | CFMutableStringRef str; | |
97 | ||
98 | str = CFStringCreateMutableCopy(NULL, 0, newSet); | |
99 | CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix))); | |
100 | ||
101 | range = CFStringFind(str, CFSTR("/"), 0); | |
102 | if (range.location != kCFNotFound) { | |
103 | SCDLog(LOG_ERR, CFSTR("Set \"%@\" not available."), newSet); | |
104 | exit (1); | |
105 | } | |
106 | ||
107 | CFRelease(newSet); | |
108 | newSet = str; | |
109 | } | |
110 | ||
111 | status = SCPGet(session, kSCPrefSets, (CFPropertyListRef *)&sets); | |
112 | if (status != SCP_OK) { | |
113 | SCDLog(LOG_ERR, CFSTR("SCDGet(...,%s,...) failed: %s"), SCPError(status)); | |
114 | exit (1); | |
115 | } | |
116 | ||
117 | status = SCPGet(session, kSCPrefCurrentSet, (CFPropertyListRef *)¤t); | |
118 | switch (status) { | |
119 | case SCP_OK : | |
120 | if (CFStringHasPrefix(current, prefix)) { | |
121 | CFMutableStringRef tmp; | |
122 | ||
123 | tmp = CFStringCreateMutableCopy(NULL, 0, current); | |
124 | CFStringDelete(tmp, CFRangeMake(0, CFStringGetLength(prefix))); | |
125 | current = tmp; | |
126 | } else { | |
127 | currentMatched = -1; /* not prefixed */ | |
128 | } | |
129 | break; | |
130 | case SCP_NOKEY : | |
131 | current = CFSTR(""); | |
132 | currentMatched = -2; /* not defined */ | |
133 | break; | |
134 | default : | |
135 | SCDLog(LOG_ERR, CFSTR("SCDGet(...,%s,...) failed: %s"), SCPError(status)); | |
136 | exit (1); | |
137 | } | |
138 | ||
139 | nSets = CFDictionaryGetCount(sets); | |
140 | setKeys = CFAllocatorAllocate(NULL, nSets * sizeof(CFStringRef), 0); | |
141 | setVals = CFAllocatorAllocate(NULL, nSets * sizeof(CFDictionaryRef), 0); | |
142 | CFDictionaryGetKeysAndValues(sets, setKeys, setVals); | |
143 | ||
144 | /* check for set with matching name */ | |
145 | for (i=0; i<nSets; i++) { | |
146 | CFStringRef key = (CFStringRef) setKeys[i]; | |
147 | CFDictionaryRef dict = (CFDictionaryRef)setVals[i]; | |
148 | ||
149 | if ((currentMatched >= 0) && CFEqual(key, current)) { | |
150 | currentMatched++; | |
151 | } | |
152 | ||
153 | if (CFEqual(newSet, key)) { | |
154 | newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName); | |
155 | if (newSetUDN) CFRetain(newSetUDN); | |
156 | current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet); | |
157 | goto found; | |
158 | } | |
159 | } | |
160 | ||
161 | /* check for set with matching user-defined name */ | |
162 | for (i=0; i<nSets; i++) { | |
163 | CFStringRef key = (CFStringRef) setKeys[i]; | |
164 | CFDictionaryRef dict = (CFDictionaryRef)setVals[i]; | |
165 | ||
166 | newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName); | |
167 | if ((newSetUDN != NULL) && CFEqual(newSet, newSetUDN)) { | |
168 | CFRelease(newSet); | |
169 | newSet = CFRetain(key); | |
170 | CFRetain(newSetUDN); | |
171 | current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet); | |
172 | goto found; | |
173 | } | |
174 | } | |
175 | ||
176 | if (argc == 2) { | |
177 | SCDLog(LOG_ERR, CFSTR("Set \"%@\" not available."), newSet); | |
178 | } else { | |
179 | usage(command); | |
180 | } | |
181 | ||
182 | SCDLog(LOG_ERR, CFSTR("")); | |
183 | SCDLog(LOG_ERR, | |
184 | CFSTR("Defined sets include:%s"), | |
185 | (currentMatched > 0) ? " (* == current set)" : ""); | |
186 | ||
187 | for (i=0; i<nSets; i++) { | |
188 | CFStringRef key = (CFStringRef) setKeys[i]; | |
189 | CFDictionaryRef dict = (CFDictionaryRef)setVals[i]; | |
190 | CFStringRef udn = CFDictionaryGetValue(dict, kSCPropUserDefinedName); | |
191 | ||
192 | SCDLog(LOG_ERR, | |
193 | CFSTR(" %s %@\t(%@)"), | |
194 | ((currentMatched > 0) && CFEqual(key, current)) ? "*" : " ", | |
195 | key, | |
196 | udn ? udn : CFSTR("")); | |
197 | } | |
198 | ||
199 | switch (currentMatched) { | |
200 | case -2 : | |
201 | SCDLog(LOG_ERR, CFSTR("")); | |
202 | SCDLog(LOG_ERR, CFSTR("CurrentSet not defined")); | |
203 | break; | |
204 | case -1 : | |
205 | SCDLog(LOG_ERR, CFSTR("")); | |
206 | SCDLog(LOG_ERR, CFSTR("CurrentSet \"%@\" may not be valid"), current); | |
207 | break; | |
208 | case 0 : | |
209 | SCDLog(LOG_ERR, CFSTR("")); | |
210 | SCDLog(LOG_ERR, CFSTR("CurrentSet \"%@\" not valid"), current); | |
211 | break; | |
212 | default : | |
213 | break; | |
214 | } | |
215 | ||
216 | exit (1); | |
217 | ||
218 | found : | |
219 | ||
220 | status = SCPSet(session, kSCPrefCurrentSet, current); | |
221 | if (status != SCP_OK) { | |
222 | SCDLog(LOG_ERR, | |
223 | CFSTR("SCDSet(...,%@,%@) failed: %s"), | |
224 | kSCPrefCurrentSet, | |
225 | current, | |
226 | SCPError(status)); | |
227 | exit (1); | |
228 | } | |
229 | ||
230 | status = SCPCommit(session); | |
231 | if (status != SCP_OK) { | |
232 | SCDLog(LOG_ERR, CFSTR("SCPCommit() failed: %s"), SCPError(status)); | |
233 | exit (1); | |
234 | } | |
235 | ||
236 | if (apply) { | |
237 | status = SCPApply(session); | |
238 | if (status != SCP_OK) { | |
239 | SCDLog(LOG_ERR, CFSTR("SCPApply() failed: %s"), SCPError(status)); | |
240 | exit (1); | |
241 | } | |
242 | } | |
243 | ||
244 | status = SCPClose(&session); | |
245 | if (status != SCP_OK) { | |
246 | SCDLog(LOG_ERR, CFSTR("SCPClose() failed: %s"), SCPError(status)); | |
247 | exit (1); | |
248 | } | |
249 | ||
250 | SCDLog(LOG_NOTICE, | |
251 | CFSTR("%@ updated to %@ (%@)"), | |
252 | kSCPrefCurrentSet, | |
253 | newSet, | |
254 | newSetUDN ? newSetUDN : CFSTR("")); | |
255 | ||
256 | exit (0); | |
257 | return 0; | |
258 | } |