main.c revision 138076
1155192Srwatson
2155192Srwatson/*
3155406Srwatson * main.c
4155192Srwatson *
5155192Srwatson * Copyright (c) 1996-1999 Whistle Communications, Inc.
6155192Srwatson * All rights reserved.
7155192Srwatson *
8155192Srwatson * Subject to the following obligations and disclaimer of warranty, use and
9155192Srwatson * redistribution of this software, in source or object code forms, with or
10155192Srwatson * without modifications are expressly permitted by Whistle Communications;
11155192Srwatson * provided, however, that:
12155192Srwatson * 1. Any and all reproductions of the source or object code must include the
13155192Srwatson *    copyright notice above and the following disclaimer of warranties; and
14155192Srwatson * 2. No rights are granted, in any manner or form, to use Whistle
15155192Srwatson *    Communications, Inc. trademarks, including the mark "WHISTLE
16155192Srwatson *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17155192Srwatson *    such appears in the above copyright notice or in the software.
18155192Srwatson *
19155192Srwatson * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20155192Srwatson * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21155192Srwatson * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22155192Srwatson * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23155192Srwatson * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24155192Srwatson * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25155192Srwatson * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26155192Srwatson * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27155192Srwatson * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28155192Srwatson * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29155192Srwatson * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30155192Srwatson * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31155192Srwatson * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32155192Srwatson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33155192Srwatson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34155192Srwatson * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35155192Srwatson * OF SUCH DAMAGE.
36155192Srwatson *
37155192Srwatson * $FreeBSD: head/usr.sbin/ngctl/main.c 138076 2004-11-25 09:27:56Z maxim $
38155192Srwatson * $Whistle: main.c,v 1.12 1999/11/29 19:17:46 archie Exp $
39155192Srwatson */
40155192Srwatson
41155192Srwatson#include "ngctl.h"
42155192Srwatson
43155192Srwatson#define PROMPT			"+ "
44155192Srwatson#define MAX_ARGS		512
45164033Srwatson#define WHITESPACE		" \t\r\n\v\f"
46155192Srwatson#define DUMP_BYTES_PER_LINE	16
47155192Srwatson
48155192Srwatson/* Internal functions */
49155192Srwatsonstatic int	ReadFile(FILE *fp);
50155192Srwatsonstatic int	DoParseCommand(char *line);
51155192Srwatsonstatic int	DoCommand(int ac, char **av);
52155192Srwatsonstatic int	DoInteractive(void);
53155192Srwatsonstatic const	struct ngcmd *FindCommand(const char *string);
54155192Srwatsonstatic int	MatchCommand(const struct ngcmd *cmd, const char *s);
55155192Srwatsonstatic void	Usage(const char *msg);
56155192Srwatsonstatic int	ReadCmd(int ac, char **av);
57155192Srwatsonstatic int	HelpCmd(int ac, char **av);
58155192Srwatsonstatic int	QuitCmd(int ac, char **av);
59155192Srwatson
60155192Srwatson/* List of commands */
61155406Srwatsonstatic const struct ngcmd *const cmds[] = {
62156291Srwatson	&config_cmd,
63155406Srwatson	&connect_cmd,
64155406Srwatson	&debug_cmd,
65155192Srwatson	&dot_cmd,
66155192Srwatson	&help_cmd,
67155192Srwatson	&list_cmd,
68155192Srwatson	&mkpeer_cmd,
69155192Srwatson	&msg_cmd,
70155192Srwatson	&name_cmd,
71155406Srwatson	&read_cmd,
72155406Srwatson	&rmhook_cmd,
73156888Srwatson	&show_cmd,
74155192Srwatson	&shutdown_cmd,
75155192Srwatson	&status_cmd,
76155192Srwatson	&types_cmd,
77155192Srwatson	&write_cmd,
78155192Srwatson	&quit_cmd,
79155192Srwatson	NULL
80156889Srwatson};
81155192Srwatson
82155192Srwatson/* Commands defined in this file */
83156889Srwatsonconst struct ngcmd read_cmd = {
84155192Srwatson	ReadCmd,
85155192Srwatson	"read <filename>",
86156889Srwatson	"Read and execute commands from a file",
87156889Srwatson	NULL,
88155192Srwatson	{ "source", "." }
89155192Srwatson};
90162176Srwatsonconst struct ngcmd help_cmd = {
91162176Srwatson	HelpCmd,
92155192Srwatson	"help [command]",
93156889Srwatson	"Show command summary or get more help on a specific command",
94156889Srwatson	NULL,
95161813Swsalamon	{ "?" }
96161813Swsalamon};
97155192Srwatsonconst struct ngcmd quit_cmd = {
98155192Srwatson	QuitCmd,
99155192Srwatson	"quit",
100155192Srwatson	"Exit program",
101156889Srwatson	NULL,
102155192Srwatson	{ "exit" }
103155192Srwatson};
104156889Srwatson
105155192Srwatson/* Our control and data sockets */
106156889Srwatsonint	csock, dsock;
107155192Srwatson
108155192Srwatson/*
109155192Srwatson * main()
110155192Srwatson */
111156889Srwatsonint
112155192Srwatsonmain(int ac, char *av[])
113155192Srwatson{
114155192Srwatson	char	name[NG_NODESIZ];
115155192Srwatson	int	interactive = isatty(0) && isatty(1);
116155192Srwatson	FILE	*fp = NULL;
117156889Srwatson	int	ch, size, rtn = 0;
118155192Srwatson
119155192Srwatson	/* Set default node name */
120155192Srwatson	snprintf(name, sizeof(name), "ngctl%d", getpid());
121155192Srwatson
122155192Srwatson	/* Parse command line */
123155192Srwatson	while ((ch = getopt(ac, av, "df:n:")) != EOF) {
124155192Srwatson		switch (ch) {
125155192Srwatson		case 'd':
126155192Srwatson			NgSetDebug(NgSetDebug(-1) + 1);
127156889Srwatson			break;
128156889Srwatson		case 'f':
129156889Srwatson			if (strcmp(optarg, "-") == 0)
130155192Srwatson				fp = stdin;
131155192Srwatson			else if ((fp = fopen(optarg, "r")) == NULL)
132155192Srwatson				err(EX_NOINPUT, "%s", optarg);
133155192Srwatson			break;
134156889Srwatson		case 'n':
135155192Srwatson			snprintf(name, sizeof(name), "%s", optarg);
136155192Srwatson			break;
137155192Srwatson		case '?':
138155192Srwatson		default:
139155192Srwatson			Usage((char *)NULL);
140155192Srwatson			break;
141159261Srwatson		}
142155192Srwatson	}
143155192Srwatson	ac -= optind;
144159261Srwatson	av += optind;
145159261Srwatson
146159261Srwatson	/* Create a new socket node */
147155192Srwatson	if (NgMkSockNode(name, &csock, &dsock) < 0)
148159261Srwatson		err(EX_OSERR, "can't create node");
149155192Srwatson	size = 128 * 1024;
150156889Srwatson	if (setsockopt(csock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1)
151156889Srwatson		err(1, "setsockopt");
152156889Srwatson	/* Do commands as requested */
153155192Srwatson	if (ac == 0) {
154155192Srwatson		if (fp != NULL) {
155156889Srwatson			rtn = ReadFile(fp);
156155192Srwatson		} else if (interactive) {
157155192Srwatson			rtn = DoInteractive();
158155406Srwatson		} else
159155192Srwatson			Usage("no command specified");
160155406Srwatson	} else {
161155406Srwatson		rtn = DoCommand(ac, av);
162155406Srwatson	}
163155406Srwatson
164155406Srwatson	/* Convert command return code into system exit code */
165155406Srwatson	switch (rtn) {
166155406Srwatson	case CMDRTN_OK:
167155406Srwatson	case CMDRTN_QUIT:
168155406Srwatson		rtn = 0;
169155406Srwatson		break;
170155406Srwatson	case CMDRTN_USAGE:
171155406Srwatson		rtn = EX_USAGE;
172155406Srwatson		break;
173155406Srwatson	case CMDRTN_ERROR:
174155406Srwatson		rtn = EX_OSERR;
175155406Srwatson		break;
176155406Srwatson	}
177155406Srwatson	return(rtn);
178155406Srwatson}
179155406Srwatson
180155406Srwatson/*
181159415Srwatson * Process commands from a file
182155406Srwatson */
183155406Srwatsonstatic int
184155406SrwatsonReadFile(FILE *fp)
185155406Srwatson{
186155406Srwatson	char line[LINE_MAX];
187155406Srwatson	int num, rtn;
188159415Srwatson
189155406Srwatson	for (num = 1; fgets(line, sizeof(line), fp) != NULL; num++) {
190155406Srwatson		if (*line == '#')
191155406Srwatson			continue;
192155406Srwatson		if ((rtn = DoParseCommand(line)) != 0) {
193155192Srwatson			warnx("line %d: error in file", num);
194155406Srwatson			return(rtn);
195155192Srwatson		}
196155406Srwatson	}
197155192Srwatson	return(CMDRTN_OK);
198155406Srwatson}
199155406Srwatson
200155406Srwatson/*
201155406Srwatson * Interactive mode
202155192Srwatson */
203155406Srwatsonstatic int
204155192SrwatsonDoInteractive(void)
205155406Srwatson{
206155192Srwatson	const int maxfd = MAX(csock, dsock) + 1;
207155406Srwatson
208155192Srwatson	(*help_cmd.func)(0, NULL);
209161813Swsalamon	while (1) {
210161813Swsalamon		struct timeval tv;
211161813Swsalamon		fd_set rfds;
212161813Swsalamon
213155192Srwatson		/* See if any data or control messages are arriving */
214155192Srwatson		FD_ZERO(&rfds);
215155192Srwatson		FD_SET(csock, &rfds);
216155192Srwatson		FD_SET(dsock, &rfds);
217155192Srwatson		memset(&tv, 0, sizeof(tv));
218155192Srwatson		if (select(maxfd, &rfds, NULL, NULL, &tv) <= 0) {
219155192Srwatson
220155192Srwatson			/* Issue prompt and wait for anything to happen */
221155192Srwatson			printf("%s", PROMPT);
222155192Srwatson			fflush(stdout);
223155192Srwatson			FD_ZERO(&rfds);
224155192Srwatson			FD_SET(0, &rfds);
225155192Srwatson			FD_SET(csock, &rfds);
226155192Srwatson			FD_SET(dsock, &rfds);
227155192Srwatson			if (select(maxfd, &rfds, NULL, NULL, NULL) < 0)
228155192Srwatson				err(EX_OSERR, "select");
229155192Srwatson
230161813Swsalamon			/* If not user input, print a newline first */
231161813Swsalamon			if (!FD_ISSET(0, &rfds))
232155192Srwatson				printf("\n");
233155192Srwatson		}
234156889Srwatson
235155192Srwatson		/* Display any incoming control message */
236155192Srwatson		if (FD_ISSET(csock, &rfds))
237155192Srwatson			MsgRead();
238155192Srwatson
239155192Srwatson		/* Display any incoming data packet */
240155192Srwatson		if (FD_ISSET(dsock, &rfds)) {
241155192Srwatson			u_char *buf;
242155192Srwatson			char hook[NG_HOOKSIZ];
243155192Srwatson			int rl;
244155192Srwatson
245155192Srwatson			/* Read packet from socket */
246155192Srwatson			if ((rl = NgAllocRecvData(dsock, &buf, hook)) < 0)
247159261Srwatson				err(EX_OSERR, "reading hook \"%s\"", hook);
248159261Srwatson			if (rl == 0)
249155192Srwatson				errx(EX_OSERR, "EOF from hook \"%s\"?", hook);
250155192Srwatson
251159266Srwatson			/* Write packet to stdout */
252155406Srwatson			printf("Rec'd data packet on hook \"%s\":\n", hook);
253155406Srwatson			DumpAscii(buf, rl);
254155406Srwatson			free(buf);
255155192Srwatson		}
256155192Srwatson
257155192Srwatson		/* Get any user input */
258155192Srwatson		if (FD_ISSET(0, &rfds)) {
259155192Srwatson			char buf[LINE_MAX];
260155192Srwatson
261155192Srwatson			if (fgets(buf, sizeof(buf), stdin) == NULL) {
262155192Srwatson				printf("\n");
263155192Srwatson				break;
264156888Srwatson			}
265156888Srwatson			if (DoParseCommand(buf) == CMDRTN_QUIT)
266155192Srwatson				break;
267155192Srwatson		}
268155192Srwatson	}
269155192Srwatson	return(CMDRTN_QUIT);
270155192Srwatson}
271155192Srwatson
272155192Srwatson/*
273155192Srwatson * Parse a command line and execute the command
274155192Srwatson */
275155192Srwatsonstatic int
276155192SrwatsonDoParseCommand(char *line)
277155192Srwatson{
278155192Srwatson	char *av[MAX_ARGS];
279155192Srwatson	int ac;
280155192Srwatson
281155192Srwatson	/* Parse line */
282155192Srwatson	for (ac = 0, av[0] = strtok(line, WHITESPACE);
283155192Srwatson	    ac < MAX_ARGS - 1 && av[ac];
284155192Srwatson	    av[++ac] = strtok(NULL, WHITESPACE));
285155192Srwatson
286155192Srwatson	/* Do command */
287155192Srwatson	return(DoCommand(ac, av));
288155192Srwatson}
289155192Srwatson
290155192Srwatson/*
291155192Srwatson * Execute the command
292155192Srwatson */
293155192Srwatsonstatic int
294155192SrwatsonDoCommand(int ac, char **av)
295155192Srwatson{
296155192Srwatson	const struct ngcmd *cmd;
297155192Srwatson	int rtn;
298155192Srwatson
299155192Srwatson	if (ac == 0 || *av[0] == 0)
300155192Srwatson		return(CMDRTN_OK);
301155192Srwatson	if ((cmd = FindCommand(av[0])) == NULL)
302155192Srwatson		return(CMDRTN_ERROR);
303155192Srwatson	if ((rtn = (*cmd->func)(ac, av)) == CMDRTN_USAGE)
304155192Srwatson		warnx("usage: %s", cmd->cmd);
305155192Srwatson	return(rtn);
306155192Srwatson}
307155192Srwatson
308155406Srwatson/*
309155406Srwatson * Find a command
310155406Srwatson */
311155406Srwatsonstatic const struct ngcmd *
312155406SrwatsonFindCommand(const char *string)
313155192Srwatson{
314155192Srwatson	int k, found = -1;
315155192Srwatson
316155406Srwatson	for (k = 0; cmds[k] != NULL; k++) {
317155192Srwatson		if (MatchCommand(cmds[k], string)) {
318155192Srwatson			if (found != -1) {
319155406Srwatson				warnx("\"%s\": ambiguous command", string);
320155406Srwatson				return(NULL);
321155192Srwatson			}
322155192Srwatson			found = k;
323155192Srwatson		}
324155192Srwatson	}
325155192Srwatson	if (found == -1) {
326155192Srwatson		warnx("\"%s\": unknown command", string);
327155192Srwatson		return(NULL);
328155192Srwatson	}
329156888Srwatson	return(cmds[found]);
330156888Srwatson}
331156888Srwatson
332156888Srwatson/*
333156888Srwatson * See if string matches a prefix of "cmd" (or an alias) case insensitively
334156888Srwatson */
335156888Srwatsonstatic int
336155192SrwatsonMatchCommand(const struct ngcmd *cmd, const char *s)
337155192Srwatson{
338155192Srwatson	int a;
339155192Srwatson
340155192Srwatson	/* Try to match command, ignoring the usage stuff */
341155192Srwatson	if (strlen(s) <= strcspn(cmd->cmd, WHITESPACE)) {
342159269Srwatson		if (strncasecmp(s, cmd->cmd, strlen(s)) == 0)
343159269Srwatson			return (1);
344159269Srwatson	}
345155192Srwatson
346155192Srwatson	/* Try to match aliases */
347155192Srwatson	for (a = 0; a < MAX_CMD_ALIAS && cmd->aliases[a] != NULL; a++) {
348155192Srwatson		if (strlen(cmd->aliases[a]) >= strlen(s)) {
349155192Srwatson			if (strncasecmp(s, cmd->aliases[a], strlen(s)) == 0)
350155192Srwatson				return (1);
351155192Srwatson		}
352155192Srwatson	}
353155192Srwatson
354155192Srwatson	/* No match */
355155192Srwatson	return (0);
356155192Srwatson}
357155192Srwatson
358155192Srwatson/*
359155192Srwatson * ReadCmd()
360155192Srwatson */
361155192Srwatsonstatic int
362156889SrwatsonReadCmd(int ac, char **av)
363155192Srwatson{
364155192Srwatson	FILE *fp;
365155192Srwatson	int rtn;
366155192Srwatson
367155192Srwatson	/* Open file */
368155192Srwatson	switch (ac) {
369155192Srwatson	case 2:
370155192Srwatson		if ((fp = fopen(av[1], "r")) == NULL) {
371155192Srwatson			warn("%s", av[1]);
372156889Srwatson			return(CMDRTN_ERROR);
373155192Srwatson		}
374155192Srwatson		break;
375155192Srwatson	default:
376155192Srwatson		return(CMDRTN_USAGE);
377155192Srwatson	}
378155192Srwatson
379155192Srwatson	/* Process it */
380155192Srwatson	rtn = ReadFile(fp);
381155192Srwatson	fclose(fp);
382155192Srwatson	return(rtn);
383155192Srwatson}
384155192Srwatson
385155192Srwatson/*
386155192Srwatson * HelpCmd()
387155192Srwatson */
388155192Srwatsonstatic int
389155192SrwatsonHelpCmd(int ac, char **av)
390159269Srwatson{
391159269Srwatson	const struct ngcmd *cmd;
392159269Srwatson	int k;
393155192Srwatson
394159269Srwatson	switch (ac) {
395159269Srwatson	case 0:
396159269Srwatson	case 1:
397159269Srwatson		/* Show all commands */
398159269Srwatson		printf("Available commands:\n");
399159269Srwatson		for (k = 0; cmds[k] != NULL; k++) {
400162380Scsjp			char *s, buf[100];
401162380Scsjp
402155192Srwatson			cmd = cmds[k];
403155192Srwatson			snprintf(buf, sizeof(buf), "%s", cmd->cmd);
404155192Srwatson			for (s = buf; *s != '\0' && !isspace(*s); s++);
405159275Srwatson			*s = '\0';
406155192Srwatson			printf("  %-10s %s\n", buf, cmd->desc);
407155192Srwatson		}
408155192Srwatson		return(CMDRTN_OK);
409155192Srwatson	default:
410155192Srwatson		/* Show help on a specific command */
411155192Srwatson		if ((cmd = FindCommand(av[1])) != NULL) {
412155192Srwatson			printf("usage:    %s\n", cmd->cmd);
413155192Srwatson			if (cmd->aliases[0] != NULL) {
414155192Srwatson				int a = 0;
415155192Srwatson
416155192Srwatson				printf("Aliases:  ");
417155192Srwatson				while (1) {
418155192Srwatson					printf("%s", cmd->aliases[a++]);
419155192Srwatson					if (a == MAX_CMD_ALIAS
420155192Srwatson					    || cmd->aliases[a] == NULL) {
421155192Srwatson						printf("\n");
422155192Srwatson						break;
423155192Srwatson					}
424155192Srwatson					printf(", ");
425155192Srwatson				}
426155192Srwatson			}
427155192Srwatson			printf("Summary:  %s\n", cmd->desc);
428155192Srwatson			if (cmd->help != NULL) {
429155192Srwatson				const char *s;
430155192Srwatson				char buf[65];
431159275Srwatson				int tot, len, done;
432155192Srwatson
433155192Srwatson				printf("Description:\n");
434156889Srwatson				for (s = cmd->help; *s != '\0'; s += len) {
435155192Srwatson					while (isspace(*s))
436155192Srwatson						s++;
437155192Srwatson					tot = snprintf(buf,
438155192Srwatson					    sizeof(buf), "%s", s);
439155192Srwatson					len = strlen(buf);
440155192Srwatson					done = len == tot;
441155192Srwatson					if (!done) {
442159261Srwatson						while (len > 0
443155192Srwatson						    && !isspace(buf[len-1]))
444155192Srwatson							buf[--len] = '\0';
445155192Srwatson					}
446155192Srwatson					printf("  %s\n", buf);
447155192Srwatson				}
448155192Srwatson			}
449155192Srwatson		}
450159261Srwatson	}
451155192Srwatson	return(CMDRTN_OK);
452155192Srwatson}
453155192Srwatson
454155192Srwatson/*
455155192Srwatson * QuitCmd()
456155192Srwatson */
457155192Srwatsonstatic int
458155192SrwatsonQuitCmd(int ac __unused, char **av __unused)
459155192Srwatson{
460155192Srwatson	return(CMDRTN_QUIT);
461155192Srwatson}
462155192Srwatson
463155192Srwatson/*
464159269Srwatson * Dump data in hex and ASCII form
465159269Srwatson */
466159269Srwatsonvoid
467155192SrwatsonDumpAscii(const u_char *buf, int len)
468155192Srwatson{
469155192Srwatson	char ch, sbuf[100];
470155192Srwatson	int k, count;
471155192Srwatson
472155192Srwatson	for (count = 0; count < len; count += DUMP_BYTES_PER_LINE) {
473155192Srwatson		snprintf(sbuf, sizeof(sbuf), "%04x:  ", count);
474155192Srwatson		for (k = 0; k < DUMP_BYTES_PER_LINE; k++) {
475162950Srwatson			if (count + k < len) {
476162950Srwatson				snprintf(sbuf + strlen(sbuf),
477155192Srwatson				    sizeof(sbuf) - strlen(sbuf),
478155192Srwatson				    "%02x ", buf[count + k]);
479155192Srwatson			} else {
480155192Srwatson				snprintf(sbuf + strlen(sbuf),
481159269Srwatson				    sizeof(sbuf) - strlen(sbuf), "   ");
482159269Srwatson			}
483155192Srwatson		}
484155192Srwatson		snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " ");
485155192Srwatson		for (k = 0; k < DUMP_BYTES_PER_LINE; k++) {
486155192Srwatson			if (count + k < len) {
487155192Srwatson				ch = isprint(buf[count + k]) ?
488155192Srwatson				    buf[count + k] : '.';
489159269Srwatson				snprintf(sbuf + strlen(sbuf),
490159269Srwatson				    sizeof(sbuf) - strlen(sbuf), "%c", ch);
491155192Srwatson			} else {
492155192Srwatson				snprintf(sbuf + strlen(sbuf),
493155192Srwatson				    sizeof(sbuf) - strlen(sbuf), " ");
494156889Srwatson			}
495155192Srwatson		}
496156889Srwatson		printf("%s\n", sbuf);
497155192Srwatson	}
498155192Srwatson}
499159269Srwatson
500159269Srwatson/*
501155192Srwatson * Usage()
502155192Srwatson */
503155192Srwatsonstatic void
504155192SrwatsonUsage(const char *msg)
505155192Srwatson{
506155192Srwatson	if (msg)
507155192Srwatson		warnx("%s", msg);
508155192Srwatson	fprintf(stderr,
509155192Srwatson		"usage: ngctl [-d] [-f file] [-n name] [command ...]\n");
510155192Srwatson	exit(EX_USAGE);
511155192Srwatson}
512155192Srwatson