2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * Author: Hartmut Brandt <harti@freebsd.org>
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/types.h>
33 #include <sys/sysctl.h>
42 #include <bsnmp/asn1.h>
43 #include <bsnmp/snmp.h>
44 #include <bsnmp/snmpclient.h>
47 #include "atmconfig.h"
56 /* need to put heading before next output */
57 static int need_heading;
62 static void help_func(int argc, char *argv[]) __dead2;
64 static const struct cmdtab static_main_tab[] = {
65 { "help", NULL, help_func },
66 { "options", NULL, NULL },
67 { "commands", NULL, NULL },
68 { "diag", diag_tab, NULL },
69 { "natm", natm_tab, NULL },
73 static struct cmdtab *main_tab = NULL;
74 static size_t main_tab_size = sizeof(static_main_tab) /
75 sizeof(static_main_tab[0]);
78 substr(const char *s1, const char *s2)
80 return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0);
84 * Current help file state
87 int file_state; /* 0:looking for main file, 1:found, 2:other */
88 const char *p_start; /* current path pointer */
89 const char *p_end; /* end of current path in path */
90 char *dirname; /* directory name */
91 DIR *dir; /* open directory */
92 char *fname; /* current filename */
93 FILE *fp; /* open file */
94 char line[LINE_MAX]; /* current line */
95 u_int fcnt; /* count of files found */
99 off_t pos; /* file position */
100 u_int fcnt; /* number of file */
101 char *fname; /* name of file */
102 const char *p_start; /* current path pointer */
103 const char *p_end; /* end of current path in path */
107 help_next_file(struct help_file *hp)
112 if (hp->file_state == 3)
115 if (hp->file_state == 0)
118 fpat = FILE_HELP_OTHERS;
120 if (hp->file_state == 0 || hp->file_state == 1) {
121 /* start from beginning */
122 hp->p_start = PATH_HELP;
127 if (hp->dir != NULL) {
128 /* directory open (must be state 2) */
129 while ((ent = readdir(hp->dir)) != NULL) {
130 if (fnmatch(fpat, ent->d_name, FNM_NOESCAPE) != 0)
132 if (asprintf(&hp->fname, "%s/%s", hp->dirname,
135 if ((hp->fp = fopen(hp->fname, "r")) != NULL) {
141 /* end of directory */
148 /* nothing open - advanc to new path element */
150 for (hp->p_end = hp->p_start; *hp->p_end != '\0' &&
151 *hp->p_end != ':'; hp->p_end++)
154 if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start),
158 if (hp->file_state == 1) {
159 /* just try to open */
160 if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1)
162 if ((hp->fp = fopen(hp->fname, "r")) != NULL) {
172 if ((hp->dir = opendir(hp->dirname)) != NULL)
178 hp->p_start = hp->p_end;
179 if (*hp->p_start == '\0') {
181 if (hp->file_state == 1)
182 errx(1, "help file not found");
191 * Save current file position
194 help_file_tell(struct help_file *hp, struct help_pos *pos)
196 if (pos->fname != NULL)
198 if ((pos->fname = strdup(hp->fname)) == NULL)
200 pos->fcnt = hp->fcnt;
201 pos->p_start = hp->p_start;
202 pos->p_end = hp->p_end;
203 if ((pos->pos = ftello(hp->fp)) == -1)
204 err(1, "%s", pos->fname);
208 * Go to that position
210 * We can go either to the original help file or back in the current file.
213 help_file_seek(struct help_file *hp, struct help_pos *pos)
215 hp->p_start = pos->p_start;
216 hp->p_end = pos->p_end;
217 hp->fcnt = pos->fcnt;
219 if (hp->dir != NULL) {
225 if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) {
230 if (hp->fp == NULL) {
231 if ((hp->fname = strdup(pos->fname)) == NULL)
233 if ((hp->fp = fopen(hp->fname, "r")) == NULL)
234 err(1, "reopen %s", hp->fname);
236 if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1)
237 err(1, "seek %s", hp->fname);
240 /* go back to state 1 */
248 * Rewind to position 0
251 help_file_rewind(struct help_file *hp)
254 if (hp->file_state == 1) {
255 if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1)
256 err(1, "rewind help file");
260 if (hp->dir != NULL) {
266 if (hp->fp != NULL) {
271 memset(hp, 0, sizeof(*hp));
275 * Get next line from a help file
278 help_next_line(struct help_file *hp)
281 if (hp->fp != NULL) {
282 if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL)
285 err(1, "%s", hp->fname);
291 if (help_next_file(hp) == -1)
298 * This function prints the available 0-level help topics from all
299 * other help files by scanning the files. It assumes, that this is called
300 * only from the main help file.
303 help_get_0topics(struct help_file *hp)
305 struct help_pos save;
308 memset(&save, 0, sizeof(save));
309 help_file_tell(hp, &save);
311 help_file_rewind(hp);
312 while ((line = help_next_line(hp)) != NULL) {
313 if (line[0] == '^' && line[1] == '^')
314 printf("%s", line + 2);
316 help_file_seek(hp, &save);
320 * Function to print help. The help argument is in argv[0] here.
323 help_func(int argc, char *argv[])
325 struct help_file hfile;
326 struct help_pos match, last_match;
330 int i, has_sub_topics;
332 memset(&hfile, 0, sizeof(hfile));
333 memset(&match, 0, sizeof(match));
334 memset(&last_match, 0, sizeof(last_match));
337 /* only 'help' - show intro */
338 if ((argv[0] = strdup("intro")) == NULL)
348 if ((line = help_next_line(&hfile)) == NULL) {
353 if (line[0] != '^' || line[1] == '^')
356 if (sscanf(line + 1, "%d%99s", &level, key) != 2)
357 errx(1, "error in help file '%s'", line);
359 if (level < optind) {
361 /* next higher level entry - stop this level */
362 if (match.pos == -1) {
366 /* go back to the match */
367 help_file_seek(&hfile, &match);
369 memset(&match, 0, sizeof(match));
373 if (++optind >= argc)
376 if (level == optind) {
377 if (substr(argv[optind], key)) {
378 if (match.pos != -1) {
379 printf("Ambiguous topic.");
382 help_file_tell(&hfile, &match);
387 /* before breaking above we have seeked back to the matching point */
389 if ((line = help_next_line(&hfile)) == NULL)
394 if (line[0] == '^') {
399 if (strncmp(line, "$MAIN", 5) == 0) {
400 help_get_0topics(&hfile);
409 printf("Topic not found.");
412 printf(" Use one of:\natmconfig help");
413 for (i = 0; i < optind; i++)
414 printf(" %s", argv[i]);
418 /* list all the keys at this level */
419 if (last_match.pos == -1)
420 /* go back to start of help */
421 help_file_rewind(&hfile);
423 help_file_seek(&hfile, &last_match);
426 while ((line = help_next_line(&hfile)) != NULL) {
427 if (line[0] == '#' || line[0] != '^' || line[1] == '^')
430 if (sscanf(line + 1, "%d%99s", &level, key) != 2)
431 errx(1, "error in help file '%s'", line);
435 if (level == optind) {
442 printf(" No sub-topics found.");
449 * Parse a server specification
451 * syntax is [trans::][community@][server][:port]
454 parse_server(char *name)
458 /* look for a double colon */
459 for (p = s; *p != '\0'; p++) {
460 if (*p == '\\' && p[1] != '\0') {
464 if (*p == ':' && p[1] == ':')
469 if (p - s == 3 && strncmp(s, "udp", 3) == 0)
470 snmp_client.trans = SNMP_TRANS_UDP;
471 else if (p - s == 6 && strncmp(s, "stream", 6) == 0)
472 snmp_client.trans = SNMP_TRANS_LOC_STREAM;
473 else if (p - s == 5 && strncmp(s, "dgram", 5) == 0)
474 snmp_client.trans = SNMP_TRANS_LOC_DGRAM;
476 errx(1, "unknown SNMP transport '%.*s'",
483 for (p = s; *p != '\0'; p++) {
484 if (*p == '\\' && p[1] != '\0') {
493 if (p - s > SNMP_COMMUNITY_MAXLEN)
494 err(1, "community string too long");
495 strncpy(snmp_client.read_community, s, p - s);
496 snmp_client.read_community[p - s] = '\0';
497 strncpy(snmp_client.write_community, s, p - s);
498 snmp_client.write_community[p - s] = '\0';
502 /* look for a colon */
503 for (p = s; *p != '\0'; p++) {
504 if (*p == '\\' && p[1] != '\0') {
515 snmp_client_set_host(&snmp_client, s);
518 snmp_client_set_port(&snmp_client, p + 1);
520 snmp_client_set_host(&snmp_client, s);
525 main(int argc, char *argv[])
528 const struct cmdtab *match, *cc, *tab;
531 snmp_client_init(&snmp_client);
532 snmp_client.trans = SNMP_TRANS_LOC_STREAM;
533 snmp_client_set_host(&snmp_client, PATH_ILMI_SOCK);
539 #define OPTSTR "htvs:"
542 while ((opt = getopt(argc, argv, OPTSTR)) != -1)
550 parse_server(optarg);
563 if (argv[optind] == NULL)
569 if ((main_tab = malloc(sizeof(static_main_tab))) == NULL)
571 memcpy(main_tab, static_main_tab, sizeof(static_main_tab));
574 /* XXX while this is compiled in */
582 * Scan the table for a match
586 while (cc->string != NULL) {
587 if (substr(argv[i], cc->string)) {
589 printf("Ambiguous option '%s'",
598 if ((cc = match) == NULL) {
599 printf("Unknown option '%s'", argv[i]);
605 * Have a match. If there is no subtable, there must
606 * be either a handler or the command is only a help entry.
608 if (cc->sub == NULL) {
609 if (cc->func != NULL)
611 printf("Unknown option '%s'", argv[i]);
617 * Look at the next argument. If it doesn't exist or it
618 * looks like a switch, terminate the scan here.
620 if (argv[i + 1] == NULL || argv[i + 1][0] == '-') {
621 if (cc->func != NULL)
623 printf("Need sub-option for '%s'", argv[i]);
635 (*cc->func)(argc, argv);
640 printf(". Select one of:\n");
641 while (cc->string != NULL) {
642 if (cc->func != NULL || cc->sub != NULL)
643 printf("%s ", cc->string);
652 verb(const char *fmt, ...)
658 vfprintf(stderr, fmt, ap);
659 fprintf(stderr, "\n");
665 heading(const char *fmt, ...)
673 fprintf(stdout, fmt, ap);
686 * stringify an enumerated value
689 penum(int32_t value, const struct penum *strtab, char *buf)
691 while (strtab->str != NULL) {
692 if (strtab->value == value) {
693 strcpy(buf, strtab->str);
698 warnx("illegal value for enumerated variable '%d'", value);
704 * And the other way 'round
707 pparse(int32_t *val, const struct penum *tab, const char *str)
710 while (tab->str != NULL) {
711 if (strcmp(tab->str, str) == 0) {
721 * Parse command line options
724 parse_options(int *pargc, char ***pargv, const struct option *opts)
726 const struct option *o, *m;
728 u_long ularg, ularg1;
735 if (arg[0] != '-' || arg[1] == '\0')
737 if (arg[1] == '-' && arg[2] == '\0') {
744 for (o = opts; o->optstr != NULL; o++) {
745 if (strlen(arg + 1) <= strlen(o->optstr) &&
746 strncmp(arg + 1, o->optstr, strlen(arg + 1)) == 0) {
748 errx(1, "ambiguous option '%s'", arg);
753 errx(1, "unknown option '%s'", arg);
758 if (m->opttype == OPT_NONE)
761 if (m->opttype == OPT_SIMPLE) {
762 *(int *)m->optarg = 1;
767 errx(1, "option requires argument '%s'", arg);
768 optarg = *(*pargv)++;
771 switch (m->opttype) {
774 ularg = strtoul(optarg, &end, 0);
776 errx(1, "bad unsigned integer argument for '%s'", arg);
777 if (ularg > UINT_MAX)
778 errx(1, "argument to large for option '%s'", arg);
779 *(u_int *)m->optarg = (u_int)ularg;
783 larg = strtol(optarg, &end, 0);
785 errx(1, "bad integer argument for '%s'", arg);
786 if (larg > INT_MAX || larg < INT_MIN)
787 errx(1, "argument out of range for option '%s'", arg);
788 *(int *)m->optarg = (int)larg;
792 ularg = strtoul(optarg, &end, 0);
794 errx(1, "bad unsigned integer argument for '%s'", arg);
795 if (ularg > UINT32_MAX)
796 errx(1, "argument to large for option '%s'", arg);
797 *(uint32_t *)m->optarg = (uint32_t)ularg;
801 larg = strtol(optarg, &end, 0);
803 errx(1, "bad integer argument for '%s'", arg);
804 if (larg > INT32_MAX || larg < INT32_MIN)
805 errx(1, "argument out of range for option '%s'", arg);
806 *(int32_t *)m->optarg = (int32_t)larg;
810 *(uint64_t *)m->optarg = strtoull(optarg, &end, 0);
812 errx(1, "bad unsigned integer argument for '%s'", arg);
816 *(int64_t *)m->optarg = strtoll(optarg, &end, 0);
818 errx(1, "bad integer argument for '%s'", arg);
822 if (strcasecmp(optarg, "enable") == 0 ||
823 strcasecmp(optarg, "yes") == 0 ||
824 strcasecmp(optarg, "true") == 0 ||
825 strcasecmp(optarg, "on") == 0 ||
826 strcmp(optarg, "1") == 0)
827 *(int *)m->optarg = 1;
828 else if (strcasecmp(optarg, "disable") == 0 ||
829 strcasecmp(optarg, "no") == 0 ||
830 strcasecmp(optarg, "false") == 0 ||
831 strcasecmp(optarg, "off") == 0 ||
832 strcmp(optarg, "0") == 0)
833 *(int *)m->optarg = 0;
835 errx(1, "bad boolean argument to '%s'", arg);
839 ularg = strtoul(optarg, &end, 0);
841 ularg1 = strtoul(end + 1, &end, 0);
847 errx(1, "bad VCI value for option '%s'", arg);
849 errx(1, "VPI value too large for option '%s'", arg);
851 errx(1, "VCI value too large for option '%s'", arg);
852 ((u_int *)m->optarg)[0] = ularg;
853 ((u_int *)m->optarg)[1] = ularg1;
857 if (m->optarg != NULL)
858 *(const char **)m->optarg = optarg;
862 errx(1, "(internal) bad option type %u for '%s'",
869 * for compiled-in modules
872 register_module(const struct amodule *mod)
875 if ((main_tab = realloc(main_tab, main_tab_size * sizeof(main_tab[0])))
878 main_tab[main_tab_size - 2] = *mod->cmd;
879 memset(&main_tab[main_tab_size - 1], 0, sizeof(main_tab[0]));