1118824Sharti/*
2118824Sharti * Copyright (c) 2001-2003
3118824Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4118824Sharti * 	All rights reserved.
5118824Sharti *
6118824Sharti * Redistribution and use in source and binary forms, with or without
7118824Sharti * modification, are permitted provided that the following conditions
8118824Sharti * are met:
9118824Sharti * 1. Redistributions of source code must retain the above copyright
10118824Sharti *    notice, this list of conditions and the following disclaimer.
11118824Sharti * 2. Redistributions in binary form must reproduce the above copyright
12118824Sharti *    notice, this list of conditions and the following disclaimer in the
13118824Sharti *    documentation and/or other materials provided with the distribution.
14118824Sharti *
15118824Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16118824Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17118824Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18118824Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19118824Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20118824Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21118824Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22118824Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23118824Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24118824Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25118824Sharti * SUCH DAMAGE.
26118824Sharti *
27118824Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28118824Sharti */
29118824Sharti#include <sys/cdefs.h>
30118824Sharti__FBSDID("$FreeBSD: releng/11.0/sbin/atm/atmconfig/main.c 270027 2014-08-15 21:22:49Z ngie $");
31118824Sharti
32118824Sharti#include <sys/types.h>
33118824Sharti#include <sys/sysctl.h>
34118824Sharti#include <netdb.h>
35118824Sharti#include <stdarg.h>
36118824Sharti#include <ctype.h>
37118824Sharti#include <limits.h>
38132493Sharti#include <stdint.h>
39132493Sharti#include <fnmatch.h>
40132493Sharti#include <dirent.h>
41270027Sngie#ifdef WITH_BSNMP
42133565Sharti#include <bsnmp/asn1.h>
43133565Sharti#include <bsnmp/snmp.h>
44133565Sharti#include <bsnmp/snmpclient.h>
45133565Sharti#endif
46133565Sharti
47118824Sharti#include "atmconfig.h"
48118824Sharti#include "private.h"
49118824Sharti
50118824Sharti/* verbosity level */
51227081Sedstatic int verbose;
52118824Sharti
53118824Sharti/* notitle option */
54118824Shartistatic int notitle;
55118824Sharti
56118824Sharti/* need to put heading before next output */
57118824Shartistatic int need_heading;
58118824Sharti
59118824Sharti/*
60118824Sharti * TOP LEVEL commands
61118824Sharti */
62118824Shartistatic void help_func(int argc, char *argv[]) __dead2;
63118824Sharti
64133565Shartistatic const struct cmdtab static_main_tab[] = {
65118824Sharti	{ "help",	NULL,		help_func },
66118824Sharti	{ "options",	NULL,		NULL },
67118824Sharti	{ "commands",	NULL,		NULL },
68118824Sharti	{ "diag",	diag_tab,	NULL },
69118824Sharti	{ "natm",	natm_tab,	NULL },
70118824Sharti	{ NULL,		NULL,		NULL }
71118824Sharti};
72118824Sharti
73133565Shartistatic struct cmdtab *main_tab = NULL;
74133565Shartistatic size_t main_tab_size = sizeof(static_main_tab) /
75133565Sharti	sizeof(static_main_tab[0]);
76133565Sharti
77118824Shartistatic int
78118824Shartisubstr(const char *s1, const char *s2)
79118824Sharti{
80118824Sharti	return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0);
81118824Sharti}
82118824Sharti
83118824Sharti/*
84132493Sharti * Current help file state
85132493Sharti */
86132493Shartistruct help_file {
87132493Sharti	int	file_state;	/* 0:looking for main file, 1:found, 2:other */
88132493Sharti	const char *p_start;	/* current path pointer */
89132493Sharti	const char *p_end;	/* end of current path in path */
90132493Sharti	char	*dirname;	/* directory name */
91132493Sharti	DIR	*dir;		/* open directory */
92132493Sharti	char	*fname;		/* current filename */
93132493Sharti	FILE	*fp;		/* open file */
94132493Sharti	char	line[LINE_MAX];	/* current line */
95132493Sharti	u_int	fcnt;		/* count of files found */
96132493Sharti};
97132493Sharti
98132493Shartistruct help_pos {
99132493Sharti	off_t	pos;		/* file position */
100132493Sharti	u_int	fcnt;		/* number of file */
101132493Sharti	char	*fname;		/* name of file */
102132493Sharti	const char *p_start;	/* current path pointer */
103132493Sharti	const char *p_end;	/* end of current path in path */
104132493Sharti};
105132493Sharti
106132493Shartistatic int
107132493Shartihelp_next_file(struct help_file *hp)
108132493Sharti{
109132493Sharti	const char *fpat;
110132493Sharti	struct dirent *ent;
111132493Sharti
112132493Sharti	if (hp->file_state == 3)
113132493Sharti		return (-1);
114132493Sharti
115132493Sharti	if (hp->file_state == 0)
116132493Sharti		fpat = FILE_HELP;
117132493Sharti	else
118132493Sharti		fpat = FILE_HELP_OTHERS;
119132493Sharti
120132493Sharti	if (hp->file_state == 0 || hp->file_state == 1) {
121132493Sharti		/* start from beginning */
122132493Sharti		hp->p_start = PATH_HELP;
123132493Sharti		hp->file_state++;
124132493Sharti	}
125132493Sharti
126132493Sharti  try_file:
127132493Sharti	if (hp->dir != NULL) {
128132493Sharti		/* directory open (must be state 2) */
129132493Sharti		while ((ent = readdir(hp->dir)) != NULL) {
130132493Sharti			if (fnmatch(fpat, ent->d_name, FNM_NOESCAPE) != 0)
131132493Sharti				continue;
132132493Sharti			if (asprintf(&hp->fname, "%s/%s", hp->dirname,
133132493Sharti			    ent->d_name) == -1)
134132493Sharti				err(1, NULL);
135132493Sharti			if ((hp->fp = fopen(hp->fname, "r")) != NULL) {
136132493Sharti				hp->fcnt++;
137132493Sharti				return (0);
138132493Sharti			}
139132493Sharti			free(hp->fname);
140132493Sharti		}
141132493Sharti		/* end of directory */
142132493Sharti		closedir(hp->dir);
143132493Sharti		hp->dir = NULL;
144132493Sharti		free(hp->dirname);
145132493Sharti		goto next_path;
146132493Sharti	}
147132493Sharti
148132493Sharti	/* nothing open - advanc to new path element */
149132493Sharti  try_path:
150132493Sharti	for (hp->p_end = hp->p_start; *hp->p_end != '\0' &&
151132493Sharti	    *hp->p_end != ':'; hp->p_end++)
152132493Sharti		;
153132493Sharti
154132493Sharti	if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start),
155132493Sharti	    hp->p_start) == -1)
156132493Sharti		err(1, NULL);
157132493Sharti
158132493Sharti	if (hp->file_state == 1) {
159132493Sharti		/* just try to open */
160132493Sharti		if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1)
161132493Sharti			err(1, NULL);
162132493Sharti		if ((hp->fp = fopen(hp->fname, "r")) != NULL) {
163132493Sharti			hp->fcnt++;
164132493Sharti			return (0);
165132493Sharti		}
166132493Sharti		free(hp->fname);
167132493Sharti
168132493Sharti		goto next_path;
169132493Sharti	}
170132493Sharti
171132493Sharti	/* open directory */
172132493Sharti	if ((hp->dir = opendir(hp->dirname)) != NULL)
173132493Sharti		goto try_file;
174132493Sharti
175132493Sharti	free(hp->dirname);
176132493Sharti
177132493Sharti  next_path:
178132493Sharti	hp->p_start = hp->p_end;
179132493Sharti	if (*hp->p_start == '\0') {
180132493Sharti		/* end of path */
181132493Sharti		if (hp->file_state == 1)
182132493Sharti			errx(1, "help file not found");
183132493Sharti		return (-1);
184132493Sharti	}
185132493Sharti	hp->p_start++;
186132493Sharti	goto try_path;
187132493Sharti
188132493Sharti}
189132493Sharti
190132493Sharti/*
191132493Sharti * Save current file position
192132493Sharti */
193132493Shartistatic void
194132493Shartihelp_file_tell(struct help_file *hp, struct help_pos *pos)
195132493Sharti{
196132493Sharti	if (pos->fname != NULL)
197132493Sharti		free(pos->fname);
198132493Sharti	if ((pos->fname = strdup(hp->fname)) == NULL)
199132493Sharti		err(1, NULL);
200132493Sharti	pos->fcnt = hp->fcnt;
201132493Sharti	pos->p_start = hp->p_start;
202132493Sharti	pos->p_end = hp->p_end;
203132493Sharti	if ((pos->pos = ftello(hp->fp)) == -1)
204132493Sharti		err(1, "%s", pos->fname);
205132493Sharti}
206132493Sharti
207132493Sharti/*
208132493Sharti * Go to that position
209132493Sharti *
210132493Sharti * We can go either to the original help file or back in the current file.
211132493Sharti */
212132493Shartistatic void
213132493Shartihelp_file_seek(struct help_file *hp, struct help_pos *pos)
214132493Sharti{
215132493Sharti	hp->p_start = pos->p_start;
216132493Sharti	hp->p_end = pos->p_end;
217132493Sharti	hp->fcnt = pos->fcnt;
218132493Sharti
219132493Sharti	if (hp->dir != NULL) {
220132493Sharti		free(hp->dirname);
221132493Sharti		closedir(hp->dir);
222132493Sharti		hp->dir = NULL;
223132493Sharti	}
224132493Sharti
225132493Sharti	if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) {
226132493Sharti		free(hp->fname);
227132493Sharti		fclose(hp->fp);
228132493Sharti		hp->fp = NULL;
229132493Sharti	}
230132493Sharti	if (hp->fp == NULL) {
231132493Sharti		if ((hp->fname = strdup(pos->fname)) == NULL)
232132493Sharti			err(1, NULL);
233132493Sharti		if ((hp->fp = fopen(hp->fname, "r")) == NULL)
234132493Sharti			err(1, "reopen %s", hp->fname);
235132493Sharti	}
236132493Sharti	if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1)
237132493Sharti		err(1, "seek %s", hp->fname);
238132493Sharti
239132493Sharti	if (pos->fcnt == 1)
240132493Sharti		/* go back to state 1 */
241132493Sharti		hp->file_state = 1;
242132493Sharti	else
243132493Sharti		/* lock */
244132493Sharti		hp->file_state = 3;
245132493Sharti}
246132493Sharti
247132493Sharti/*
248132493Sharti * Rewind to position 0
249132493Sharti */
250132493Shartistatic void
251132493Shartihelp_file_rewind(struct help_file *hp)
252132493Sharti{
253132493Sharti
254132493Sharti	if (hp->file_state == 1) {
255132493Sharti		if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1)
256132493Sharti			err(1, "rewind help file");
257132493Sharti		return;
258132493Sharti	}
259132493Sharti
260132493Sharti	if (hp->dir != NULL) {
261132493Sharti		free(hp->dirname);
262132493Sharti		closedir(hp->dir);
263132493Sharti		hp->dir = NULL;
264132493Sharti	}
265132493Sharti
266132493Sharti	if (hp->fp != NULL) {
267132493Sharti		free(hp->fname);
268132493Sharti		fclose(hp->fp);
269132493Sharti		hp->fp = NULL;
270132493Sharti	}
271132493Sharti	memset(hp, 0, sizeof(*hp));
272132493Sharti}
273132493Sharti
274132493Sharti/*
275132493Sharti * Get next line from a help file
276132493Sharti */
277132493Shartistatic const char *
278132493Shartihelp_next_line(struct help_file *hp)
279132493Sharti{
280132493Sharti	for (;;) {
281132493Sharti		if (hp->fp != NULL) {
282132493Sharti			if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL)
283132493Sharti				return (hp->line);
284132493Sharti			if (ferror(hp->fp))
285132493Sharti				err(1, "%s", hp->fname);
286132493Sharti			free(hp->fname);
287132493Sharti
288132493Sharti			fclose(hp->fp);
289132493Sharti			hp->fp = NULL;
290132493Sharti		}
291132493Sharti		if (help_next_file(hp) == -1)
292132493Sharti			return (NULL);
293132493Sharti	}
294132493Sharti
295132493Sharti}
296132493Sharti
297132493Sharti/*
298132493Sharti * This function prints the available 0-level help topics from all
299132493Sharti * other help files by scanning the files. It assumes, that this is called
300132493Sharti * only from the main help file.
301132493Sharti */
302132493Shartistatic void
303132493Shartihelp_get_0topics(struct help_file *hp)
304132493Sharti{
305132493Sharti	struct help_pos save;
306132493Sharti	const char *line;
307132493Sharti
308132493Sharti	memset(&save, 0, sizeof(save));
309132493Sharti	help_file_tell(hp, &save);
310132493Sharti
311132493Sharti	help_file_rewind(hp);
312132493Sharti	while ((line = help_next_line(hp)) != NULL) {
313132493Sharti		if (line[0] == '^' && line[1] == '^')
314132493Sharti			printf("%s", line + 2);
315132493Sharti	}
316132493Sharti	help_file_seek(hp, &save);
317132493Sharti}
318132493Sharti
319132493Sharti/*
320118824Sharti * Function to print help. The help argument is in argv[0] here.
321118824Sharti */
322118824Shartistatic void
323118824Shartihelp_func(int argc, char *argv[])
324118824Sharti{
325132493Sharti	struct help_file hfile;
326132493Sharti	struct help_pos match, last_match;
327132493Sharti	const char *line;
328118824Sharti	char key[100];
329132493Sharti	int level;
330132493Sharti	int i, has_sub_topics;
331118824Sharti
332132493Sharti	memset(&hfile, 0, sizeof(hfile));
333132493Sharti	memset(&match, 0, sizeof(match));
334132493Sharti	memset(&last_match, 0, sizeof(last_match));
335118824Sharti
336118824Sharti	if (argc == 0) {
337132493Sharti		/* only 'help' - show intro */
338119172Sharti		if ((argv[0] = strdup("intro")) == NULL)
339119172Sharti			err(1, NULL);
340118824Sharti		argc = 1;
341118824Sharti	}
342118824Sharti
343118824Sharti	optind = 0;
344132493Sharti	match.pos = -1;
345132493Sharti	last_match.pos = -1;
346118824Sharti	for (;;) {
347118824Sharti		/* read next line */
348132493Sharti		if ((line = help_next_line(&hfile)) == NULL) {
349118824Sharti			/* EOF */
350118824Sharti			level = 999;
351118824Sharti			goto stop;
352118824Sharti		}
353132493Sharti		if (line[0] != '^' || line[1] == '^')
354118824Sharti			continue;
355118824Sharti
356118824Sharti		if (sscanf(line + 1, "%d%99s", &level, key) != 2)
357118824Sharti			errx(1, "error in help file '%s'", line);
358118824Sharti
359118824Sharti		if (level < optind) {
360118824Sharti  stop:
361118824Sharti			/* next higher level entry - stop this level */
362132493Sharti			if (match.pos == -1) {
363118824Sharti				/* not found */
364118824Sharti				goto not_found;
365118824Sharti			}
366118824Sharti			/* go back to the match */
367132493Sharti			help_file_seek(&hfile, &match);
368118824Sharti			last_match = match;
369132493Sharti			memset(&match, 0, sizeof(match));
370132493Sharti			match.pos = -1;
371118824Sharti
372118824Sharti			/* go to next key */
373118824Sharti			if (++optind >= argc)
374118824Sharti				break;
375118824Sharti		}
376118824Sharti		if (level == optind) {
377118824Sharti			if (substr(argv[optind], key)) {
378132493Sharti				if (match.pos != -1) {
379118824Sharti					printf("Ambiguous topic.");
380118824Sharti					goto list_topics;
381118824Sharti				}
382132493Sharti				help_file_tell(&hfile, &match);
383118824Sharti			}
384118824Sharti		}
385118824Sharti	}
386118824Sharti
387132493Sharti	/* before breaking above we have seeked back to the matching point */
388118824Sharti	for (;;) {
389132493Sharti		if ((line = help_next_line(&hfile)) == NULL)
390118824Sharti			break;
391132493Sharti
392118824Sharti		if (line[0] == '#')
393118824Sharti			continue;
394132493Sharti		if (line[0] == '^') {
395132493Sharti			if (line[1] == '^')
396132493Sharti				continue;
397118824Sharti			break;
398132493Sharti		}
399132493Sharti		if (strncmp(line, "$MAIN", 5) == 0) {
400132493Sharti			help_get_0topics(&hfile);
401132493Sharti			continue;
402132493Sharti		}
403118824Sharti		printf("%s", line);
404118824Sharti	}
405118824Sharti
406118824Sharti	exit(0);
407118824Sharti
408118824Sharti  not_found:
409118824Sharti	printf("Topic not found.");
410118824Sharti
411118824Sharti  list_topics:
412132493Sharti	printf(" Use one of:\natmconfig help");
413118824Sharti	for (i = 0; i < optind; i++)
414118824Sharti		printf(" %s", argv[i]);
415132493Sharti
416118824Sharti	printf(" [");
417132493Sharti
418118824Sharti	/* list all the keys at this level */
419132493Sharti	if (last_match.pos == -1)
420132493Sharti		/* go back to start of help */
421132493Sharti		help_file_rewind(&hfile);
422132493Sharti	else
423132493Sharti		help_file_seek(&hfile, &last_match);
424118824Sharti
425132493Sharti	has_sub_topics = 0;
426132493Sharti	while ((line = help_next_line(&hfile)) != NULL) {
427132493Sharti		if (line[0] == '#' || line[0] != '^' || line[1] == '^')
428118824Sharti			continue;
429118824Sharti
430118824Sharti		if (sscanf(line + 1, "%d%99s", &level, key) != 2)
431118824Sharti			errx(1, "error in help file '%s'", line);
432118824Sharti
433118824Sharti		if (level < optind)
434118824Sharti			break;
435132493Sharti		if (level == optind) {
436132493Sharti			has_sub_topics = 1;
437118824Sharti			printf(" %s", key);
438132493Sharti		}
439118824Sharti	}
440132493Sharti	printf(" ].");
441132493Sharti	if (!has_sub_topics)
442132493Sharti		printf(" No sub-topics found.");
443132493Sharti	printf("\n");
444118824Sharti	exit(1);
445118824Sharti}
446118824Sharti
447270027Sngie#ifdef WITH_BSNMP
448133565Sharti/*
449133565Sharti * Parse a server specification
450133565Sharti *
451133565Sharti * syntax is [trans::][community@][server][:port]
452133565Sharti */
453133565Shartistatic void
454133565Shartiparse_server(char *name)
455133565Sharti{
456133565Sharti	char *p, *s = name;
457133565Sharti
458133565Sharti	/* look for a double colon */
459133565Sharti	for (p = s; *p != '\0'; p++) {
460133565Sharti		if (*p == '\\' && p[1] != '\0') {
461133565Sharti			p++;
462133565Sharti			continue;
463133565Sharti		}
464133565Sharti		if (*p == ':' && p[1] == ':')
465133565Sharti			break;
466133565Sharti	}
467133565Sharti	if (*p != '\0') {
468133565Sharti		if (p > s) {
469133565Sharti			if (p - s == 3 && strncmp(s, "udp", 3) == 0)
470133565Sharti				snmp_client.trans = SNMP_TRANS_UDP;
471133565Sharti			else if (p - s == 6 && strncmp(s, "stream", 6) == 0)
472133565Sharti				snmp_client.trans = SNMP_TRANS_LOC_STREAM;
473133565Sharti			else if (p - s == 5 && strncmp(s, "dgram", 5) == 0)
474133565Sharti				snmp_client.trans = SNMP_TRANS_LOC_DGRAM;
475133565Sharti			else
476133565Sharti				errx(1, "unknown SNMP transport '%.*s'",
477133565Sharti				    (int)(p - s), s);
478133565Sharti		}
479133565Sharti		s = p + 2;
480133565Sharti	}
481133565Sharti
482133565Sharti	/* look for a @ */
483133565Sharti	for (p = s; *p != '\0'; p++) {
484133565Sharti		if (*p == '\\' && p[1] != '\0') {
485133565Sharti			p++;
486133565Sharti			continue;
487133565Sharti		}
488133565Sharti		if (*p == '@')
489133565Sharti			break;
490133565Sharti	}
491133565Sharti
492133565Sharti	if (*p != '\0') {
493133565Sharti		if (p - s > SNMP_COMMUNITY_MAXLEN)
494133565Sharti			err(1, "community string too long");
495133565Sharti		strncpy(snmp_client.read_community, s, p - s);
496133565Sharti		snmp_client.read_community[p - s] = '\0';
497133565Sharti		strncpy(snmp_client.write_community, s, p - s);
498133565Sharti		snmp_client.write_community[p - s] = '\0';
499133565Sharti		s = p + 1;
500133565Sharti	}
501133565Sharti
502133565Sharti	/* look for a colon */
503133565Sharti	for (p = s; *p != '\0'; p++) {
504133565Sharti		if (*p == '\\' && p[1] != '\0') {
505133565Sharti			p++;
506133565Sharti			continue;
507133565Sharti		}
508133565Sharti		if (*p == ':')
509133565Sharti			break;
510133565Sharti	}
511133565Sharti
512133565Sharti	if (*p == ':') {
513133565Sharti		if (p > s) {
514133565Sharti			*p = '\0';
515133565Sharti			snmp_client_set_host(&snmp_client, s);
516133565Sharti			*p = ':';
517133565Sharti		}
518133565Sharti		snmp_client_set_port(&snmp_client, p + 1);
519133565Sharti	} else if (p > s)
520133565Sharti		snmp_client_set_host(&snmp_client, s);
521133565Sharti}
522133565Sharti#endif
523133565Sharti
524118824Shartiint
525118824Shartimain(int argc, char *argv[])
526118824Sharti{
527118824Sharti	int opt, i;
528118824Sharti	const struct cmdtab *match, *cc, *tab;
529118824Sharti
530270027Sngie#ifdef WITH_BSNMP
531133565Sharti	snmp_client_init(&snmp_client);
532133565Sharti	snmp_client.trans = SNMP_TRANS_LOC_STREAM;
533133565Sharti	snmp_client_set_host(&snmp_client, PATH_ILMI_SOCK);
534133565Sharti#endif
535133565Sharti
536270027Sngie#ifdef WITH_BSNMP
537270027Sngie#define	OPTSTR	"htvs:"
538270027Sngie#else
539133565Sharti#define OPTSTR	"htv"
540133565Sharti#endif
541133565Sharti
542133565Sharti	while ((opt = getopt(argc, argv, OPTSTR)) != -1)
543118824Sharti		switch (opt) {
544118824Sharti
545118824Sharti		  case 'h':
546118824Sharti			help_func(0, argv);
547118824Sharti
548270027Sngie#ifdef WITH_BSNMP
549133565Sharti		  case 's':
550133565Sharti			parse_server(optarg);
551133565Sharti			break;
552133565Sharti#endif
553133565Sharti
554118824Sharti		  case 'v':
555118824Sharti			verbose++;
556118824Sharti			break;
557118824Sharti
558118824Sharti		  case 't':
559118824Sharti			notitle = 1;
560118824Sharti			break;
561118824Sharti		}
562118824Sharti
563118824Sharti	if (argv[optind] == NULL)
564118824Sharti		help_func(0, argv);
565118824Sharti
566118824Sharti	argc -= optind;
567118824Sharti	argv += optind;
568118824Sharti
569133565Sharti	if ((main_tab = malloc(sizeof(static_main_tab))) == NULL)
570133565Sharti		err(1, NULL);
571133565Sharti	memcpy(main_tab, static_main_tab, sizeof(static_main_tab));
572133565Sharti
573270027Sngie#ifdef WITH_BSNMP
574133565Sharti	/* XXX while this is compiled in */
575133565Sharti	device_register();
576133565Sharti#endif
577133565Sharti
578118824Sharti	cc = main_tab;
579118824Sharti	i = 0;
580118824Sharti	for (;;) {
581118824Sharti		/*
582118824Sharti		 * Scan the table for a match
583118824Sharti		 */
584118824Sharti		tab = cc;
585118824Sharti		match = NULL;
586118824Sharti		while (cc->string != NULL) {
587118824Sharti			if (substr(argv[i], cc->string)) {
588118824Sharti				if (match != NULL) {
589118824Sharti					printf("Ambiguous option '%s'",
590118824Sharti					    argv[i]);
591118824Sharti					cc = tab;
592118824Sharti					goto subopts;
593118824Sharti				}
594118824Sharti				match = cc;
595118824Sharti			}
596118824Sharti			cc++;
597118824Sharti		}
598118824Sharti		if ((cc = match) == NULL) {
599118824Sharti			printf("Unknown option '%s'", argv[i]);
600118824Sharti			cc = tab;
601118824Sharti			goto subopts;
602118824Sharti		}
603118824Sharti
604118824Sharti		/*
605118824Sharti		 * Have a match. If there is no subtable, there must
606118824Sharti		 * be either a handler or the command is only a help entry.
607118824Sharti		 */
608118824Sharti		if (cc->sub == NULL) {
609118824Sharti			if (cc->func != NULL)
610118824Sharti				break;
611118824Sharti			printf("Unknown option '%s'", argv[i]);
612118824Sharti			cc = tab;
613118824Sharti			goto subopts;
614118824Sharti		}
615118824Sharti
616118824Sharti		/*
617118824Sharti		 * Look at the next argument. If it doesn't exist or it
618118824Sharti		 * looks like a switch, terminate the scan here.
619118824Sharti		 */
620118824Sharti		if (argv[i + 1] == NULL || argv[i + 1][0] == '-') {
621118824Sharti			if (cc->func != NULL)
622118824Sharti				break;
623118824Sharti			printf("Need sub-option for '%s'", argv[i]);
624118824Sharti			cc = cc->sub;
625118824Sharti			goto subopts;
626118824Sharti		}
627118824Sharti
628118824Sharti		cc = cc->sub;
629118824Sharti		i++;
630118824Sharti	}
631118824Sharti
632118824Sharti	argc -= i + 1;
633118824Sharti	argv += i + 1;
634118824Sharti
635118824Sharti	(*cc->func)(argc, argv);
636118824Sharti
637118824Sharti	return (0);
638118824Sharti
639118824Sharti  subopts:
640118824Sharti	printf(". Select one of:\n");
641118824Sharti	while (cc->string != NULL) {
642118824Sharti		if (cc->func != NULL || cc->sub != NULL)
643118824Sharti			printf("%s ", cc->string);
644118824Sharti		cc++;
645118824Sharti	}
646118824Sharti	printf("\n");
647118824Sharti
648118824Sharti	return (1);
649118824Sharti}
650118824Sharti
651118824Shartivoid
652118824Shartiverb(const char *fmt, ...)
653118824Sharti{
654118824Sharti	va_list ap;
655118824Sharti
656118824Sharti	if (verbose) {
657118824Sharti		va_start(ap, fmt);
658118824Sharti		vfprintf(stderr, fmt, ap);
659118824Sharti		fprintf(stderr, "\n");
660118824Sharti		va_end(ap);
661118824Sharti	}
662118824Sharti}
663118824Sharti
664118824Shartivoid
665118824Shartiheading(const char *fmt, ...)
666118824Sharti{
667118824Sharti	va_list ap;
668118824Sharti
669118824Sharti	if (need_heading) {
670118824Sharti		need_heading = 0;
671118824Sharti		if (!notitle) {
672118824Sharti			va_start(ap, fmt);
673118824Sharti			fprintf(stdout, fmt, ap);
674118824Sharti			va_end(ap);
675118824Sharti		}
676118824Sharti	}
677118824Sharti}
678118824Sharti
679118824Shartivoid
680118824Shartiheading_init(void)
681118824Sharti{
682118824Sharti	need_heading = 1;
683118824Sharti}
684118824Sharti
685118824Sharti/*
686118824Sharti * stringify an enumerated value
687118824Sharti */
688118824Sharticonst char *
689118824Shartipenum(int32_t value, const struct penum *strtab, char *buf)
690118824Sharti{
691118824Sharti	while (strtab->str != NULL) {
692118824Sharti		if (strtab->value == value) {
693118824Sharti			strcpy(buf, strtab->str);
694118824Sharti			return (buf);
695118824Sharti		}
696118824Sharti		strtab++;
697118824Sharti	}
698118824Sharti	warnx("illegal value for enumerated variable '%d'", value);
699118824Sharti	strcpy(buf, "?");
700118824Sharti	return (buf);
701118824Sharti}
702118824Sharti
703118824Sharti/*
704133565Sharti * And the other way 'round
705133565Sharti */
706133565Shartiint
707133565Shartipparse(int32_t *val, const struct penum *tab, const char *str)
708133565Sharti{
709133565Sharti
710133565Sharti	while (tab->str != NULL) {
711133565Sharti		if (strcmp(tab->str, str) == 0) {
712133565Sharti			*val = tab->value;
713133565Sharti			return (0);
714133565Sharti		}
715133565Sharti		tab++;
716133565Sharti	}
717133565Sharti	return (-1);
718133565Sharti}
719133565Sharti
720133565Sharti/*
721118824Sharti * Parse command line options
722118824Sharti */
723118824Shartiint
724118824Shartiparse_options(int *pargc, char ***pargv, const struct option *opts)
725118824Sharti{
726118824Sharti	const struct option *o, *m;
727118824Sharti	char *arg;
728118824Sharti	u_long ularg, ularg1;
729118824Sharti	long larg;
730118824Sharti	char *end;
731118824Sharti
732118824Sharti	if (*pargc == 0)
733118824Sharti		return (-1);
734118824Sharti	arg = (*pargv)[0];
735118824Sharti	if (arg[0] != '-' || arg[1] == '\0')
736118824Sharti		return (-1);
737118824Sharti	if (arg[1] == '-' && arg[2] == '\0') {
738118824Sharti		(*pargv)++;
739118824Sharti		(*pargc)--;
740118824Sharti		return (-1);
741118824Sharti	}
742118824Sharti
743118824Sharti	m = NULL;
744118824Sharti	for (o = opts; o->optstr != NULL; o++) {
745118824Sharti		if (strlen(arg + 1) <= strlen(o->optstr) &&
746118824Sharti		    strncmp(arg + 1, o->optstr, strlen(arg + 1)) == 0) {
747118824Sharti			if (m != NULL)
748118824Sharti				errx(1, "ambiguous option '%s'", arg);
749118824Sharti			m = o;
750118824Sharti		}
751118824Sharti	}
752118824Sharti	if (m == NULL)
753118824Sharti		errx(1, "unknown option '%s'", arg);
754118824Sharti
755118824Sharti	(*pargv)++;
756118824Sharti	(*pargc)--;
757118824Sharti
758118824Sharti	if (m->opttype == OPT_NONE)
759118824Sharti		return (m - opts);
760118824Sharti
761118824Sharti	if (m->opttype == OPT_SIMPLE) {
762118824Sharti		*(int *)m->optarg = 1;
763118824Sharti		return (m - opts);
764118824Sharti	}
765118824Sharti
766118824Sharti	if (*pargc == 0)
767118824Sharti		errx(1, "option requires argument '%s'", arg);
768118824Sharti	optarg = *(*pargv)++;
769118824Sharti	(*pargc)--;
770118824Sharti
771118824Sharti	switch (m->opttype) {
772118824Sharti
773118824Sharti	  case OPT_UINT:
774118824Sharti		ularg = strtoul(optarg, &end, 0);
775118824Sharti		if (*end != '\0')
776118824Sharti			errx(1, "bad unsigned integer argument for '%s'", arg);
777118824Sharti		if (ularg > UINT_MAX)
778118824Sharti			errx(1, "argument to large for option '%s'", arg);
779118824Sharti		*(u_int *)m->optarg = (u_int)ularg;
780118824Sharti		break;
781118824Sharti
782118824Sharti	  case OPT_INT:
783118824Sharti		larg = strtol(optarg, &end, 0);
784118824Sharti		if (*end != '\0')
785118824Sharti			errx(1, "bad integer argument for '%s'", arg);
786118824Sharti		if (larg > INT_MAX || larg < INT_MIN)
787118824Sharti			errx(1, "argument out of range for option '%s'", arg);
788118824Sharti		*(int *)m->optarg = (int)larg;
789118824Sharti		break;
790118824Sharti
791118824Sharti	  case OPT_UINT32:
792118824Sharti		ularg = strtoul(optarg, &end, 0);
793118824Sharti		if (*end != '\0')
794118824Sharti			errx(1, "bad unsigned integer argument for '%s'", arg);
795118824Sharti		if (ularg > UINT32_MAX)
796118824Sharti			errx(1, "argument to large for option '%s'", arg);
797118824Sharti		*(uint32_t *)m->optarg = (uint32_t)ularg;
798118824Sharti		break;
799118824Sharti
800118824Sharti	  case OPT_INT32:
801118824Sharti		larg = strtol(optarg, &end, 0);
802118824Sharti		if (*end != '\0')
803118824Sharti			errx(1, "bad integer argument for '%s'", arg);
804118824Sharti		if (larg > INT32_MAX || larg < INT32_MIN)
805118824Sharti			errx(1, "argument out of range for option '%s'", arg);
806118824Sharti		*(int32_t *)m->optarg = (int32_t)larg;
807118824Sharti		break;
808118824Sharti
809118824Sharti	  case OPT_UINT64:
810118824Sharti		*(uint64_t *)m->optarg = strtoull(optarg, &end, 0);
811118824Sharti		if (*end != '\0')
812118824Sharti			errx(1, "bad unsigned integer argument for '%s'", arg);
813118824Sharti		break;
814118824Sharti
815118824Sharti	  case OPT_INT64:
816118824Sharti		*(int64_t *)m->optarg = strtoll(optarg, &end, 0);
817118824Sharti		if (*end != '\0')
818118824Sharti			errx(1, "bad integer argument for '%s'", arg);
819118824Sharti		break;
820118824Sharti
821118824Sharti	  case OPT_FLAG:
822118824Sharti		if (strcasecmp(optarg, "enable") == 0 ||
823118824Sharti		    strcasecmp(optarg, "yes") == 0 ||
824118824Sharti		    strcasecmp(optarg, "true") == 0 ||
825118824Sharti		    strcasecmp(optarg, "on") == 0 ||
826118824Sharti		    strcmp(optarg, "1") == 0)
827118824Sharti			*(int *)m->optarg = 1;
828118824Sharti		else if (strcasecmp(optarg, "disable") == 0 ||
829118824Sharti		    strcasecmp(optarg, "no") == 0 ||
830118824Sharti		    strcasecmp(optarg, "false") == 0 ||
831118824Sharti		    strcasecmp(optarg, "off") == 0 ||
832118824Sharti		    strcmp(optarg, "0") == 0)
833118824Sharti			*(int *)m->optarg = 0;
834118824Sharti		else
835118824Sharti			errx(1, "bad boolean argument to '%s'", arg);
836118824Sharti		break;
837118824Sharti
838118824Sharti	  case OPT_VCI:
839118824Sharti		ularg = strtoul(optarg, &end, 0);
840118824Sharti		if (*end == '.') {
841118824Sharti			ularg1 = strtoul(end + 1, &end, 0);
842118824Sharti		} else {
843118824Sharti			ularg1 = ularg;
844118824Sharti			ularg = 0;
845118824Sharti		}
846118824Sharti		if (*end != '\0')
847118824Sharti			errx(1, "bad VCI value for option '%s'", arg);
848118824Sharti		if (ularg > 0xff)
849118824Sharti			errx(1, "VPI value too large for option '%s'", arg);
850118824Sharti		if (ularg1 > 0xffff)
851118824Sharti			errx(1, "VCI value too large for option '%s'", arg);
852118824Sharti		((u_int *)m->optarg)[0] = ularg;
853118824Sharti		((u_int *)m->optarg)[1] = ularg1;
854118824Sharti		break;
855118824Sharti
856118824Sharti	  case OPT_STRING:
857118824Sharti		if (m->optarg != NULL)
858118824Sharti			*(const char **)m->optarg = optarg;
859118824Sharti		break;
860118824Sharti
861118824Sharti	  default:
862118824Sharti		errx(1, "(internal) bad option type %u for '%s'",
863118824Sharti		    m->opttype, arg);
864118824Sharti	}
865118824Sharti	return (m - opts);
866118824Sharti}
867133565Sharti
868133565Sharti/*
869133565Sharti * for compiled-in modules
870133565Sharti */
871133565Shartivoid
872133565Shartiregister_module(const struct amodule *mod)
873133565Sharti{
874133565Sharti	main_tab_size++;
875133565Sharti	if ((main_tab = realloc(main_tab, main_tab_size * sizeof(main_tab[0])))
876133565Sharti	    == NULL)
877133565Sharti		err(1, NULL);
878133565Sharti	main_tab[main_tab_size - 2] = *mod->cmd;
879133565Sharti	memset(&main_tab[main_tab_size - 1], 0, sizeof(main_tab[0]));
880133565Sharti}
881