main.c revision 133565
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: head/sbin/atm/atmconfig/main.c 133565 2004-08-12 12:31:43Z harti $"); 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 */ 51int verbose; 52 53/* notitle option */ 54static int notitle; 55 56/* need to put heading before next output */ 57static int need_heading; 58 59/* 60 * TOP LEVEL commands 61 */ 62static void help_func(int argc, char *argv[]) __dead2; 63 64static 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 73static struct cmdtab *main_tab = NULL; 74static size_t main_tab_size = sizeof(static_main_tab) / 75 sizeof(static_main_tab[0]); 76 77static int 78substr(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 */ 86struct 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 98struct 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 106static int 107help_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 */ 193static void 194help_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 */ 212static void 213help_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 */ 250static void 251help_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 */ 277static const char * 278help_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 */ 302static void 303help_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 */ 322static void 323help_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 */ 453static void 454parse_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 524int 525main(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 651void 652verb(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 664void 665heading(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 679void 680heading_init(void) 681{ 682 need_heading = 1; 683} 684 685/* 686 * stringify an enumerated value 687 */ 688const char * 689penum(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 */ 706int 707pparse(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 */ 723int 724parse_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 */ 871void 872register_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} 881