]>
Commit | Line | Data |
---|---|---|
5958d7c0 | 1 | /* |
6bb65964 | 2 | * Copyright (c) 2000-2011 Apple Inc. All rights reserved. |
5958d7c0 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
009ee3c6 | 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 | |
5958d7c0 A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
009ee3c6 A |
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 | * | |
5958d7c0 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
0fae82ee A |
24 | /* |
25 | * Modification History | |
26 | * | |
27 | * June 1, 2001 Allan Nathanson <ajn@apple.com> | |
28 | * - public API conversion | |
29 | * | |
30 | * November 9, 2000 Allan Nathanson <ajn@apple.com> | |
31 | * - initial revision | |
32 | */ | |
33 | ||
5958d7c0 A |
34 | #include <stdio.h> |
35 | #include <string.h> | |
36 | #include <sys/errno.h> | |
37 | ||
38 | #include "scutil.h" | |
39 | #include "commands.h" | |
40 | #include "dictionary.h" | |
41 | #include "session.h" | |
42 | #include "cache.h" | |
dbf6a266 | 43 | #include "notifications.h" |
5958d7c0 | 44 | #include "tests.h" |
dbf6a266 | 45 | #include "net.h" |
edebe297 | 46 | #include "prefs.h" |
5958d7c0 | 47 | |
5958d7c0 | 48 | |
dbf6a266 A |
49 | __private_extern__ |
50 | const cmdInfo commands_store[] = { | |
0fae82ee A |
51 | /* cmd minArgs maxArgs func group ctype */ |
52 | /* usage */ | |
5958d7c0 | 53 | |
0fae82ee A |
54 | { "help", 0, 0, do_help, 0, 0, |
55 | " help : list available commands" }, | |
5958d7c0 | 56 | |
0fae82ee A |
57 | { "f.read", 1, 1, do_readFile, 0, 0, |
58 | " f.read file : process commands from file" }, | |
5958d7c0 | 59 | |
dbf6a266 A |
60 | { "quit", 0, 0, do_quit, 0, 0, |
61 | " quit : quit" }, | |
62 | ||
63 | { "q", 0, 0, do_quit, 0, -1, | |
64 | NULL }, | |
65 | ||
66 | { "exit", 0, 0, do_quit, 0, -1, | |
67 | NULL }, | |
68 | ||
5958d7c0 A |
69 | /* local dictionary manipulation commands */ |
70 | ||
0fae82ee A |
71 | { "d.init", 0, 0, do_dictInit, 1, 0, |
72 | " d.init : initialize (empty) dictionary" }, | |
5958d7c0 | 73 | |
0fae82ee A |
74 | { "d.show", 0, 0, do_dictShow, 1, 0, |
75 | " d.show : show dictionary contents" }, | |
5958d7c0 | 76 | |
0fae82ee A |
77 | { "d.add", 2, 101, do_dictSetKey, 1, 0, |
78 | " d.add key [*#?] val [v2 ...] : add information to dictionary\n" | |
dbf6a266 | 79 | " (*=array, #=number, ?=boolean)" }, |
5958d7c0 | 80 | |
0fae82ee A |
81 | { "d.remove", 1, 1, do_dictRemoveKey, 1, 0, |
82 | " d.remove key : remove key from dictionary" }, | |
5958d7c0 | 83 | |
edebe297 | 84 | /* dynamic store manipulation commands */ |
5958d7c0 | 85 | |
dbf6a266 A |
86 | { "open", 0, 1, do_open, 2, 1, |
87 | " open [\"temporary\"] : open a session with \"configd\"" }, | |
0fae82ee | 88 | |
dbf6a266 | 89 | { "close", 0, 0, do_close, 2, 1, |
0fae82ee A |
90 | " close : close current \"configd\" session" }, |
91 | ||
92 | { "lock", 0, 0, do_lock, 3, 1, | |
edebe297 | 93 | " lock : locks write access to data store" }, |
5958d7c0 | 94 | |
0fae82ee | 95 | { "unlock", 0, 0, do_unlock, 3, 1, |
edebe297 | 96 | " unlock : unlocks write access to data store" }, |
5958d7c0 | 97 | |
0fae82ee A |
98 | { "list", 0, 2, do_list, 4, 0, |
99 | " list [pattern] : list keys in data store" }, | |
5958d7c0 | 100 | |
0fae82ee | 101 | { "add", 1, 2, do_add, 4, 0, |
dbf6a266 | 102 | " add key [\"temporary\"] : add key in data store w/current dict" }, |
5958d7c0 | 103 | |
0fae82ee A |
104 | { "get", 1, 1, do_get, 4, 0, |
105 | " get key : get dict from data store w/key" }, | |
5958d7c0 | 106 | |
0fae82ee | 107 | { "set", 1, 1, do_set, 4, 0, |
edebe297 | 108 | " set key : set key in data store w/current dict" }, |
5958d7c0 | 109 | |
009ee3c6 A |
110 | { "show", 1, 2, do_show, 4, 0, |
111 | " show key [\"pattern\"] : show values in data store w/key" }, | |
5958d7c0 | 112 | |
0fae82ee A |
113 | { "remove", 1, 1, do_remove, 4, 0, |
114 | " remove key : remove key from data store" }, | |
5958d7c0 | 115 | |
0fae82ee A |
116 | { "notify", 1, 1, do_notify, 4, 0, |
117 | " notify key : notify key in data store" }, | |
5958d7c0 | 118 | |
0fae82ee A |
119 | { "touch", 1, 1, do_touch, 4, 1, |
120 | " touch key : touch key in data store" }, | |
5958d7c0 | 121 | |
0fae82ee A |
122 | { "n.list", 0, 1, do_notify_list, 5, 0, |
123 | " n.list [\"pattern\"] : list notification keys" }, | |
5958d7c0 | 124 | |
0fae82ee | 125 | { "n.add", 1, 2, do_notify_add, 5, 0, |
dbf6a266 | 126 | " n.add key [\"pattern\"] : add notification key" }, |
5958d7c0 | 127 | |
0fae82ee A |
128 | { "n.remove", 1, 2, do_notify_remove, 5, 0, |
129 | " n.remove key [\"pattern\"] : remove notification key" }, | |
5958d7c0 | 130 | |
0fae82ee A |
131 | { "n.changes", 0, 0, do_notify_changes, 5, 0, |
132 | " n.changes : list changed keys" }, | |
5958d7c0 | 133 | |
a40a14f8 A |
134 | { "n.watch", 0, 0, do_notify_watch, 5, 0, |
135 | " n.watch : watch for changes" }, | |
5958d7c0 | 136 | |
0fae82ee A |
137 | { "n.wait", 0, 0, do_notify_wait, 5, 2, |
138 | " n.wait : wait for changes" }, | |
5958d7c0 | 139 | |
0fae82ee A |
140 | { "n.callback", 0, 1, do_notify_callback, 5, 2, |
141 | " n.callback [\"verbose\"] : watch for changes" }, | |
5958d7c0 | 142 | |
0fae82ee A |
143 | { "n.signal", 1, 2, do_notify_signal, 5, 2, |
144 | " n.signal sig [pid] : signal changes" }, | |
5958d7c0 | 145 | |
0fae82ee A |
146 | { "n.file", 0, 1, do_notify_file, 5, 2, |
147 | " n.file [identifier] : watch for changes via file" }, | |
5958d7c0 | 148 | |
0fae82ee A |
149 | { "n.cancel", 0, 1, do_notify_cancel, 5, 0, |
150 | " n.cancel : cancel notification requests" }, | |
5958d7c0 | 151 | |
dbf6a266 A |
152 | { "snapshot", 0, 0, do_snapshot, 99, 2, |
153 | " snapshot : save snapshot of store and session data" } | |
5958d7c0 | 154 | }; |
dbf6a266 A |
155 | __private_extern__ |
156 | const int nCommands_store = (sizeof(commands_store)/sizeof(cmdInfo)); | |
157 | ||
158 | ||
159 | __private_extern__ | |
edebe297 | 160 | const cmdInfo commands_net[] = { |
dbf6a266 A |
161 | /* cmd minArgs maxArgs func group ctype */ |
162 | /* usage */ | |
163 | ||
164 | { "help", 0, 0, do_help, 0, 0, | |
165 | " help : list available commands" }, | |
166 | ||
167 | { "f.read", 1, 1, do_readFile, 0, 0, | |
168 | " f.read file : process commands from file" }, | |
169 | ||
170 | { "quit", 0, 1, do_net_quit, 0, 0, | |
171 | " quit [!] : quit" }, | |
172 | ||
173 | { "q", 0, 1, do_net_quit, 0, -1, | |
174 | NULL }, | |
175 | ||
176 | { "exit", 0, 1, do_net_quit, 0, -1, | |
177 | NULL }, | |
178 | ||
179 | /* network configuration manipulation commands */ | |
180 | ||
181 | { "open", 0, 1, do_net_open, 2, 1, | |
182 | " open : open the network configuration" }, | |
183 | ||
184 | { "commit", 0, 0, do_net_commit, 2, 0, | |
185 | " commit : commit any changes" }, | |
186 | ||
187 | { "apply", 0, 0, do_net_apply, 2, 0, | |
188 | " apply : apply any changes" }, | |
5958d7c0 | 189 | |
dbf6a266 A |
190 | { "close", 0, 1, do_net_close, 2, 1, |
191 | " close [!] : close the network configuration" }, | |
5958d7c0 | 192 | |
dbf6a266 A |
193 | { "create", 1, 3, do_net_create, 3, 0, |
194 | " create interface <interfaceType> [ <interfaceName> | <interface#> ]\n" | |
195 | " create protocol <protocolType>\n" | |
196 | " create service [ <interfaceName> | <interface#> [ <serviceName> ]]\n" | |
197 | " create set [setName]" }, | |
0fae82ee | 198 | |
edebe297 | 199 | { "disable", 1, 2, do_net_disable, 4, 0, |
dbf6a266 A |
200 | " disable protocol [ <protocolType> ]\n" |
201 | " disable service [ <serviceName> | <service#> ]" }, | |
5958d7c0 | 202 | |
edebe297 | 203 | { "enable", 1, 2, do_net_enable, 5, 0, |
dbf6a266 A |
204 | " enable protocol [ <protocolType> ]\n" |
205 | " enable service [ <serviceName> | <service#> ]" }, | |
206 | ||
207 | { "remove", 1, 2, do_net_remove, 6, 0, | |
208 | " remove protocol [ <protocolType> ]\n" | |
209 | " remove service [ <serviceName> | <service#> ]\n" | |
210 | " remove set [ <setName> | <set#> ]" }, | |
211 | ||
a40a14f8 | 212 | { "select", 2, 3, do_net_select, 7, 0, |
6bb65964 | 213 | " select interface <interfaceName> | <interface#> | $child | $service | $vlan | $bond <memberName> | $bridge <memberName>\n" |
dbf6a266 A |
214 | " select protocol <protocolType>\n" |
215 | " select service <serviceName> | <service#>\n" | |
216 | " select set <setName> | <set#>" }, | |
217 | ||
218 | { "set", 2, 101, do_net_set, 8, 0, | |
219 | " set interface context-sensitive-arguments (or ? for help)\n" | |
220 | " set protocol context-sensitive-arguments (or ? for help)\n" | |
a40a14f8 | 221 | " set service [ name <serviceName> ] [ order new-order ] [ rank ("" | First | Last | Never) [temp] ]\n" |
6bb65964 | 222 | " set set [ name setName ] | [ current ]" }, |
dbf6a266 A |
223 | |
224 | { "show", 1, 2, do_net_show, 9, 0, | |
225 | " show interfaces\n" | |
226 | " show interface [ <interfaceName> | <interface#> ]\n" | |
227 | " show protocols\n" | |
228 | " show protocol [ <protocolType> ]\n" | |
229 | " show services [ all ]\n" | |
230 | " show service [ <serviceName> | <service#> ]\n" | |
231 | " show sets\n\n" | |
232 | " show set [ <setName> | <set#> ]" }, | |
233 | ||
edebe297 A |
234 | { "update", 0, 1, do_net_update, 10, 0, |
235 | " update : update the network configuration" }, | |
236 | ||
dbf6a266 A |
237 | { "snapshot", 0, 0, do_net_snapshot, 99, 2, |
238 | " snapshot" } | |
239 | ||
240 | }; | |
241 | __private_extern__ | |
edebe297 A |
242 | const int nCommands_net = (sizeof(commands_net)/sizeof(cmdInfo)); |
243 | ||
244 | ||
245 | __private_extern__ | |
246 | const cmdInfo commands_prefs[] = { | |
247 | /* cmd minArgs maxArgs func group ctype */ | |
248 | /* usage */ | |
249 | ||
250 | { "help", 0, 0, do_help, 0, 0, | |
251 | " help : list available commands" }, | |
252 | ||
253 | { "f.read", 1, 1, do_readFile, 0, 0, | |
254 | " f.read file : process commands from file" }, | |
255 | ||
256 | { "quit", 0, 1, do_prefs_quit, 0, 0, | |
257 | " quit [!] : quit" }, | |
258 | ||
259 | { "q", 0, 1, do_prefs_quit, 0, -1, | |
260 | NULL }, | |
261 | ||
262 | { "exit", 0, 1, do_prefs_quit, 0, -1, | |
263 | NULL }, | |
264 | ||
265 | /* local dictionary manipulation commands */ | |
266 | ||
267 | { "d.init", 0, 0, do_dictInit, 1, 0, | |
268 | " d.init : initialize (empty) dictionary" }, | |
269 | ||
270 | { "d.show", 0, 0, do_dictShow, 1, 0, | |
271 | " d.show : show dictionary contents" }, | |
272 | ||
273 | { "d.add", 2, 101, do_dictSetKey, 1, 0, | |
274 | " d.add key [*#?] val [v2 ...] : add information to dictionary\n" | |
275 | " (*=array, #=number, ?=boolean)" }, | |
276 | ||
277 | { "d.remove", 1, 1, do_dictRemoveKey, 1, 0, | |
278 | " d.remove key : remove key from dictionary" }, | |
279 | ||
280 | /* data store manipulation commands */ | |
281 | ||
282 | { "open", 0, 1, do_prefs_open, 2, 1, | |
a40a14f8 | 283 | " open [\"prefsID\"] : open a \"preferences\" session" }, |
edebe297 A |
284 | |
285 | { "lock", 0, 1, do_prefs_lock, 3, 1, | |
286 | " lock [wait] : locks write access to preferences" }, | |
287 | ||
288 | { "commit", 0, 0, do_prefs_commit, 2, 0, | |
289 | " commit : commit any changes" }, | |
290 | ||
291 | { "apply", 0, 0, do_prefs_apply, 2, 0, | |
292 | " apply : apply any changes" }, | |
293 | ||
294 | { "unlock", 0, 0, do_prefs_unlock, 3, 1, | |
295 | " unlock : unlocks write access to preferences" }, | |
296 | ||
297 | { "close", 0, 1, do_prefs_close, 2, 1, | |
298 | " close [!] : close current \"preference\" session" }, | |
299 | ||
6d034b4e A |
300 | { "synchronize",0, 1, do_prefs_synchronize, 2, 0, |
301 | " synchronize : synchronize a \"preferences\" session" }, | |
a40a14f8 | 302 | |
edebe297 A |
303 | { "list", 0, 1, do_prefs_list, 4, 0, |
304 | " list [path] : list preference paths" }, | |
305 | ||
306 | { "get", 1, 1, do_prefs_get, 4, 0, | |
307 | " get path : get dict from preferences w/path" }, | |
308 | ||
309 | { "set", 1, 2, do_prefs_set, 4, 0, | |
310 | " set path : set path in preferences w/current dict\n" | |
311 | " set path link : set path in preferences w/link" }, | |
312 | ||
313 | { "remove", 1, 1, do_prefs_remove, 4, 0, | |
314 | " remove path : remove path from preferences" } | |
315 | }; | |
316 | __private_extern__ | |
dbf6a266 A |
317 | const int nCommands_prefs = (sizeof(commands_prefs)/sizeof(cmdInfo)); |
318 | ||
319 | ||
320 | __private_extern__ cmdInfo *commands = NULL; | |
321 | __private_extern__ int nCommands = 0; | |
322 | __private_extern__ Boolean enablePrivateAPI = FALSE; | |
323 | __private_extern__ Boolean termRequested = FALSE; | |
324 | ||
325 | ||
326 | __private_extern__ | |
5958d7c0 A |
327 | void |
328 | do_command(int argc, char **argv) | |
329 | { | |
330 | int i; | |
331 | char *cmd = argv[0]; | |
332 | ||
009ee3c6 | 333 | for (i = 0; i < nCommands; i++) { |
0fae82ee A |
334 | if ((commands[i].ctype > 1) && !enablePrivateAPI) { |
335 | continue; /* if "private" API and access has not been enabled */ | |
336 | } | |
337 | ||
5958d7c0 A |
338 | if (strcasecmp(cmd, commands[i].cmd) == 0) { |
339 | --argc; | |
340 | argv++; | |
341 | if (argc < commands[i].minArgs) { | |
0fae82ee | 342 | SCPrint(TRUE, stdout, CFSTR("%s: too few arguments\n"), cmd); |
5958d7c0 A |
343 | return; |
344 | } else if (argc > commands[i].maxArgs) { | |
0fae82ee | 345 | SCPrint(TRUE, stdout, CFSTR("%s: too many arguments\n"), cmd); |
5958d7c0 A |
346 | return; |
347 | } | |
dbf6a266 | 348 | (*commands[i].func)(argc, argv); |
5958d7c0 A |
349 | return; |
350 | } | |
351 | } | |
352 | ||
0fae82ee | 353 | SCPrint(TRUE, stdout, CFSTR("%s: unknown, type \"help\" for command info\n"), cmd); |
5958d7c0 A |
354 | return; |
355 | } | |
356 | ||
357 | ||
dbf6a266 | 358 | __private_extern__ |
5958d7c0 A |
359 | void |
360 | do_help(int argc, char **argv) | |
361 | { | |
362 | int g = -1; /* current group */ | |
363 | int i; | |
364 | ||
0fae82ee | 365 | SCPrint(TRUE, stdout, CFSTR("\nAvailable commands:\n")); |
009ee3c6 | 366 | for (i = 0; i < nCommands; i++) { |
dbf6a266 A |
367 | if (commands[i].ctype < 0) { |
368 | continue; /* if "hidden" */ | |
369 | } | |
370 | ||
0fae82ee A |
371 | if ((commands[i].ctype > 0) && !enablePrivateAPI) { |
372 | continue; /* if "private" API and access has not been enabled */ | |
373 | } | |
374 | ||
375 | /* check if this is a new command group */ | |
5958d7c0 | 376 | if (g != commands[i].group) { |
0fae82ee | 377 | SCPrint(TRUE, stdout, CFSTR("\n")); |
5958d7c0 A |
378 | g = commands[i].group; |
379 | } | |
0fae82ee A |
380 | |
381 | /* display the command */ | |
382 | SCPrint(TRUE, stdout, CFSTR("%s\n"), commands[i].usage); | |
5958d7c0 | 383 | } |
0fae82ee | 384 | SCPrint(TRUE, stdout, CFSTR("\n")); |
5958d7c0 A |
385 | |
386 | return; | |
387 | } | |
388 | ||
389 | ||
dbf6a266 | 390 | __private_extern__ |
5958d7c0 A |
391 | void |
392 | do_readFile(int argc, char **argv) | |
393 | { | |
009ee3c6 | 394 | InputRef src; |
5958d7c0 | 395 | |
009ee3c6 A |
396 | /* allocate command input stream */ |
397 | src = (InputRef)CFAllocatorAllocate(NULL, sizeof(Input), 0); | |
398 | src->el = NULL; | |
6bb65964 | 399 | src->h = NULL; |
009ee3c6 A |
400 | src->fp = fopen(argv[0], "r"); |
401 | ||
402 | if (src->fp == NULL) { | |
0fae82ee | 403 | SCPrint(TRUE, stdout, CFSTR("f.read: could not open file (%s).\n"), strerror(errno)); |
009ee3c6 | 404 | CFAllocatorDeallocate(NULL, src); |
5958d7c0 A |
405 | return; |
406 | } | |
407 | ||
408 | /* open file, increase nesting level */ | |
0fae82ee | 409 | SCPrint(TRUE, stdout, CFSTR("f.read: reading file (%s).\n"), argv[0]); |
5958d7c0 A |
410 | nesting++; |
411 | ||
a40a14f8 A |
412 | while (TRUE) { |
413 | Boolean ok; | |
414 | ||
415 | ok = process_line(src); | |
416 | if (!ok) { | |
417 | break; | |
418 | } | |
009ee3c6 A |
419 | } |
420 | ||
421 | (void)fclose(src->fp); | |
422 | CFAllocatorDeallocate(NULL, src); | |
5958d7c0 A |
423 | |
424 | return; | |
425 | } | |
dbf6a266 A |
426 | |
427 | ||
428 | __private_extern__ | |
429 | void | |
430 | do_quit(int argc, char **argv) | |
431 | { | |
432 | termRequested = TRUE; | |
433 | return; | |
434 | } |