]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/atm/atmconfig/main.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sbin / atm / atmconfig / main.c
1 /*
2  * Copyright (c) 2001-2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
28  */
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/types.h>
33 #include <sys/sysctl.h>
34 #include <netdb.h>
35 #include <stdarg.h>
36 #include <ctype.h>
37 #include <limits.h>
38 #include <stdint.h>
39 #include <fnmatch.h>
40 #include <dirent.h>
41 #ifndef RESCUE
42 #include <bsnmp/asn1.h>
43 #include <bsnmp/snmp.h>
44 #include <bsnmp/snmpclient.h>
45 #endif
46
47 #include "atmconfig.h"
48 #include "private.h"
49
50 /* verbosity level */
51 static int verbose;
52
53 /* notitle option */
54 static int notitle;
55
56 /* need to put heading before next output */
57 static int need_heading;
58
59 /*
60  * TOP LEVEL commands
61  */
62 static void help_func(int argc, char *argv[]) __dead2;
63
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 },
70         { NULL,         NULL,           NULL }
71 };
72
73 static struct cmdtab *main_tab = NULL;
74 static size_t main_tab_size = sizeof(static_main_tab) /
75         sizeof(static_main_tab[0]);
76
77 static int
78 substr(const char *s1, const char *s2)
79 {
80         return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0);
81 }
82
83 /*
84  * Current help file state
85  */
86 struct help_file {
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 */
96 };
97
98 struct help_pos {
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 */
104 };
105
106 static int
107 help_next_file(struct help_file *hp)
108 {
109         const char *fpat;
110         struct dirent *ent;
111
112         if (hp->file_state == 3)
113                 return (-1);
114
115         if (hp->file_state == 0)
116                 fpat = FILE_HELP;
117         else
118                 fpat = FILE_HELP_OTHERS;
119
120         if (hp->file_state == 0 || hp->file_state == 1) {
121                 /* start from beginning */
122                 hp->p_start = PATH_HELP;
123                 hp->file_state++;
124         }
125
126   try_file:
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)
131                                 continue;
132                         if (asprintf(&hp->fname, "%s/%s", hp->dirname,
133                             ent->d_name) == -1)
134                                 err(1, NULL);
135                         if ((hp->fp = fopen(hp->fname, "r")) != NULL) {
136                                 hp->fcnt++;
137                                 return (0);
138                         }
139                         free(hp->fname);
140                 }
141                 /* end of directory */
142                 closedir(hp->dir);
143                 hp->dir = NULL;
144                 free(hp->dirname);
145                 goto next_path;
146         }
147
148         /* nothing open - advanc to new path element */
149   try_path:
150         for (hp->p_end = hp->p_start; *hp->p_end != '\0' &&
151             *hp->p_end != ':'; hp->p_end++)
152                 ;
153
154         if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start),
155             hp->p_start) == -1)
156                 err(1, NULL);
157
158         if (hp->file_state == 1) {
159                 /* just try to open */
160                 if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1)
161                         err(1, NULL);
162                 if ((hp->fp = fopen(hp->fname, "r")) != NULL) {
163                         hp->fcnt++;
164                         return (0);
165                 }
166                 free(hp->fname);
167
168                 goto next_path;
169         }
170
171         /* open directory */
172         if ((hp->dir = opendir(hp->dirname)) != NULL)
173                 goto try_file;
174
175         free(hp->dirname);
176
177   next_path:
178         hp->p_start = hp->p_end;
179         if (*hp->p_start == '\0') {
180                 /* end of path */
181                 if (hp->file_state == 1)
182                         errx(1, "help file not found");
183                 return (-1);
184         }
185         hp->p_start++;
186         goto try_path;
187
188 }
189
190 /*
191  * Save current file position
192  */
193 static void
194 help_file_tell(struct help_file *hp, struct help_pos *pos)
195 {
196         if (pos->fname != NULL)
197                 free(pos->fname);
198         if ((pos->fname = strdup(hp->fname)) == NULL)
199                 err(1, 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);
205 }
206
207 /*
208  * Go to that position
209  *
210  * We can go either to the original help file or back in the current file.
211  */
212 static void
213 help_file_seek(struct help_file *hp, struct help_pos *pos)
214 {
215         hp->p_start = pos->p_start;
216         hp->p_end = pos->p_end;
217         hp->fcnt = pos->fcnt;
218
219         if (hp->dir != NULL) {
220                 free(hp->dirname);
221                 closedir(hp->dir);
222                 hp->dir = NULL;
223         }
224
225         if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) {
226                 free(hp->fname);
227                 fclose(hp->fp);
228                 hp->fp = NULL;
229         }
230         if (hp->fp == NULL) {
231                 if ((hp->fname = strdup(pos->fname)) == NULL)
232                         err(1, NULL);
233                 if ((hp->fp = fopen(hp->fname, "r")) == NULL)
234                         err(1, "reopen %s", hp->fname);
235         }
236         if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1)
237                 err(1, "seek %s", hp->fname);
238
239         if (pos->fcnt == 1)
240                 /* go back to state 1 */
241                 hp->file_state = 1;
242         else
243                 /* lock */
244                 hp->file_state = 3;
245 }
246
247 /*
248  * Rewind to position 0
249  */
250 static void
251 help_file_rewind(struct help_file *hp)
252 {
253
254         if (hp->file_state == 1) {
255                 if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1)
256                         err(1, "rewind help file");
257                 return;
258         }
259
260         if (hp->dir != NULL) {
261                 free(hp->dirname);
262                 closedir(hp->dir);
263                 hp->dir = NULL;
264         }
265
266         if (hp->fp != NULL) {
267                 free(hp->fname);
268                 fclose(hp->fp);
269                 hp->fp = NULL;
270         }
271         memset(hp, 0, sizeof(*hp));
272 }
273
274 /*
275  * Get next line from a help file
276  */
277 static const char *
278 help_next_line(struct help_file *hp)
279 {
280         for (;;) {
281                 if (hp->fp != NULL) {
282                         if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL)
283                                 return (hp->line);
284                         if (ferror(hp->fp))
285                                 err(1, "%s", hp->fname);
286                         free(hp->fname);
287
288                         fclose(hp->fp);
289                         hp->fp = NULL;
290                 }
291                 if (help_next_file(hp) == -1)
292                         return (NULL);
293         }
294         
295 }
296
297 /*
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.
301  */
302 static void
303 help_get_0topics(struct help_file *hp)
304 {
305         struct help_pos save;
306         const char *line;
307
308         memset(&save, 0, sizeof(save));
309         help_file_tell(hp, &save);
310
311         help_file_rewind(hp);
312         while ((line = help_next_line(hp)) != NULL) {
313                 if (line[0] == '^' && line[1] == '^')
314                         printf("%s", line + 2);
315         }
316         help_file_seek(hp, &save);
317 }
318
319 /*
320  * Function to print help. The help argument is in argv[0] here.
321  */
322 static void
323 help_func(int argc, char *argv[])
324 {
325         struct help_file hfile;
326         struct help_pos match, last_match;
327         const char *line;
328         char key[100];
329         int level;
330         int i, has_sub_topics;
331
332         memset(&hfile, 0, sizeof(hfile));
333         memset(&match, 0, sizeof(match));
334         memset(&last_match, 0, sizeof(last_match));
335
336         if (argc == 0) {
337                 /* only 'help' - show intro */
338                 if ((argv[0] = strdup("intro")) == NULL)
339                         err(1, NULL);
340                 argc = 1;
341         }
342
343         optind = 0;
344         match.pos = -1;
345         last_match.pos = -1;
346         for (;;) {
347                 /* read next line */
348                 if ((line = help_next_line(&hfile)) == NULL) {
349                         /* EOF */
350                         level = 999;
351                         goto stop;
352                 }
353                 if (line[0] != '^' || line[1] == '^')
354                         continue;
355
356                 if (sscanf(line + 1, "%d%99s", &level, key) != 2)
357                         errx(1, "error in help file '%s'", line);
358
359                 if (level < optind) {
360   stop:
361                         /* next higher level entry - stop this level */
362                         if (match.pos == -1) {
363                                 /* not found */
364                                 goto not_found;
365                         }
366                         /* go back to the match */
367                         help_file_seek(&hfile, &match);
368                         last_match = match;
369                         memset(&match, 0, sizeof(match));
370                         match.pos = -1;
371
372                         /* go to next key */
373                         if (++optind >= argc)
374                                 break;
375                 }
376                 if (level == optind) {
377                         if (substr(argv[optind], key)) {
378                                 if (match.pos != -1) {
379                                         printf("Ambiguous topic.");
380                                         goto list_topics;
381                                 }
382                                 help_file_tell(&hfile, &match);
383                         }
384                 }
385         }
386
387         /* before breaking above we have seeked back to the matching point */
388         for (;;) {
389                 if ((line = help_next_line(&hfile)) == NULL)
390                         break;
391
392                 if (line[0] == '#')
393                         continue;
394                 if (line[0] == '^') {
395                         if (line[1] == '^')
396                                 continue;
397                         break;
398                 }
399                 if (strncmp(line, "$MAIN", 5) == 0) {
400                         help_get_0topics(&hfile);
401                         continue;
402                 }
403                 printf("%s", line);
404         }
405
406         exit(0);
407
408   not_found:
409         printf("Topic not found.");
410
411   list_topics:
412         printf(" Use one of:\natmconfig help");
413         for (i = 0; i < optind; i++)
414                 printf(" %s", argv[i]);
415
416         printf(" [");
417
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);
422         else
423                 help_file_seek(&hfile, &last_match);
424
425         has_sub_topics = 0;
426         while ((line = help_next_line(&hfile)) != NULL) {
427                 if (line[0] == '#' || line[0] != '^' || line[1] == '^')
428                         continue;
429
430                 if (sscanf(line + 1, "%d%99s", &level, key) != 2)
431                         errx(1, "error in help file '%s'", line);
432
433                 if (level < optind)
434                         break;
435                 if (level == optind) {
436                         has_sub_topics = 1;
437                         printf(" %s", key);
438                 }
439         }
440         printf(" ].");
441         if (!has_sub_topics)
442                 printf(" No sub-topics found.");
443         printf("\n");
444         exit(1);
445 }
446
447 #ifndef RESCUE
448 /*
449  * Parse a server specification
450  *
451  * syntax is [trans::][community@][server][:port]
452  */
453 static void
454 parse_server(char *name)
455 {
456         char *p, *s = name;
457
458         /* look for a double colon */
459         for (p = s; *p != '\0'; p++) {
460                 if (*p == '\\' && p[1] != '\0') {
461                         p++;
462                         continue;
463                 }
464                 if (*p == ':' && p[1] == ':')
465                         break;
466         }
467         if (*p != '\0') {
468                 if (p > s) {
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;
475                         else
476                                 errx(1, "unknown SNMP transport '%.*s'",
477                                     (int)(p - s), s);
478                 }
479                 s = p + 2;
480         }
481
482         /* look for a @ */
483         for (p = s; *p != '\0'; p++) {
484                 if (*p == '\\' && p[1] != '\0') {
485                         p++;
486                         continue;
487                 }
488                 if (*p == '@')
489                         break;
490         }
491
492         if (*p != '\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';
499                 s = p + 1;
500         }
501
502         /* look for a colon */
503         for (p = s; *p != '\0'; p++) {
504                 if (*p == '\\' && p[1] != '\0') {
505                         p++;
506                         continue;
507                 }
508                 if (*p == ':')
509                         break;
510         }
511
512         if (*p == ':') {
513                 if (p > s) {
514                         *p = '\0';
515                         snmp_client_set_host(&snmp_client, s);
516                         *p = ':';
517                 }
518                 snmp_client_set_port(&snmp_client, p + 1);
519         } else if (p > s)
520                 snmp_client_set_host(&snmp_client, s);
521 }
522 #endif
523
524 int
525 main(int argc, char *argv[])
526 {
527         int opt, i;
528         const struct cmdtab *match, *cc, *tab;
529
530 #ifndef RESCUE
531         snmp_client_init(&snmp_client);
532         snmp_client.trans = SNMP_TRANS_LOC_STREAM;
533         snmp_client_set_host(&snmp_client, PATH_ILMI_SOCK);
534 #endif
535
536 #ifdef RESCUE
537 #define OPTSTR  "htv"
538 #else
539 #define OPTSTR  "htvs:"
540 #endif
541
542         while ((opt = getopt(argc, argv, OPTSTR)) != -1)
543                 switch (opt) {
544
545                   case 'h':
546                         help_func(0, argv);
547
548 #ifndef RESCUE
549                   case 's':
550                         parse_server(optarg);
551                         break;
552 #endif
553
554                   case 'v':
555                         verbose++;
556                         break;
557
558                   case 't':
559                         notitle = 1;
560                         break;
561                 }
562
563         if (argv[optind] == NULL)
564                 help_func(0, argv);
565
566         argc -= optind;
567         argv += optind;
568
569         if ((main_tab = malloc(sizeof(static_main_tab))) == NULL)
570                 err(1, NULL);
571         memcpy(main_tab, static_main_tab, sizeof(static_main_tab));
572
573 #ifndef RESCUE
574         /* XXX while this is compiled in */
575         device_register();
576 #endif
577
578         cc = main_tab;
579         i = 0;
580         for (;;) {
581                 /*
582                  * Scan the table for a match
583                  */
584                 tab = cc;
585                 match = NULL;
586                 while (cc->string != NULL) {
587                         if (substr(argv[i], cc->string)) {
588                                 if (match != NULL) {
589                                         printf("Ambiguous option '%s'",
590                                             argv[i]);
591                                         cc = tab;
592                                         goto subopts;
593                                 }
594                                 match = cc;
595                         }
596                         cc++;
597                 }
598                 if ((cc = match) == NULL) {
599                         printf("Unknown option '%s'", argv[i]);
600                         cc = tab;
601                         goto subopts;
602                 }
603
604                 /*
605                  * Have a match. If there is no subtable, there must
606                  * be either a handler or the command is only a help entry.
607                  */
608                 if (cc->sub == NULL) {
609                         if (cc->func != NULL)
610                                 break;
611                         printf("Unknown option '%s'", argv[i]);
612                         cc = tab;
613                         goto subopts;
614                 }
615
616                 /*
617                  * Look at the next argument. If it doesn't exist or it
618                  * looks like a switch, terminate the scan here.
619                  */
620                 if (argv[i + 1] == NULL || argv[i + 1][0] == '-') {
621                         if (cc->func != NULL)
622                                 break;
623                         printf("Need sub-option for '%s'", argv[i]);
624                         cc = cc->sub;
625                         goto subopts;
626                 }
627
628                 cc = cc->sub;
629                 i++;
630         }
631
632         argc -= i + 1;
633         argv += i + 1;
634
635         (*cc->func)(argc, argv);
636
637         return (0);
638
639   subopts:
640         printf(". Select one of:\n");
641         while (cc->string != NULL) {
642                 if (cc->func != NULL || cc->sub != NULL)
643                         printf("%s ", cc->string);
644                 cc++;
645         }
646         printf("\n");
647
648         return (1);
649 }
650
651 void
652 verb(const char *fmt, ...)
653 {
654         va_list ap;
655
656         if (verbose) {
657                 va_start(ap, fmt);
658                 vfprintf(stderr, fmt, ap);
659                 fprintf(stderr, "\n");
660                 va_end(ap);
661         }
662 }
663
664 void
665 heading(const char *fmt, ...)
666 {
667         va_list ap;
668
669         if (need_heading) {
670                 need_heading = 0;
671                 if (!notitle) {
672                         va_start(ap, fmt);
673                         fprintf(stdout, fmt, ap);
674                         va_end(ap);
675                 }
676         }
677 }
678
679 void
680 heading_init(void)
681 {
682         need_heading = 1;
683 }
684
685 /*
686  * stringify an enumerated value
687  */
688 const char *
689 penum(int32_t value, const struct penum *strtab, char *buf)
690 {
691         while (strtab->str != NULL) {
692                 if (strtab->value == value) {
693                         strcpy(buf, strtab->str);
694                         return (buf);
695                 }
696                 strtab++;
697         }
698         warnx("illegal value for enumerated variable '%d'", value);
699         strcpy(buf, "?");
700         return (buf);
701 }
702
703 /*
704  * And the other way 'round
705  */
706 int
707 pparse(int32_t *val, const struct penum *tab, const char *str)
708 {
709
710         while (tab->str != NULL) {
711                 if (strcmp(tab->str, str) == 0) {
712                         *val = tab->value;
713                         return (0);
714                 }
715                 tab++;
716         }
717         return (-1);
718 }
719
720 /*
721  * Parse command line options
722  */
723 int
724 parse_options(int *pargc, char ***pargv, const struct option *opts)
725 {
726         const struct option *o, *m;
727         char *arg;
728         u_long ularg, ularg1;
729         long larg;
730         char *end;
731
732         if (*pargc == 0)
733                 return (-1);
734         arg = (*pargv)[0];
735         if (arg[0] != '-' || arg[1] == '\0')
736                 return (-1);
737         if (arg[1] == '-' && arg[2] == '\0') {
738                 (*pargv)++;
739                 (*pargc)--;
740                 return (-1);
741         }
742
743         m = NULL;
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) {
747                         if (m != NULL)
748                                 errx(1, "ambiguous option '%s'", arg);
749                         m = o;
750                 }
751         }
752         if (m == NULL)
753                 errx(1, "unknown option '%s'", arg);
754         
755         (*pargv)++;
756         (*pargc)--;
757
758         if (m->opttype == OPT_NONE)
759                 return (m - opts);
760
761         if (m->opttype == OPT_SIMPLE) {
762                 *(int *)m->optarg = 1;
763                 return (m - opts);
764         }
765
766         if (*pargc == 0)
767                 errx(1, "option requires argument '%s'", arg);
768         optarg = *(*pargv)++;
769         (*pargc)--;
770
771         switch (m->opttype) {
772
773           case OPT_UINT:
774                 ularg = strtoul(optarg, &end, 0);
775                 if (*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;
780                 break;
781
782           case OPT_INT:
783                 larg = strtol(optarg, &end, 0);
784                 if (*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;
789                 break;
790
791           case OPT_UINT32:
792                 ularg = strtoul(optarg, &end, 0);
793                 if (*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;
798                 break;
799
800           case OPT_INT32:
801                 larg = strtol(optarg, &end, 0);
802                 if (*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;
807                 break;
808
809           case OPT_UINT64:
810                 *(uint64_t *)m->optarg = strtoull(optarg, &end, 0);
811                 if (*end != '\0')
812                         errx(1, "bad unsigned integer argument for '%s'", arg);
813                 break;
814
815           case OPT_INT64:
816                 *(int64_t *)m->optarg = strtoll(optarg, &end, 0);
817                 if (*end != '\0')
818                         errx(1, "bad integer argument for '%s'", arg);
819                 break;
820
821           case OPT_FLAG:
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;
834                 else
835                         errx(1, "bad boolean argument to '%s'", arg);
836                 break;
837
838           case OPT_VCI:
839                 ularg = strtoul(optarg, &end, 0);
840                 if (*end == '.') {
841                         ularg1 = strtoul(end + 1, &end, 0);
842                 } else {
843                         ularg1 = ularg;
844                         ularg = 0;
845                 }
846                 if (*end != '\0')
847                         errx(1, "bad VCI value for option '%s'", arg);
848                 if (ularg > 0xff)
849                         errx(1, "VPI value too large for option '%s'", arg);
850                 if (ularg1 > 0xffff)
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;
854                 break;
855
856           case OPT_STRING:
857                 if (m->optarg != NULL)
858                         *(const char **)m->optarg = optarg;
859                 break;
860
861           default:
862                 errx(1, "(internal) bad option type %u for '%s'",
863                     m->opttype, arg);
864         }
865         return (m - opts);
866 }
867
868 /*
869  * for compiled-in modules
870  */
871 void
872 register_module(const struct amodule *mod)
873 {
874         main_tab_size++;
875         if ((main_tab = realloc(main_tab, main_tab_size * sizeof(main_tab[0])))
876             == NULL)
877                 err(1, NULL);
878         main_tab[main_tab_size - 2] = *mod->cmd;
879         memset(&main_tab[main_tab_size - 1], 0, sizeof(main_tab[0]));
880 }