1139826Simp/* 253541Sshin * Copyright (c) 2001-2003 353541Sshin * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 453541Sshin * All rights reserved. 553541Sshin * 653541Sshin * Redistribution and use in source and binary forms, with or without 753541Sshin * modification, are permitted provided that the following conditions 853541Sshin * are met: 953541Sshin * 1. Redistributions of source code must retain the above copyright 1053541Sshin * notice, this list of conditions and the following disclaimer. 1153541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer in the 1353541Sshin * documentation and/or other materials provided with the distribution. 1453541Sshin * 1553541Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1653541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1753541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1853541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1953541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2053541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2153541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2253541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2353541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2453541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2553541Sshin * SUCH DAMAGE. 2653541Sshin * 2753541Sshin * Author: Hartmut Brandt <harti@freebsd.org> 28174510Sobrien */ 29174510Sobrien#include <sys/cdefs.h> 3053541Sshin__FBSDID("$FreeBSD: releng/10.3/sbin/atm/atmconfig/main.c 270824 2014-08-29 18:26:55Z ngie $"); 3153541Sshin 32174510Sobrien#include <sys/types.h> 33174510Sobrien#include <sys/sysctl.h> 34174510Sobrien#include <netdb.h> 3562587Sitojun#include <stdarg.h> 3662587Sitojun#include <ctype.h> 37142215Sglebius#include <limits.h> 38178167Sqingli#include <stdint.h> 3955009Sshin#include <fnmatch.h> 4053541Sshin#include <dirent.h> 4153541Sshin#ifdef WITH_BSNMP 4253541Sshin#include <bsnmp/asn1.h> 43186119Sqingli#include <bsnmp/snmp.h> 44186119Sqingli#include <bsnmp/snmpclient.h> 4553541Sshin#endif 4653541Sshin 4753541Sshin#include "atmconfig.h" 4853541Sshin#include "private.h" 4953541Sshin 5053541Sshin/* verbosity level */ 5153541Sshinstatic int verbose; 5253541Sshin 5378064Sume/* notitle option */ 5453541Sshinstatic int notitle; 5553541Sshin 5653541Sshin/* need to put heading before next output */ 5753541Sshinstatic int need_heading; 58147306Sbrooks 5953541Sshin/* 60178167Sqingli * TOP LEVEL commands 61178167Sqingli */ 62178167Sqinglistatic void help_func(int argc, char *argv[]) __dead2; 6353541Sshin 6453541Sshinstatic const struct cmdtab static_main_tab[] = { 6553541Sshin { "help", NULL, help_func }, 66186119Sqingli { "options", NULL, NULL }, 67186119Sqingli { "commands", NULL, NULL }, 6853541Sshin { "diag", diag_tab, NULL }, 69151477Ssuz { "natm", natm_tab, NULL }, 7062587Sitojun { NULL, NULL, NULL } 7153541Sshin}; 72148385Sume 7353541Sshinstatic struct cmdtab *main_tab = NULL; 7462587Sitojunstatic size_t main_tab_size = sizeof(static_main_tab) / 75211193Swill sizeof(static_main_tab[0]); 76211501Sanchie 7753541Sshinstatic int 7862587Sitojunsubstr(const char *s1, const char *s2) 7953541Sshin{ 8062587Sitojun return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0); 81175162Sobrien} 82175162Sobrien 83175162Sobrien/* 84191816Szec * Current help file state 85175162Sobrien */ 86175162Sobrienstruct help_file { 87175162Sobrien int file_state; /* 0:looking for main file, 1:found, 2:other */ 8853541Sshin const char *p_start; /* current path pointer */ 89207369Sbz const char *p_end; /* end of current path in path */ 90207369Sbz char *dirname; /* directory name */ 91195727Srwatson DIR *dir; /* open directory */ 92195727Srwatson char *fname; /* current filename */ 93195699Srwatson FILE *fp; /* open file */ 9453541Sshin char line[LINE_MAX]; /* current line */ 95108470Sschweikh u_int fcnt; /* count of files found */ 9653541Sshin}; 9753541Sshin 98148987Sumestruct help_pos { 9953541Sshin off_t pos; /* file position */ 10053541Sshin u_int fcnt; /* number of file */ 101171259Sdelphij char *fname; /* name of file */ 10253541Sshin const char *p_start; /* current path pointer */ 10353541Sshin const char *p_end; /* end of current path in path */ 10453541Sshin}; 10562587Sitojun 10653541Sshinstatic int 10753541Sshinhelp_next_file(struct help_file *hp) 10862587Sitojun{ 10953541Sshin const char *fpat; 11053541Sshin struct dirent *ent; 111142215Sglebius 11253541Sshin if (hp->file_state == 3) 11353541Sshin return (-1); 11453541Sshin 11553541Sshin if (hp->file_state == 0) 11662587Sitojun fpat = FILE_HELP; 117165118Sbz else 11853541Sshin fpat = FILE_HELP_OTHERS; 11978064Sume 12078064Sume if (hp->file_state == 0 || hp->file_state == 1) { 12178064Sume /* start from beginning */ 12278064Sume hp->p_start = PATH_HELP; 12378064Sume hp->file_state++; 12478064Sume } 125190964Srwatson 12678064Sume try_file: 12778064Sume if (hp->dir != NULL) { 12878064Sume /* directory open (must be state 2) */ 12978064Sume while ((ent = readdir(hp->dir)) != NULL) { 13078064Sume if (fnmatch(fpat, ent->d_name, FNM_NOESCAPE) != 0) 131148385Sume continue; 132148385Sume if (asprintf(&hp->fname, "%s/%s", hp->dirname, 13378064Sume ent->d_name) == -1) 13453541Sshin err(1, NULL); 13578064Sume if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 13678064Sume hp->fcnt++; 137165118Sbz return (0); 138165118Sbz } 13978064Sume free(hp->fname); 14053541Sshin } 14153541Sshin /* end of directory */ 14253541Sshin closedir(hp->dir); 143148987Sume hp->dir = NULL; 144120941Sume free(hp->dirname); 14595023Ssuz goto next_path; 146120941Sume } 147120941Sume 148120941Sume /* nothing open - advanc to new path element */ 14995023Ssuz try_path: 15053541Sshin for (hp->p_end = hp->p_start; *hp->p_end != '\0' && 15178064Sume *hp->p_end != ':'; hp->p_end++) 152120941Sume ; 15353541Sshin 15453541Sshin if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start), 155185348Szec hp->p_start) == -1) 156183529Scperciva err(1, NULL); 157183529Scperciva 158183529Scperciva if (hp->file_state == 1) { 159183529Scperciva /* just try to open */ 160183529Scperciva if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1) 161183529Scperciva err(1, NULL); 162183529Scperciva if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 163183529Scperciva hp->fcnt++; 164183529Scperciva return (0); 165183529Scperciva } 166183529Scperciva free(hp->fname); 167183529Scperciva 168186119Sqingli goto next_path; 169183529Scperciva } 170183529Scperciva 171183529Scperciva /* open directory */ 172183529Scperciva if ((hp->dir = opendir(hp->dirname)) != NULL) 17353541Sshin goto try_file; 17453541Sshin 17553541Sshin free(hp->dirname); 17678064Sume 17753541Sshin next_path: 17853541Sshin hp->p_start = hp->p_end; 17953541Sshin if (*hp->p_start == '\0') { 18053541Sshin /* end of path */ 18153541Sshin if (hp->file_state == 1) 18253541Sshin errx(1, "help file not found"); 18378064Sume return (-1); 18478064Sume } 18578064Sume hp->p_start++; 18678064Sume goto try_path; 18753541Sshin 18853541Sshin} 18953541Sshin 19095023Ssuz/* 19153541Sshin * Save current file position 19253541Sshin */ 193120941Sumestatic void 19453541Sshinhelp_file_tell(struct help_file *hp, struct help_pos *pos) 19578064Sume{ 19678064Sume if (pos->fname != NULL) 19753541Sshin free(pos->fname); 19853541Sshin if ((pos->fname = strdup(hp->fname)) == NULL) 19953541Sshin err(1, NULL); 20053541Sshin pos->fcnt = hp->fcnt; 20153541Sshin pos->p_start = hp->p_start; 20253541Sshin pos->p_end = hp->p_end; 20353541Sshin if ((pos->pos = ftello(hp->fp)) == -1) 20453541Sshin err(1, "%s", pos->fname); 20553541Sshin} 20653541Sshin 20753541Sshin/* 20853541Sshin * Go to that position 20953541Sshin * 21053541Sshin * We can go either to the original help file or back in the current file. 21153541Sshin */ 21253541Sshinstatic void 21353541Sshinhelp_file_seek(struct help_file *hp, struct help_pos *pos) 21453541Sshin{ 21553541Sshin hp->p_start = pos->p_start; 21653541Sshin hp->p_end = pos->p_end; 21753541Sshin hp->fcnt = pos->fcnt; 21853541Sshin 21953541Sshin if (hp->dir != NULL) { 22053541Sshin free(hp->dirname); 22153541Sshin closedir(hp->dir); 222142215Sglebius hp->dir = NULL; 223211157Swill } 224151465Ssuz 225142215Sglebius if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) { 22653541Sshin free(hp->fname); 22753541Sshin fclose(hp->fp); 228151465Ssuz hp->fp = NULL; 22953541Sshin } 23053541Sshin if (hp->fp == NULL) { 231121765Ssam if ((hp->fname = strdup(pos->fname)) == NULL) 232178167Sqingli err(1, NULL); 233178167Sqingli if ((hp->fp = fopen(hp->fname, "r")) == NULL) 234178167Sqingli err(1, "reopen %s", hp->fname); 23553541Sshin } 236171260Sdelphij if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1) 23753541Sshin err(1, "seek %s", hp->fname); 23853541Sshin 23953541Sshin if (pos->fcnt == 1) 24053541Sshin /* go back to state 1 */ 241178167Sqingli hp->file_state = 1; 242178167Sqingli else 243178167Sqingli /* lock */ 244178167Sqingli hp->file_state = 3; 245178167Sqingli} 246178167Sqingli 24753541Sshin/* 248178167Sqingli * Rewind to position 0 249121765Ssam */ 250121765Ssamstatic void 251121765Ssamhelp_file_rewind(struct help_file *hp) 252187946Sbz{ 253121765Ssam 25453541Sshin if (hp->file_state == 1) { 25562587Sitojun if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1) 25653541Sshin err(1, "rewind help file"); 25762587Sitojun return; 25862587Sitojun } 25962587Sitojun 26053541Sshin if (hp->dir != NULL) { 26162587Sitojun free(hp->dirname); 26262587Sitojun closedir(hp->dir); 26353541Sshin hp->dir = NULL; 26453541Sshin } 265151479Ssuz 26653541Sshin if (hp->fp != NULL) { 26778064Sume free(hp->fname); 26853541Sshin fclose(hp->fp); 26953541Sshin hp->fp = NULL; 27053541Sshin } 27162587Sitojun memset(hp, 0, sizeof(*hp)); 27253541Sshin} 27353541Sshin 27453541Sshin/* 27553541Sshin * Get next line from a help file 27653541Sshin */ 27762587Sitojunstatic const char * 27853541Sshinhelp_next_line(struct help_file *hp) 27953541Sshin{ 280120941Sume for (;;) { 28153541Sshin if (hp->fp != NULL) { 282165118Sbz if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL) 283120941Sume return (hp->line); 28478064Sume if (ferror(hp->fp)) 28553541Sshin err(1, "%s", hp->fname); 28653541Sshin free(hp->fname); 28753541Sshin 288120941Sume fclose(hp->fp); 289165118Sbz hp->fp = NULL; 29062587Sitojun } 29153541Sshin if (help_next_file(hp) == -1) 29253541Sshin return (NULL); 29353541Sshin } 29453541Sshin 29553541Sshin} 29653541Sshin 29753541Sshin/* 29853541Sshin * This function prints the available 0-level help topics from all 29953541Sshin * other help files by scanning the files. It assumes, that this is called 30053541Sshin * only from the main help file. 30153541Sshin */ 30253541Sshinstatic void 30353541Sshinhelp_get_0topics(struct help_file *hp) 30453541Sshin{ 30553541Sshin struct help_pos save; 30653541Sshin const char *line; 30753541Sshin 308148987Sume memset(&save, 0, sizeof(save)); 30953541Sshin help_file_tell(hp, &save); 31053541Sshin 31153541Sshin help_file_rewind(hp); 31253541Sshin while ((line = help_next_line(hp)) != NULL) { 31353541Sshin if (line[0] == '^' && line[1] == '^') 31453541Sshin printf("%s", line + 2); 31553541Sshin } 31662587Sitojun help_file_seek(hp, &save); 31753541Sshin} 31853541Sshin 31953541Sshin/* 32053541Sshin * Function to print help. The help argument is in argv[0] here. 32153541Sshin */ 32253541Sshinstatic void 32353541Sshinhelp_func(int argc, char *argv[]) 32453541Sshin{ 32553541Sshin struct help_file hfile; 32653541Sshin struct help_pos match, last_match; 32753541Sshin const char *line; 328148385Sume char key[100]; 329148385Sume int level; 330148385Sume int i, has_sub_topics; 331148385Sume 332148385Sume memset(&hfile, 0, sizeof(hfile)); 333148385Sume memset(&match, 0, sizeof(match)); 334120941Sume memset(&last_match, 0, sizeof(last_match)); 335181803Sbz 336120941Sume if (argc == 0) { 33762587Sitojun /* only 'help' - show intro */ 33853541Sshin if ((argv[0] = strdup("intro")) == NULL) 33953541Sshin err(1, NULL); 340120941Sume argc = 1; 341120941Sume } 34253541Sshin 34353541Sshin optind = 0; 344120941Sume match.pos = -1; 345181803Sbz last_match.pos = -1; 346120941Sume for (;;) { 34762587Sitojun /* read next line */ 348194760Srwatson if ((line = help_next_line(&hfile)) == NULL) { 349194760Srwatson /* EOF */ 35062587Sitojun level = 999; 35153541Sshin goto stop; 35253541Sshin } 35353541Sshin if (line[0] != '^' || line[1] == '^') 354165118Sbz continue; 355165118Sbz 356165118Sbz if (sscanf(line + 1, "%d%99s", &level, key) != 2) 357165118Sbz errx(1, "error in help file '%s'", line); 358165118Sbz 359165118Sbz if (level < optind) { 360190964Srwatson stop: 361194760Srwatson /* next higher level entry - stop this level */ 362194760Srwatson if (match.pos == -1) { 36362587Sitojun /* not found */ 36453541Sshin goto not_found; 36553541Sshin } 36653541Sshin /* go back to the match */ 367108470Sschweikh help_file_seek(&hfile, &match); 36853541Sshin last_match = match; 36953541Sshin memset(&match, 0, sizeof(match)); 37053541Sshin match.pos = -1; 37153541Sshin 37253541Sshin /* go to next key */ 373148987Sume if (++optind >= argc) 374171259Sdelphij break; 375171259Sdelphij } 376171259Sdelphij if (level == optind) { 37753541Sshin if (substr(argv[optind], key)) { 37853541Sshin if (match.pos != -1) { 379186119Sqingli printf("Ambiguous topic."); 380186119Sqingli goto list_topics; 38153541Sshin } 38253541Sshin help_file_tell(&hfile, &match); 383211501Sanchie } 38453541Sshin } 38553541Sshin } 38653541Sshin 38753541Sshin /* before breaking above we have seeked back to the matching point */ 38862587Sitojun for (;;) { 38953541Sshin if ((line = help_next_line(&hfile)) == NULL) 390148385Sume break; 391120941Sume 39253541Sshin if (line[0] == '#') 39353541Sshin continue; 39453541Sshin if (line[0] == '^') { 39562587Sitojun if (line[1] == '^') 39662587Sitojun continue; 39762587Sitojun break; 39862587Sitojun } 39962587Sitojun if (strncmp(line, "$MAIN", 5) == 0) { 40062587Sitojun help_get_0topics(&hfile); 40162587Sitojun continue; 40262587Sitojun } 40353541Sshin printf("%s", line); 40462587Sitojun } 40553541Sshin 406111119Simp exit(0); 40762587Sitojun 408111119Simp not_found: 40962587Sitojun printf("Topic not found."); 41062587Sitojun 41162587Sitojun list_topics: 41262587Sitojun printf(" Use one of:\natmconfig help"); 41362587Sitojun for (i = 0; i < optind; i++) 41462587Sitojun printf(" %s", argv[i]); 41562587Sitojun 41678064Sume printf(" ["); 41762587Sitojun 418215559Sbz /* list all the keys at this level */ 419215559Sbz if (last_match.pos == -1) 42053541Sshin /* go back to start of help */ 42153541Sshin help_file_rewind(&hfile); 42253541Sshin else 42353541Sshin help_file_seek(&hfile, &last_match); 42453541Sshin 42553541Sshin has_sub_topics = 0; 42653541Sshin while ((line = help_next_line(&hfile)) != NULL) { 42753541Sshin if (line[0] == '#' || line[0] != '^' || line[1] == '^') 42853541Sshin continue; 42995023Ssuz 43053541Sshin if (sscanf(line + 1, "%d%99s", &level, key) != 2) 43153541Sshin errx(1, "error in help file '%s'", line); 43253541Sshin 43353541Sshin if (level < optind) 43462587Sitojun break; 43562587Sitojun if (level == optind) { 43653541Sshin has_sub_topics = 1; 43753541Sshin printf(" %s", key); 43853541Sshin } 43953541Sshin } 44053541Sshin printf(" ]."); 44153541Sshin if (!has_sub_topics) 44253541Sshin printf(" No sub-topics found."); 443148385Sume printf("\n"); 44453541Sshin exit(1); 44553541Sshin} 44653541Sshin 44753541Sshin#ifdef WITH_BSNMP 448148385Sume/* 449148385Sume * Parse a server specification 45053541Sshin * 45153541Sshin * syntax is [trans::][community@][server][:port] 452194760Srwatson */ 453194760Srwatsonstatic void 45453541Sshinparse_server(char *name) 45553541Sshin{ 45653541Sshin char *p, *s = name; 45753541Sshin 45853541Sshin /* look for a double colon */ 45953541Sshin for (p = s; *p != '\0'; p++) { 46053541Sshin if (*p == '\\' && p[1] != '\0') { 46153541Sshin p++; 46253541Sshin continue; 46353541Sshin } 46453541Sshin if (*p == ':' && p[1] == ':') 46553541Sshin break; 46653541Sshin } 467148385Sume if (*p != '\0') { 46853541Sshin if (p > s) { 469216022Sbz if (p - s == 3 && strncmp(s, "udp", 3) == 0) 47053541Sshin snmp_client.trans = SNMP_TRANS_UDP; 471216022Sbz else if (p - s == 6 && strncmp(s, "stream", 6) == 0) 472216022Sbz snmp_client.trans = SNMP_TRANS_LOC_STREAM; 473216022Sbz else if (p - s == 5 && strncmp(s, "dgram", 5) == 0) 474216022Sbz snmp_client.trans = SNMP_TRANS_LOC_DGRAM; 475216022Sbz else 476216022Sbz errx(1, "unknown SNMP transport '%.*s'", 477216022Sbz (int)(p - s), s); 478216022Sbz } 479216022Sbz s = p + 2; 480216022Sbz } 481216022Sbz 482216022Sbz /* look for a @ */ 483216022Sbz for (p = s; *p != '\0'; p++) { 484216022Sbz if (*p == '\\' && p[1] != '\0') { 485216022Sbz p++; 486216022Sbz continue; 487216022Sbz } 488216022Sbz if (*p == '@') 489148385Sume break; 490194760Srwatson } 491194760Srwatson 492216022Sbz if (*p != '\0') { 493194760Srwatson if (p - s > SNMP_COMMUNITY_MAXLEN) 494194760Srwatson err(1, "community string too long"); 495148385Sume strncpy(snmp_client.read_community, s, p - s); 496148385Sume snmp_client.read_community[p - s] = '\0'; 497216022Sbz strncpy(snmp_client.write_community, s, p - s); 498148385Sume snmp_client.write_community[p - s] = '\0'; 499148385Sume s = p + 1; 500148385Sume } 501148385Sume 502148385Sume /* look for a colon */ 503148385Sume for (p = s; *p != '\0'; p++) { 504194777Sbz if (*p == '\\' && p[1] != '\0') { 505194777Sbz p++; 506194777Sbz continue; 507165118Sbz } 508148385Sume if (*p == ':') 509148385Sume break; 510148385Sume } 511165118Sbz 512165118Sbz if (*p == ':') { 513148385Sume if (p > s) { 51453541Sshin *p = '\0'; 515216022Sbz snmp_client_set_host(&snmp_client, s); 51653541Sshin *p = ':'; 51753541Sshin } 51853541Sshin snmp_client_set_port(&snmp_client, p + 1); 51953541Sshin } else if (p > s) 52053541Sshin snmp_client_set_host(&snmp_client, s); 521148385Sume} 522148385Sume#endif 523148385Sume 52453541Sshinint 525216022Sbzmain(int argc, char *argv[]) 52653541Sshin{ 52753541Sshin int opt, i; 52853541Sshin const struct cmdtab *match, *cc, *tab; 52953541Sshin 53053541Sshin#ifdef WITH_BSNMP 53153541Sshin snmp_client_init(&snmp_client); 532121315Sume snmp_client.trans = SNMP_TRANS_LOC_STREAM; 53353541Sshin snmp_client_set_host(&snmp_client, PATH_ILMI_SOCK); 53453541Sshin#endif 53553541Sshin 53653541Sshin#ifdef WITH_BSNMP 53753541Sshin#define OPTSTR "htvs:" 53853541Sshin#else 53953541Sshin#define OPTSTR "htv" 54053541Sshin#endif 54153541Sshin 54253541Sshin while ((opt = getopt(argc, argv, OPTSTR)) != -1) 54353541Sshin switch (opt) { 54453541Sshin 54553541Sshin case 'h': 54653541Sshin help_func(0, argv); 54753541Sshin 54853541Sshin#ifdef WITH_BSNMP 54953541Sshin case 's': 55053541Sshin parse_server(optarg); 551120941Sume break; 55253541Sshin#endif 55353541Sshin 55453541Sshin case 'v': 55553541Sshin verbose++; 55653541Sshin break; 55753541Sshin 55853541Sshin case 't': 55953541Sshin notitle = 1; 56053541Sshin break; 56153541Sshin } 56253541Sshin 563120941Sume if (argv[optind] == NULL) 564120941Sume help_func(0, argv); 56553541Sshin 566211501Sanchie argc -= optind; 567211501Sanchie argv += optind; 568211501Sanchie 569211501Sanchie if ((main_tab = malloc(sizeof(static_main_tab))) == NULL) 570211501Sanchie err(1, NULL); 571211501Sanchie memcpy(main_tab, static_main_tab, sizeof(static_main_tab)); 572211501Sanchie 573211501Sanchie#ifdef WITH_BSNMP 574211501Sanchie /* XXX while this is compiled in */ 575151536Ssuz device_register(); 576148385Sume#endif 577148385Sume 578190964Srwatson cc = main_tab; 579148385Sume i = 0; 580148385Sume for (;;) { 581148385Sume /* 58253541Sshin * Scan the table for a match 583148385Sume */ 584148385Sume tab = cc; 585148385Sume match = NULL; 586148385Sume while (cc->string != NULL) { 587148385Sume if (substr(argv[i], cc->string)) { 588148385Sume if (match != NULL) { 589148385Sume printf("Ambiguous option '%s'", 590148385Sume argv[i]); 59153541Sshin cc = tab; 59253541Sshin goto subopts; 59353541Sshin } 59453541Sshin match = cc; 59553541Sshin } 59653541Sshin cc++; 597148987Sume } 59862587Sitojun if ((cc = match) == NULL) { 59962587Sitojun printf("Unknown option '%s'", argv[i]); 60062587Sitojun cc = tab; 60162587Sitojun goto subopts; 60253541Sshin } 60353541Sshin 604171259Sdelphij /* 60553541Sshin * Have a match. If there is no subtable, there must 60653541Sshin * be either a handler or the command is only a help entry. 60753541Sshin */ 60862587Sitojun if (cc->sub == NULL) { 60953541Sshin if (cc->func != NULL) 61062587Sitojun break; 61162587Sitojun printf("Unknown option '%s'", argv[i]); 61262587Sitojun cc = tab; 61362587Sitojun goto subopts; 61462587Sitojun } 61553541Sshin 61653541Sshin /* 617186468Skmacy * Look at the next argument. If it doesn't exist or it 61853541Sshin * looks like a switch, terminate the scan here. 619186119Sqingli */ 62053541Sshin if (argv[i + 1] == NULL || argv[i + 1][0] == '-') { 621186119Sqingli if (cc->func != NULL) 622211501Sanchie break; 623186119Sqingli printf("Need sub-option for '%s'", argv[i]); 624165118Sbz cc = cc->sub; 62553541Sshin goto subopts; 62653541Sshin } 62778064Sume 62878064Sume cc = cc->sub; 629165118Sbz i++; 630165118Sbz } 63178064Sume 63262587Sitojun argc -= i + 1; 63362587Sitojun argv += i + 1; 63462587Sitojun 63562587Sitojun (*cc->func)(argc, argv); 63662587Sitojun 63762587Sitojun return (0); 63862587Sitojun 63962587Sitojun subopts: 640190964Srwatson printf(". Select one of:\n"); 64153541Sshin while (cc->string != NULL) { 64253541Sshin if (cc->func != NULL || cc->sub != NULL) 64362587Sitojun printf("%s ", cc->string); 644148385Sume cc++; 64562587Sitojun } 64662587Sitojun printf("\n"); 64762587Sitojun 64862587Sitojun return (1); 64953541Sshin} 650148385Sume 651148385Sumevoid 652150202Ssuzverb(const char *fmt, ...) 65353541Sshin{ 65453541Sshin va_list ap; 65578064Sume 65653541Sshin if (verbose) { 657165118Sbz va_start(ap, fmt); 65878064Sume vfprintf(stderr, fmt, ap); 65953541Sshin fprintf(stderr, "\n"); 66053541Sshin va_end(ap); 66153541Sshin } 66278064Sume} 66378064Sume 66478064Sumevoid 66553541Sshinheading(const char *fmt, ...) 66653541Sshin{ 66753541Sshin va_list ap; 66853541Sshin 66953541Sshin if (need_heading) { 67078064Sume need_heading = 0; 67178064Sume if (!notitle) { 67278064Sume va_start(ap, fmt); 67362587Sitojun fprintf(stdout, fmt, ap); 67453541Sshin va_end(ap); 67553541Sshin } 67653541Sshin } 67753541Sshin} 67853541Sshin 67953541Sshinvoid 68053541Sshinheading_init(void) 68153541Sshin{ 68253541Sshin need_heading = 1; 68353541Sshin} 68453541Sshin 68553541Sshin/* 68653541Sshin * stringify an enumerated value 68753541Sshin */ 68853541Sshinconst char * 68953541Sshinpenum(int32_t value, const struct penum *strtab, char *buf) 69053541Sshin{ 69153541Sshin while (strtab->str != NULL) { 69253541Sshin if (strtab->value == value) { 69353541Sshin strcpy(buf, strtab->str); 694194760Srwatson return (buf); 69553541Sshin } 69662587Sitojun strtab++; 69753541Sshin } 69853541Sshin warnx("illegal value for enumerated variable '%d'", value); 69995023Ssuz strcpy(buf, "?"); 70053541Sshin return (buf); 701194760Srwatson} 70253541Sshin 70353541Sshin/* 704165118Sbz * And the other way 'round 70562587Sitojun */ 70653541Sshinint 70753541Sshinpparse(int32_t *val, const struct penum *tab, const char *str) 70853541Sshin{ 709120941Sume 710165118Sbz while (tab->str != NULL) { 711120941Sume if (strcmp(tab->str, str) == 0) { 71278064Sume *val = tab->value; 71353541Sshin return (0); 71453541Sshin } 71553541Sshin tab++; 716120941Sume } 717120941Sume return (-1); 71853541Sshin} 719186119Sqingli 720186119Sqingli/* 721186119Sqingli * Parse command line options 722186119Sqingli */ 72362587Sitojunint 724186119Sqingliparse_options(int *pargc, char ***pargv, const struct option *opts) 72553541Sshin{ 72653541Sshin const struct option *o, *m; 72753541Sshin char *arg; 72853541Sshin u_long ularg, ularg1; 72953541Sshin long larg; 73053541Sshin char *end; 731186119Sqingli 73262587Sitojun if (*pargc == 0) 733186119Sqingli return (-1); 73453541Sshin arg = (*pargv)[0]; 73553541Sshin if (arg[0] != '-' || arg[1] == '\0') 73653541Sshin return (-1); 73753541Sshin if (arg[1] == '-' && arg[2] == '\0') { 738186119Sqingli (*pargv)++; 739186119Sqingli (*pargc)--; 74053541Sshin return (-1); 74153541Sshin } 74262587Sitojun 743151539Ssuz m = NULL; 744186119Sqingli for (o = opts; o->optstr != NULL; o++) { 745186119Sqingli if (strlen(arg + 1) <= strlen(o->optstr) && 746120941Sume strncmp(arg + 1, o->optstr, strlen(arg + 1)) == 0) { 74778064Sume if (m != NULL) 74853541Sshin errx(1, "ambiguous option '%s'", arg); 749186119Sqingli m = o; 75078064Sume } 75178064Sume } 75278064Sume if (m == NULL) 75378064Sume errx(1, "unknown option '%s'", arg); 75478064Sume 75578064Sume (*pargv)++; 75678064Sume (*pargc)--; 757186468Skmacy 75878064Sume if (m->opttype == OPT_NONE) 75953541Sshin return (m - opts); 76053541Sshin 76153541Sshin if (m->opttype == OPT_SIMPLE) { 76253541Sshin *(int *)m->optarg = 1; 76353541Sshin return (m - opts); 76453541Sshin } 765151465Ssuz 76653541Sshin if (*pargc == 0) 76753541Sshin errx(1, "option requires argument '%s'", arg); 768186119Sqingli optarg = *(*pargv)++; 769186119Sqingli (*pargc)--; 77053541Sshin 77153541Sshin switch (m->opttype) { 77253541Sshin 77353541Sshin case OPT_UINT: 77453541Sshin ularg = strtoul(optarg, &end, 0); 77553541Sshin if (*end != '\0') 77653541Sshin errx(1, "bad unsigned integer argument for '%s'", arg); 77753541Sshin if (ularg > UINT_MAX) 77853541Sshin errx(1, "argument to large for option '%s'", arg); 77953541Sshin *(u_int *)m->optarg = (u_int)ularg; 78053541Sshin break; 78153541Sshin 78253541Sshin case OPT_INT: 78353541Sshin larg = strtol(optarg, &end, 0); 78453541Sshin if (*end != '\0') 78553541Sshin errx(1, "bad integer argument for '%s'", arg); 78653541Sshin if (larg > INT_MAX || larg < INT_MIN) 78753541Sshin errx(1, "argument out of range for option '%s'", arg); 78853541Sshin *(int *)m->optarg = (int)larg; 78953541Sshin break; 79053541Sshin 79153541Sshin case OPT_UINT32: 79253541Sshin ularg = strtoul(optarg, &end, 0); 79353541Sshin if (*end != '\0') 79453541Sshin errx(1, "bad unsigned integer argument for '%s'", arg); 79553541Sshin if (ularg > UINT32_MAX) 796151539Ssuz errx(1, "argument to large for option '%s'", arg); 79753541Sshin *(uint32_t *)m->optarg = (uint32_t)ularg; 79853541Sshin break; 79953541Sshin 80053541Sshin case OPT_INT32: 80178064Sume larg = strtol(optarg, &end, 0); 80253541Sshin if (*end != '\0') 803186119Sqingli errx(1, "bad integer argument for '%s'", arg); 80478064Sume if (larg > INT32_MAX || larg < INT32_MIN) 80562587Sitojun errx(1, "argument out of range for option '%s'", arg); 80653541Sshin *(int32_t *)m->optarg = (int32_t)larg; 807151465Ssuz break; 808151465Ssuz 80953541Sshin case OPT_UINT64: 81053541Sshin *(uint64_t *)m->optarg = strtoull(optarg, &end, 0); 81153541Sshin if (*end != '\0') 812151465Ssuz errx(1, "bad unsigned integer argument for '%s'", arg); 813186119Sqingli break; 814186119Sqingli 81553541Sshin case OPT_INT64: 81653541Sshin *(int64_t *)m->optarg = strtoll(optarg, &end, 0); 81753541Sshin if (*end != '\0') 81853541Sshin errx(1, "bad integer argument for '%s'", arg); 81953541Sshin break; 82053541Sshin 82153541Sshin case OPT_FLAG: 82253541Sshin if (strcasecmp(optarg, "enable") == 0 || 82353541Sshin strcasecmp(optarg, "yes") == 0 || 82462587Sitojun strcasecmp(optarg, "true") == 0 || 825151539Ssuz strcasecmp(optarg, "on") == 0 || 826186119Sqingli strcmp(optarg, "1") == 0) 827151539Ssuz *(int *)m->optarg = 1; 82853541Sshin else if (strcasecmp(optarg, "disable") == 0 || 82953541Sshin strcasecmp(optarg, "no") == 0 || 830151465Ssuz strcasecmp(optarg, "false") == 0 || 83153541Sshin strcasecmp(optarg, "off") == 0 || 832186119Sqingli strcmp(optarg, "0") == 0) 833181803Sbz *(int *)m->optarg = 0; 83478064Sume else 83553541Sshin errx(1, "bad boolean argument to '%s'", arg); 83653541Sshin break; 83753541Sshin 83853541Sshin case OPT_VCI: 83953541Sshin ularg = strtoul(optarg, &end, 0); 84053541Sshin if (*end == '.') { 84153541Sshin ularg1 = strtoul(end + 1, &end, 0); 84253541Sshin } else { 84353541Sshin ularg1 = ularg; 84453541Sshin ularg = 0; 84553541Sshin } 84653541Sshin if (*end != '\0') 847186119Sqingli errx(1, "bad VCI value for option '%s'", arg); 84895023Ssuz if (ularg > 0xff) 84995023Ssuz errx(1, "VPI value too large for option '%s'", arg); 85095023Ssuz if (ularg1 > 0xffff) 85195023Ssuz errx(1, "VCI value too large for option '%s'", arg); 85295023Ssuz ((u_int *)m->optarg)[0] = ularg; 853120941Sume ((u_int *)m->optarg)[1] = ularg1; 85495023Ssuz break; 855186119Sqingli 85653541Sshin case OPT_STRING: 85753541Sshin if (m->optarg != NULL) 858181803Sbz *(const char **)m->optarg = optarg; 85953541Sshin break; 86053541Sshin 86153541Sshin default: 86253541Sshin errx(1, "(internal) bad option type %u for '%s'", 86353541Sshin m->opttype, arg); 86453541Sshin } 86553541Sshin return (m - opts); 866128422Sluigi} 86753541Sshin 86853541Sshin/* 86953541Sshin * for compiled-in modules 87053541Sshin */ 871186119Sqinglivoid 872186119Sqingliregister_module(const struct amodule *mod) 873186119Sqingli{ 874186119Sqingli main_tab_size++; 875186119Sqingli if ((main_tab = realloc(main_tab, main_tab_size * sizeof(main_tab[0]))) 876186119Sqingli == NULL) 877151539Ssuz err(1, NULL); 878151539Ssuz main_tab[main_tab_size - 2] = *mod->cmd; 879169273Ssuz memset(&main_tab[main_tab_size - 1], 0, sizeof(main_tab[0])); 880186119Sqingli} 881186119Sqingli