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