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