main.c revision 270824
1247835Skib/* 2247835Skib * Copyright (c) 2001-2003 3247835Skib * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4247835Skib * All rights reserved. 5247835Skib * 6247835Skib * Redistribution and use in source and binary forms, with or without 7247835Skib * modification, are permitted provided that the following conditions 8247835Skib * are met: 9247835Skib * 1. Redistributions of source code must retain the above copyright 10247835Skib * notice, this list of conditions and the following disclaimer. 11247835Skib * 2. Redistributions in binary form must reproduce the above copyright 12247835Skib * notice, this list of conditions and the following disclaimer in the 13247835Skib * documentation and/or other materials provided with the distribution. 14247835Skib * 15247835Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16247835Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17247835Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18247835Skib * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19247835Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20247835Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21247835Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22247835Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23247835Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24247835Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25247835Skib * SUCH DAMAGE. 26247835Skib * 27247835Skib * Author: Hartmut Brandt <harti@freebsd.org> 28247835Skib */ 29247835Skib#include <sys/cdefs.h> 30247835Skib__FBSDID("$FreeBSD: stable/10/sbin/atm/atmconfig/main.c 270824 2014-08-29 18:26:55Z ngie $"); 31247835Skib 32247835Skib#include <sys/types.h> 33247835Skib#include <sys/sysctl.h> 34247835Skib#include <netdb.h> 35247835Skib#include <stdarg.h> 36247835Skib#include <ctype.h> 37247835Skib#include <limits.h> 38247835Skib#include <stdint.h> 39247835Skib#include <fnmatch.h> 40247835Skib#include <dirent.h> 41247835Skib#ifdef WITH_BSNMP 42247835Skib#include <bsnmp/asn1.h> 43247835Skib#include <bsnmp/snmp.h> 44247835Skib#include <bsnmp/snmpclient.h> 45247835Skib#endif 46247835Skib 47247835Skib#include "atmconfig.h" 48247835Skib#include "private.h" 49247835Skib 50247835Skib/* verbosity level */ 51247835Skibstatic int verbose; 52247835Skib 53247835Skib/* notitle option */ 54247835Skibstatic int notitle; 55247835Skib 56247835Skib/* need to put heading before next output */ 57247835Skibstatic int need_heading; 58247835Skib 59247835Skib/* 60247835Skib * TOP LEVEL commands 61247835Skib */ 62247835Skibstatic void help_func(int argc, char *argv[]) __dead2; 63247835Skib 64247835Skibstatic const struct cmdtab static_main_tab[] = { 65247835Skib { "help", NULL, help_func }, 66247835Skib { "options", NULL, NULL }, 67247835Skib { "commands", NULL, NULL }, 68247835Skib { "diag", diag_tab, NULL }, 69247835Skib { "natm", natm_tab, NULL }, 70247835Skib { NULL, NULL, NULL } 71247835Skib}; 72247835Skib 73247835Skibstatic struct cmdtab *main_tab = NULL; 74247835Skibstatic size_t main_tab_size = sizeof(static_main_tab) / 75247835Skib sizeof(static_main_tab[0]); 76247835Skib 77247835Skibstatic int 78247835Skibsubstr(const char *s1, const char *s2) 79247835Skib{ 80247835Skib return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0); 81247835Skib} 82247835Skib 83247835Skib/* 84247835Skib * Current help file state 85247835Skib */ 86247835Skibstruct help_file { 87247835Skib int file_state; /* 0:looking for main file, 1:found, 2:other */ 88247835Skib const char *p_start; /* current path pointer */ 89247835Skib const char *p_end; /* end of current path in path */ 90247835Skib char *dirname; /* directory name */ 91247835Skib DIR *dir; /* open directory */ 92247835Skib char *fname; /* current filename */ 93247835Skib FILE *fp; /* open file */ 94247835Skib char line[LINE_MAX]; /* current line */ 95247835Skib u_int fcnt; /* count of files found */ 96247835Skib}; 97247835Skib 98247835Skibstruct help_pos { 99247835Skib off_t pos; /* file position */ 100247835Skib u_int fcnt; /* number of file */ 101247835Skib char *fname; /* name of file */ 102247835Skib const char *p_start; /* current path pointer */ 103247835Skib const char *p_end; /* end of current path in path */ 104247835Skib}; 105247835Skib 106247835Skibstatic int 107247835Skibhelp_next_file(struct help_file *hp) 108247835Skib{ 109247835Skib const char *fpat; 110247835Skib struct dirent *ent; 111247835Skib 112247835Skib if (hp->file_state == 3) 113247835Skib return (-1); 114247835Skib 115247835Skib if (hp->file_state == 0) 116247835Skib fpat = FILE_HELP; 117247835Skib else 118247835Skib fpat = FILE_HELP_OTHERS; 119247835Skib 120247835Skib if (hp->file_state == 0 || hp->file_state == 1) { 121247835Skib /* start from beginning */ 122247835Skib hp->p_start = PATH_HELP; 123247835Skib hp->file_state++; 124247835Skib } 125247835Skib 126247835Skib try_file: 127247835Skib if (hp->dir != NULL) { 128247835Skib /* directory open (must be state 2) */ 129247835Skib while ((ent = readdir(hp->dir)) != NULL) { 130247835Skib if (fnmatch(fpat, ent->d_name, FNM_NOESCAPE) != 0) 131247835Skib continue; 132247835Skib if (asprintf(&hp->fname, "%s/%s", hp->dirname, 133247835Skib ent->d_name) == -1) 134247835Skib err(1, NULL); 135247835Skib if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 136247835Skib hp->fcnt++; 137247835Skib return (0); 138247835Skib } 139247835Skib free(hp->fname); 140247835Skib } 141247835Skib /* end of directory */ 142247835Skib closedir(hp->dir); 143247835Skib hp->dir = NULL; 144247835Skib free(hp->dirname); 145247835Skib goto next_path; 146247835Skib } 147247835Skib 148247835Skib /* nothing open - advanc to new path element */ 149247835Skib try_path: 150247835Skib for (hp->p_end = hp->p_start; *hp->p_end != '\0' && 151247835Skib *hp->p_end != ':'; hp->p_end++) 152247835Skib ; 153247835Skib 154247835Skib if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start), 155247835Skib hp->p_start) == -1) 156247835Skib err(1, NULL); 157247835Skib 158247835Skib if (hp->file_state == 1) { 159247835Skib /* just try to open */ 160247835Skib if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1) 161247835Skib err(1, NULL); 162247835Skib if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 163247835Skib hp->fcnt++; 164247835Skib return (0); 165247835Skib } 166247835Skib free(hp->fname); 167247835Skib 168247835Skib goto next_path; 169247835Skib } 170247835Skib 171247835Skib /* open directory */ 172247835Skib if ((hp->dir = opendir(hp->dirname)) != NULL) 173247835Skib goto try_file; 174247835Skib 175247835Skib free(hp->dirname); 176247835Skib 177247835Skib next_path: 178247835Skib hp->p_start = hp->p_end; 179247835Skib if (*hp->p_start == '\0') { 180247835Skib /* end of path */ 181247835Skib if (hp->file_state == 1) 182247835Skib errx(1, "help file not found"); 183247835Skib return (-1); 184247835Skib } 185247835Skib hp->p_start++; 186247835Skib goto try_path; 187247835Skib 188247835Skib} 189247835Skib 190247835Skib/* 191247835Skib * Save current file position 192247835Skib */ 193247835Skibstatic void 194247835Skibhelp_file_tell(struct help_file *hp, struct help_pos *pos) 195247835Skib{ 196247835Skib if (pos->fname != NULL) 197247835Skib free(pos->fname); 198247835Skib if ((pos->fname = strdup(hp->fname)) == NULL) 199247835Skib err(1, NULL); 200247835Skib pos->fcnt = hp->fcnt; 201247835Skib pos->p_start = hp->p_start; 202247835Skib pos->p_end = hp->p_end; 203247835Skib if ((pos->pos = ftello(hp->fp)) == -1) 204247835Skib err(1, "%s", pos->fname); 205247835Skib} 206247835Skib 207247835Skib/* 208247835Skib * Go to that position 209247835Skib * 210247835Skib * We can go either to the original help file or back in the current file. 211247835Skib */ 212247835Skibstatic void 213247835Skibhelp_file_seek(struct help_file *hp, struct help_pos *pos) 214247835Skib{ 215247835Skib hp->p_start = pos->p_start; 216247835Skib hp->p_end = pos->p_end; 217247835Skib hp->fcnt = pos->fcnt; 218247835Skib 219247835Skib if (hp->dir != NULL) { 220247835Skib free(hp->dirname); 221247835Skib closedir(hp->dir); 222247835Skib hp->dir = NULL; 223247835Skib } 224247835Skib 225247835Skib if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) { 226247835Skib free(hp->fname); 227247835Skib fclose(hp->fp); 228247835Skib hp->fp = NULL; 229247835Skib } 230247835Skib if (hp->fp == NULL) { 231247835Skib if ((hp->fname = strdup(pos->fname)) == NULL) 232247835Skib err(1, NULL); 233247835Skib if ((hp->fp = fopen(hp->fname, "r")) == NULL) 234247835Skib err(1, "reopen %s", hp->fname); 235247835Skib } 236247835Skib if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1) 237247835Skib err(1, "seek %s", hp->fname); 238247835Skib 239247835Skib if (pos->fcnt == 1) 240247835Skib /* go back to state 1 */ 241247835Skib hp->file_state = 1; 242247835Skib else 243247835Skib /* lock */ 244247835Skib hp->file_state = 3; 245247835Skib} 246247835Skib 247247835Skib/* 248247835Skib * Rewind to position 0 249247835Skib */ 250247835Skibstatic void 251247835Skibhelp_file_rewind(struct help_file *hp) 252247835Skib{ 253247835Skib 254247835Skib if (hp->file_state == 1) { 255247835Skib if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1) 256247835Skib err(1, "rewind help file"); 257247835Skib return; 258247835Skib } 259247835Skib 260247835Skib if (hp->dir != NULL) { 261247835Skib free(hp->dirname); 262247835Skib closedir(hp->dir); 263247835Skib hp->dir = NULL; 264247835Skib } 265247835Skib 266247835Skib if (hp->fp != NULL) { 267247835Skib free(hp->fname); 268247835Skib fclose(hp->fp); 269247835Skib hp->fp = NULL; 270247835Skib } 271247835Skib memset(hp, 0, sizeof(*hp)); 272247835Skib} 273247835Skib 274247835Skib/* 275247835Skib * Get next line from a help file 276247835Skib */ 277247835Skibstatic const char * 278247835Skibhelp_next_line(struct help_file *hp) 279247835Skib{ 280247835Skib for (;;) { 281247835Skib if (hp->fp != NULL) { 282247835Skib if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL) 283247835Skib return (hp->line); 284247835Skib if (ferror(hp->fp)) 285247835Skib err(1, "%s", hp->fname); 286247835Skib free(hp->fname); 287247835Skib 288248084Sattilio fclose(hp->fp); 289247835Skib hp->fp = NULL; 290247835Skib } 291254649Skib if (help_next_file(hp) == -1) 292247835Skib return (NULL); 293247835Skib } 294247835Skib 295247835Skib} 296247835Skib 297247835Skib/* 298247835Skib * This function prints the available 0-level help topics from all 299247835Skib * other help files by scanning the files. It assumes, that this is called 300247835Skib * only from the main help file. 301247835Skib */ 302247835Skibstatic void 303247835Skibhelp_get_0topics(struct help_file *hp) 304247835Skib{ 305254138Sattilio struct help_pos save; 306247835Skib const char *line; 307247835Skib 308247835Skib memset(&save, 0, sizeof(save)); 309247835Skib help_file_tell(hp, &save); 310247835Skib 311247835Skib help_file_rewind(hp); 312247835Skib while ((line = help_next_line(hp)) != NULL) { 313247835Skib if (line[0] == '^' && line[1] == '^') 314248084Sattilio printf("%s", line + 2); 315247835Skib } 316247835Skib help_file_seek(hp, &save); 317247835Skib} 318247835Skib 319247835Skib/* 320247835Skib * Function to print help. The help argument is in argv[0] here. 321247835Skib */ 322247835Skibstatic void 323247835Skibhelp_func(int argc, char *argv[]) 324248084Sattilio{ 325247835Skib struct help_file hfile; 326247835Skib struct help_pos match, last_match; 327247835Skib const char *line; 328247835Skib char key[100]; 329247835Skib int level; 330247835Skib int i, has_sub_topics; 331247835Skib 332247835Skib memset(&hfile, 0, sizeof(hfile)); 333247835Skib memset(&match, 0, sizeof(match)); 334247835Skib memset(&last_match, 0, sizeof(last_match)); 335247835Skib 336247835Skib if (argc == 0) { 337247835Skib /* only 'help' - show intro */ 338247835Skib if ((argv[0] = strdup("intro")) == NULL) 339247835Skib err(1, NULL); 340247835Skib argc = 1; 341247835Skib } 342247835Skib 343247835Skib optind = 0; 344247835Skib match.pos = -1; 345247835Skib last_match.pos = -1; 346247835Skib for (;;) { 347247835Skib /* read next line */ 348248084Sattilio if ((line = help_next_line(&hfile)) == NULL) { 349247835Skib /* EOF */ 350247835Skib level = 999; 351247835Skib goto stop; 352247835Skib } 353247835Skib if (line[0] != '^' || line[1] == '^') 354254649Skib continue; 355247835Skib 356254875Sdumbbell if (sscanf(line + 1, "%d%99s", &level, key) != 2) 357247835Skib errx(1, "error in help file '%s'", line); 358254138Sattilio 359247835Skib if (level < optind) { 360247835Skib stop: 361248084Sattilio /* next higher level entry - stop this level */ 362247835Skib if (match.pos == -1) { 363247835Skib /* not found */ 364247835Skib goto not_found; 365247835Skib } 366247835Skib /* go back to the match */ 367247835Skib help_file_seek(&hfile, &match); 368247835Skib last_match = match; 369247835Skib 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#ifdef WITH_BSNMP 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#ifdef WITH_BSNMP 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 WITH_BSNMP 537#define OPTSTR "htvs:" 538#else 539#define OPTSTR "htv" 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#ifdef WITH_BSNMP 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#ifdef WITH_BSNMP 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