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>
| 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 119172 2003-08-20 08:25:36Z harti $");
| 30__FBSDID("$FreeBSD: head/sbin/atm/atmconfig/main.c 132493 2004-07-21 09:42:56Z 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>
| 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 <inttypes.h>
| 38#include <stdint.h> 39#include <fnmatch.h> 40#include <dirent.h>
|
39#include "atmconfig.h" 40#include "private.h" 41 42/* verbosity level */ 43int verbose; 44 45/* notitle option */ 46static int notitle; 47 48/* need to put heading before next output */ 49static int need_heading; 50 51/* 52 * TOP LEVEL commands 53 */ 54static void help_func(int argc, char *argv[]) __dead2; 55 56static const struct cmdtab main_tab[] = { 57 { "help", NULL, help_func }, 58 { "options", NULL, NULL }, 59 { "commands", NULL, NULL }, 60 { "diag", diag_tab, NULL }, 61 { "natm", natm_tab, NULL }, 62 { NULL, NULL, NULL } 63}; 64 65static int 66substr(const char *s1, const char *s2) 67{ 68 return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0); 69} 70 71/*
| 41#include "atmconfig.h" 42#include "private.h" 43 44/* verbosity level */ 45int verbose; 46 47/* notitle option */ 48static int notitle; 49 50/* need to put heading before next output */ 51static int need_heading; 52 53/* 54 * TOP LEVEL commands 55 */ 56static void help_func(int argc, char *argv[]) __dead2; 57 58static const struct cmdtab main_tab[] = { 59 { "help", NULL, help_func }, 60 { "options", NULL, NULL }, 61 { "commands", NULL, NULL }, 62 { "diag", diag_tab, NULL }, 63 { "natm", natm_tab, NULL }, 64 { NULL, NULL, NULL } 65}; 66 67static int 68substr(const char *s1, const char *s2) 69{ 70 return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0); 71} 72 73/*
|
| 74 * Current help file state 75 */ 76struct help_file { 77 int file_state; /* 0:looking for main file, 1:found, 2:other */ 78 const char *p_start; /* current path pointer */ 79 const char *p_end; /* end of current path in path */ 80 char *dirname; /* directory name */ 81 DIR *dir; /* open directory */ 82 char *fname; /* current filename */ 83 FILE *fp; /* open file */ 84 char line[LINE_MAX]; /* current line */ 85 u_int fcnt; /* count of files found */ 86}; 87 88struct help_pos { 89 off_t pos; /* file position */ 90 u_int fcnt; /* number of file */ 91 char *fname; /* name of file */ 92 const char *p_start; /* current path pointer */ 93 const char *p_end; /* end of current path in path */ 94}; 95 96static int 97help_next_file(struct help_file *hp) 98{ 99 const char *fpat; 100 struct dirent *ent; 101 102 if (hp->file_state == 3) 103 return (-1); 104 105 if (hp->file_state == 0) 106 fpat = FILE_HELP; 107 else 108 fpat = FILE_HELP_OTHERS; 109 110 if (hp->file_state == 0 || hp->file_state == 1) { 111 /* start from beginning */ 112 hp->p_start = PATH_HELP; 113 hp->file_state++; 114 } 115 116 try_file: 117 if (hp->dir != NULL) { 118 /* directory open (must be state 2) */ 119 while ((ent = readdir(hp->dir)) != NULL) { 120 if (fnmatch(fpat, ent->d_name, FNM_NOESCAPE) != 0) 121 continue; 122 if (asprintf(&hp->fname, "%s/%s", hp->dirname, 123 ent->d_name) == -1) 124 err(1, NULL); 125 if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 126 hp->fcnt++; 127 return (0); 128 } 129 free(hp->fname); 130 } 131 /* end of directory */ 132 closedir(hp->dir); 133 hp->dir = NULL; 134 free(hp->dirname); 135 goto next_path; 136 } 137 138 /* nothing open - advanc to new path element */ 139 try_path: 140 for (hp->p_end = hp->p_start; *hp->p_end != '\0' && 141 *hp->p_end != ':'; hp->p_end++) 142 ; 143 144 if (asprintf(&hp->dirname, "%.*s", (int)(hp->p_end - hp->p_start), 145 hp->p_start) == -1) 146 err(1, NULL); 147 148 if (hp->file_state == 1) { 149 /* just try to open */ 150 if (asprintf(&hp->fname, "%s/%s", hp->dirname, fpat) == -1) 151 err(1, NULL); 152 if ((hp->fp = fopen(hp->fname, "r")) != NULL) { 153 hp->fcnt++; 154 return (0); 155 } 156 free(hp->fname); 157 158 goto next_path; 159 } 160 161 /* open directory */ 162 if ((hp->dir = opendir(hp->dirname)) != NULL) 163 goto try_file; 164 165 free(hp->dirname); 166 167 next_path: 168 hp->p_start = hp->p_end; 169 if (*hp->p_start == '\0') { 170 /* end of path */ 171 if (hp->file_state == 1) 172 errx(1, "help file not found"); 173 return (-1); 174 } 175 hp->p_start++; 176 goto try_path; 177 178} 179 180/* 181 * Save current file position 182 */ 183static void 184help_file_tell(struct help_file *hp, struct help_pos *pos) 185{ 186 if (pos->fname != NULL) 187 free(pos->fname); 188 if ((pos->fname = strdup(hp->fname)) == NULL) 189 err(1, NULL); 190 pos->fcnt = hp->fcnt; 191 pos->p_start = hp->p_start; 192 pos->p_end = hp->p_end; 193 if ((pos->pos = ftello(hp->fp)) == -1) 194 err(1, "%s", pos->fname); 195} 196 197/* 198 * Go to that position 199 * 200 * We can go either to the original help file or back in the current file. 201 */ 202static void 203help_file_seek(struct help_file *hp, struct help_pos *pos) 204{ 205 hp->p_start = pos->p_start; 206 hp->p_end = pos->p_end; 207 hp->fcnt = pos->fcnt; 208 209 if (hp->dir != NULL) { 210 free(hp->dirname); 211 closedir(hp->dir); 212 hp->dir = NULL; 213 } 214 215 if (hp->fp != NULL &&strcmp(hp->fname, pos->fname) != 0) { 216 free(hp->fname); 217 fclose(hp->fp); 218 hp->fp = NULL; 219 } 220 if (hp->fp == NULL) { 221 if ((hp->fname = strdup(pos->fname)) == NULL) 222 err(1, NULL); 223 if ((hp->fp = fopen(hp->fname, "r")) == NULL) 224 err(1, "reopen %s", hp->fname); 225 } 226 if (fseeko(hp->fp, pos->pos, SEEK_SET) == -1) 227 err(1, "seek %s", hp->fname); 228 229 if (pos->fcnt == 1) 230 /* go back to state 1 */ 231 hp->file_state = 1; 232 else 233 /* lock */ 234 hp->file_state = 3; 235} 236 237/* 238 * Rewind to position 0 239 */ 240static void 241help_file_rewind(struct help_file *hp) 242{ 243 244 if (hp->file_state == 1) { 245 if (fseeko(hp->fp, (off_t)0, SEEK_SET) == -1) 246 err(1, "rewind help file"); 247 return; 248 } 249 250 if (hp->dir != NULL) { 251 free(hp->dirname); 252 closedir(hp->dir); 253 hp->dir = NULL; 254 } 255 256 if (hp->fp != NULL) { 257 free(hp->fname); 258 fclose(hp->fp); 259 hp->fp = NULL; 260 } 261 memset(hp, 0, sizeof(*hp)); 262} 263 264/* 265 * Get next line from a help file 266 */ 267static const char * 268help_next_line(struct help_file *hp) 269{ 270 for (;;) { 271 if (hp->fp != NULL) { 272 if (fgets(hp->line, sizeof(hp->line), hp->fp) != NULL) 273 return (hp->line); 274 if (ferror(hp->fp)) 275 err(1, "%s", hp->fname); 276 free(hp->fname); 277 278 fclose(hp->fp); 279 hp->fp = NULL; 280 } 281 if (help_next_file(hp) == -1) 282 return (NULL); 283 } 284 285} 286 287/* 288 * This function prints the available 0-level help topics from all 289 * other help files by scanning the files. It assumes, that this is called 290 * only from the main help file. 291 */ 292static void 293help_get_0topics(struct help_file *hp) 294{ 295 struct help_pos save; 296 const char *line; 297 298 memset(&save, 0, sizeof(save)); 299 help_file_tell(hp, &save); 300 301 help_file_rewind(hp); 302 while ((line = help_next_line(hp)) != NULL) { 303 if (line[0] == '^' && line[1] == '^') 304 printf("%s", line + 2); 305 } 306 help_file_seek(hp, &save); 307} 308 309/*
|
72 * Function to print help. The help argument is in argv[0] here. 73 */ 74static void 75help_func(int argc, char *argv[]) 76{
| 310 * Function to print help. The help argument is in argv[0] here. 311 */ 312static void 313help_func(int argc, char *argv[]) 314{
|
77 FILE *hp; 78 const char *start, *end; 79 char *fname; 80 off_t match, last_match; 81 char line[LINE_MAX];
| 315 struct help_file hfile; 316 struct help_pos match, last_match; 317 const char *line;
|
82 char key[100];
| 318 char key[100];
|
83 int level, i;
| 319 int level; 320 int i, has_sub_topics;
|
84
| 321
|
85 /* 86 * Find the help file 87 */ 88 hp = NULL; 89 for (start = PATH_HELP; *start != '\0'; start = end + 1) { 90 for (end = start; *end != ':' && *end != '\0'; end++) 91 ; 92 if (start == end) { 93 if (asprintf(&fname, "%s", FILE_HELP) == -1) 94 err(1, NULL); 95 } else { 96 if (asprintf(&fname, "%.*s/%s", (int)(end - start), 97 start, FILE_HELP) == -1) 98 err(1, NULL); 99 } 100 if ((hp = fopen(fname, "r")) != NULL) 101 break; 102 free(fname); 103 } 104 if (hp == NULL) 105 errx(1, "help file not found");
| 322 memset(&hfile, 0, sizeof(hfile)); 323 memset(&match, 0, sizeof(match)); 324 memset(&last_match, 0, sizeof(last_match));
|
106 107 if (argc == 0) {
| 325 326 if (argc == 0) {
|
| 327 /* only 'help' - show intro */
|
108 if ((argv[0] = strdup("intro")) == NULL) 109 err(1, NULL); 110 argc = 1; 111 } 112 113 optind = 0;
| 328 if ((argv[0] = strdup("intro")) == NULL) 329 err(1, NULL); 330 argc = 1; 331 } 332 333 optind = 0;
|
114 match = -1; 115 last_match = -1;
| 334 match.pos = -1; 335 last_match.pos = -1;
|
116 for (;;) { 117 /* read next line */
| 336 for (;;) { 337 /* read next line */
|
118 if (fgets(line, sizeof(line), hp) == NULL) { 119 if (ferror(hp)) 120 err(1, fname);
| 338 if ((line = help_next_line(&hfile)) == NULL) {
|
121 /* EOF */
| 339 /* EOF */
|
122 clearerr(hp);
| |
123 level = 999; 124 goto stop; 125 }
| 340 level = 999; 341 goto stop; 342 }
|
126 if (line[0] != '^')
| 343 if (line[0] != '^' || line[1] == '^')
|
127 continue; 128 129 if (sscanf(line + 1, "%d%99s", &level, key) != 2) 130 errx(1, "error in help file '%s'", line); 131 132 if (level < optind) { 133 stop: 134 /* next higher level entry - stop this level */
| 344 continue; 345 346 if (sscanf(line + 1, "%d%99s", &level, key) != 2) 347 errx(1, "error in help file '%s'", line); 348 349 if (level < optind) { 350 stop: 351 /* next higher level entry - stop this level */
|
135 if (match == -1) {
| 352 if (match.pos == -1) {
|
136 /* not found */ 137 goto not_found; 138 } 139 /* go back to the match */
| 353 /* not found */ 354 goto not_found; 355 } 356 /* go back to the match */
|
140 if (fseeko(hp, match, SEEK_SET) == -1) 141 err(1, fname);
| 357 help_file_seek(&hfile, &match);
|
142 last_match = match;
| 358 last_match = match;
|
143 match = -1;
| 359 memset(&match, 0, sizeof(match)); 360 match.pos = -1;
|
144 145 /* go to next key */ 146 if (++optind >= argc) 147 break; 148 } 149 if (level == optind) { 150 if (substr(argv[optind], key)) {
| 361 362 /* go to next key */ 363 if (++optind >= argc) 364 break; 365 } 366 if (level == optind) { 367 if (substr(argv[optind], key)) {
|
151 if (match != -1) {
| 368 if (match.pos != -1) {
|
152 printf("Ambiguous topic."); 153 goto list_topics; 154 }
| 369 printf("Ambiguous topic."); 370 goto list_topics; 371 }
|
155 if ((match = ftello(hp)) == -1) 156 err(1, fname);
| 372 help_file_tell(&hfile, &match);
|
157 } 158 } 159 }
| 373 } 374 } 375 }
|
160 if (last_match == -1) { 161 if (fseek(hp, 0L, SEEK_SET) == -1) 162 err(1, fname); 163 } else { 164 if (fseeko(hp, last_match, SEEK_SET) == -1) 165 err(1, fname); 166 }
| |
167
| 376
|
| 377 /* before breaking above we have seeked back to the matching point */
|
168 for (;;) {
| 378 for (;;) {
|
169 if (fgets(line, sizeof(line), hp) == NULL) { 170 if (ferror(hp)) 171 err(1, fname);
| 379 if ((line = help_next_line(&hfile)) == NULL)
|
172 break;
| 380 break;
|
173 }
| 381
|
174 if (line[0] == '#') 175 continue;
| 382 if (line[0] == '#') 383 continue;
|
176 if (line[0] == '^')
| 384 if (line[0] == '^') { 385 if (line[1] == '^') 386 continue;
|
177 break;
| 387 break;
|
| 388 } 389 if (strncmp(line, "$MAIN", 5) == 0) { 390 help_get_0topics(&hfile); 391 continue; 392 }
|
178 printf("%s", line); 179 } 180 181 exit(0); 182 183 not_found: 184 printf("Topic not found."); 185 186 list_topics:
| 393 printf("%s", line); 394 } 395 396 exit(0); 397 398 not_found: 399 printf("Topic not found."); 400 401 list_topics:
|
187 printf(" Use one of:\natmconfig");
| 402 printf(" Use one of:\natmconfig help");
|
188 for (i = 0; i < optind; i++) 189 printf(" %s", argv[i]);
| 403 for (i = 0; i < optind; i++) 404 printf(" %s", argv[i]);
|
| 405
|
190 printf(" [");
| 406 printf(" [");
|
| 407
|
191 /* list all the keys at this level */
| 408 /* list all the keys at this level */
|
192 if (last_match == -1) { 193 if (fseek(hp, 0L, SEEK_SET) == -1) 194 err(1, fname); 195 } else { 196 if (fseeko(hp, last_match, SEEK_SET) == -1) 197 err(1, fname); 198 }
| 409 if (last_match.pos == -1) 410 /* go back to start of help */ 411 help_file_rewind(&hfile); 412 else 413 help_file_seek(&hfile, &last_match);
|
199
| 414
|
200 for (;;) { 201 /* read next line */ 202 if (fgets(line, sizeof(line), hp) == NULL) { 203 if (ferror(hp)) 204 err(1, fname); 205 break; 206 } 207 if (line[0] == '#' || line[0] != '^')
| 415 has_sub_topics = 0; 416 while ((line = help_next_line(&hfile)) != NULL) { 417 if (line[0] == '#' || line[0] != '^' || line[1] == '^')
|
208 continue; 209 210 if (sscanf(line + 1, "%d%99s", &level, key) != 2) 211 errx(1, "error in help file '%s'", line); 212 213 if (level < optind) 214 break;
| 418 continue; 419 420 if (sscanf(line + 1, "%d%99s", &level, key) != 2) 421 errx(1, "error in help file '%s'", line); 422 423 if (level < optind) 424 break;
|
215 if (level == optind)
| 425 if (level == optind) { 426 has_sub_topics = 1;
|
216 printf(" %s", key);
| 427 printf(" %s", key);
|
| 428 }
|
217 }
| 429 }
|
218 printf(" ]\n");
| 430 printf(" ]."); 431 if (!has_sub_topics) 432 printf(" No sub-topics found."); 433 printf("\n");
|
219 exit(1); 220} 221 222int 223main(int argc, char *argv[]) 224{ 225 int opt, i; 226 const struct cmdtab *match, *cc, *tab; 227 228 while ((opt = getopt(argc, argv, "htv")) != -1) 229 switch (opt) { 230 231 case 'h': 232 help_func(0, argv); 233 234 case 'v': 235 verbose++; 236 break; 237 238 case 't': 239 notitle = 1; 240 break; 241 } 242 243 if (argv[optind] == NULL) 244 help_func(0, argv); 245 246 argc -= optind; 247 argv += optind; 248 249 cc = main_tab; 250 i = 0; 251 for (;;) { 252 /* 253 * Scan the table for a match 254 */ 255 tab = cc; 256 match = NULL; 257 while (cc->string != NULL) { 258 if (substr(argv[i], cc->string)) { 259 if (match != NULL) { 260 printf("Ambiguous option '%s'", 261 argv[i]); 262 cc = tab; 263 goto subopts; 264 } 265 match = cc; 266 } 267 cc++; 268 } 269 if ((cc = match) == NULL) { 270 printf("Unknown option '%s'", argv[i]); 271 cc = tab; 272 goto subopts; 273 } 274 275 /* 276 * Have a match. If there is no subtable, there must 277 * be either a handler or the command is only a help entry. 278 */ 279 if (cc->sub == NULL) { 280 if (cc->func != NULL) 281 break; 282 printf("Unknown option '%s'", argv[i]); 283 cc = tab; 284 goto subopts; 285 } 286 287 /* 288 * Look at the next argument. If it doesn't exist or it 289 * looks like a switch, terminate the scan here. 290 */ 291 if (argv[i + 1] == NULL || argv[i + 1][0] == '-') { 292 if (cc->func != NULL) 293 break; 294 printf("Need sub-option for '%s'", argv[i]); 295 cc = cc->sub; 296 goto subopts; 297 } 298 299 cc = cc->sub; 300 i++; 301 } 302 303 argc -= i + 1; 304 argv += i + 1; 305 306 (*cc->func)(argc, argv); 307 308 return (0); 309 310 subopts: 311 printf(". Select one of:\n"); 312 while (cc->string != NULL) { 313 if (cc->func != NULL || cc->sub != NULL) 314 printf("%s ", cc->string); 315 cc++; 316 } 317 printf("\n"); 318 319 return (1); 320} 321 322void 323verb(const char *fmt, ...) 324{ 325 va_list ap; 326 327 if (verbose) { 328 va_start(ap, fmt); 329 vfprintf(stderr, fmt, ap); 330 fprintf(stderr, "\n"); 331 va_end(ap); 332 } 333} 334 335void 336heading(const char *fmt, ...) 337{ 338 va_list ap; 339 340 if (need_heading) { 341 need_heading = 0; 342 if (!notitle) { 343 va_start(ap, fmt); 344 fprintf(stdout, fmt, ap); 345 va_end(ap); 346 } 347 } 348} 349 350void 351heading_init(void) 352{ 353 need_heading = 1; 354} 355 356/* 357 * stringify an enumerated value 358 */ 359const char * 360penum(int32_t value, const struct penum *strtab, char *buf) 361{ 362 while (strtab->str != NULL) { 363 if (strtab->value == value) { 364 strcpy(buf, strtab->str); 365 return (buf); 366 } 367 strtab++; 368 } 369 warnx("illegal value for enumerated variable '%d'", value); 370 strcpy(buf, "?"); 371 return (buf); 372} 373 374/* 375 * Parse command line options 376 */ 377int 378parse_options(int *pargc, char ***pargv, const struct option *opts) 379{ 380 const struct option *o, *m; 381 char *arg; 382 u_long ularg, ularg1; 383 long larg; 384 char *end; 385 386 if (*pargc == 0) 387 return (-1); 388 arg = (*pargv)[0]; 389 if (arg[0] != '-' || arg[1] == '\0') 390 return (-1); 391 if (arg[1] == '-' && arg[2] == '\0') { 392 (*pargv)++; 393 (*pargc)--; 394 return (-1); 395 } 396 397 m = NULL; 398 for (o = opts; o->optstr != NULL; o++) { 399 if (strlen(arg + 1) <= strlen(o->optstr) && 400 strncmp(arg + 1, o->optstr, strlen(arg + 1)) == 0) { 401 if (m != NULL) 402 errx(1, "ambiguous option '%s'", arg); 403 m = o; 404 } 405 } 406 if (m == NULL) 407 errx(1, "unknown option '%s'", arg); 408 409 (*pargv)++; 410 (*pargc)--; 411 412 if (m->opttype == OPT_NONE) 413 return (m - opts); 414 415 if (m->opttype == OPT_SIMPLE) { 416 *(int *)m->optarg = 1; 417 return (m - opts); 418 } 419 420 if (*pargc == 0) 421 errx(1, "option requires argument '%s'", arg); 422 optarg = *(*pargv)++; 423 (*pargc)--; 424 425 switch (m->opttype) { 426 427 case OPT_UINT: 428 ularg = strtoul(optarg, &end, 0); 429 if (*end != '\0') 430 errx(1, "bad unsigned integer argument for '%s'", arg); 431 if (ularg > UINT_MAX) 432 errx(1, "argument to large for option '%s'", arg); 433 *(u_int *)m->optarg = (u_int)ularg; 434 break; 435 436 case OPT_INT: 437 larg = strtol(optarg, &end, 0); 438 if (*end != '\0') 439 errx(1, "bad integer argument for '%s'", arg); 440 if (larg > INT_MAX || larg < INT_MIN) 441 errx(1, "argument out of range for option '%s'", arg); 442 *(int *)m->optarg = (int)larg; 443 break; 444 445 case OPT_UINT32: 446 ularg = strtoul(optarg, &end, 0); 447 if (*end != '\0') 448 errx(1, "bad unsigned integer argument for '%s'", arg); 449 if (ularg > UINT32_MAX) 450 errx(1, "argument to large for option '%s'", arg); 451 *(uint32_t *)m->optarg = (uint32_t)ularg; 452 break; 453 454 case OPT_INT32: 455 larg = strtol(optarg, &end, 0); 456 if (*end != '\0') 457 errx(1, "bad integer argument for '%s'", arg); 458 if (larg > INT32_MAX || larg < INT32_MIN) 459 errx(1, "argument out of range for option '%s'", arg); 460 *(int32_t *)m->optarg = (int32_t)larg; 461 break; 462 463 case OPT_UINT64: 464 *(uint64_t *)m->optarg = strtoull(optarg, &end, 0); 465 if (*end != '\0') 466 errx(1, "bad unsigned integer argument for '%s'", arg); 467 break; 468 469 case OPT_INT64: 470 *(int64_t *)m->optarg = strtoll(optarg, &end, 0); 471 if (*end != '\0') 472 errx(1, "bad integer argument for '%s'", arg); 473 break; 474 475 case OPT_FLAG: 476 if (strcasecmp(optarg, "enable") == 0 || 477 strcasecmp(optarg, "yes") == 0 || 478 strcasecmp(optarg, "true") == 0 || 479 strcasecmp(optarg, "on") == 0 || 480 strcmp(optarg, "1") == 0) 481 *(int *)m->optarg = 1; 482 else if (strcasecmp(optarg, "disable") == 0 || 483 strcasecmp(optarg, "no") == 0 || 484 strcasecmp(optarg, "false") == 0 || 485 strcasecmp(optarg, "off") == 0 || 486 strcmp(optarg, "0") == 0) 487 *(int *)m->optarg = 0; 488 else 489 errx(1, "bad boolean argument to '%s'", arg); 490 break; 491 492 case OPT_VCI: 493 ularg = strtoul(optarg, &end, 0); 494 if (*end == '.') { 495 ularg1 = strtoul(end + 1, &end, 0); 496 } else { 497 ularg1 = ularg; 498 ularg = 0; 499 } 500 if (*end != '\0') 501 errx(1, "bad VCI value for option '%s'", arg); 502 if (ularg > 0xff) 503 errx(1, "VPI value too large for option '%s'", arg); 504 if (ularg1 > 0xffff) 505 errx(1, "VCI value too large for option '%s'", arg); 506 ((u_int *)m->optarg)[0] = ularg; 507 ((u_int *)m->optarg)[1] = ularg1; 508 break; 509 510 case OPT_STRING: 511 if (m->optarg != NULL) 512 *(const char **)m->optarg = optarg; 513 break; 514 515 default: 516 errx(1, "(internal) bad option type %u for '%s'", 517 m->opttype, arg); 518 } 519 return (m - opts); 520}
| 434 exit(1); 435} 436 437int 438main(int argc, char *argv[]) 439{ 440 int opt, i; 441 const struct cmdtab *match, *cc, *tab; 442 443 while ((opt = getopt(argc, argv, "htv")) != -1) 444 switch (opt) { 445 446 case 'h': 447 help_func(0, argv); 448 449 case 'v': 450 verbose++; 451 break; 452 453 case 't': 454 notitle = 1; 455 break; 456 } 457 458 if (argv[optind] == NULL) 459 help_func(0, argv); 460 461 argc -= optind; 462 argv += optind; 463 464 cc = main_tab; 465 i = 0; 466 for (;;) { 467 /* 468 * Scan the table for a match 469 */ 470 tab = cc; 471 match = NULL; 472 while (cc->string != NULL) { 473 if (substr(argv[i], cc->string)) { 474 if (match != NULL) { 475 printf("Ambiguous option '%s'", 476 argv[i]); 477 cc = tab; 478 goto subopts; 479 } 480 match = cc; 481 } 482 cc++; 483 } 484 if ((cc = match) == NULL) { 485 printf("Unknown option '%s'", argv[i]); 486 cc = tab; 487 goto subopts; 488 } 489 490 /* 491 * Have a match. If there is no subtable, there must 492 * be either a handler or the command is only a help entry. 493 */ 494 if (cc->sub == NULL) { 495 if (cc->func != NULL) 496 break; 497 printf("Unknown option '%s'", argv[i]); 498 cc = tab; 499 goto subopts; 500 } 501 502 /* 503 * Look at the next argument. If it doesn't exist or it 504 * looks like a switch, terminate the scan here. 505 */ 506 if (argv[i + 1] == NULL || argv[i + 1][0] == '-') { 507 if (cc->func != NULL) 508 break; 509 printf("Need sub-option for '%s'", argv[i]); 510 cc = cc->sub; 511 goto subopts; 512 } 513 514 cc = cc->sub; 515 i++; 516 } 517 518 argc -= i + 1; 519 argv += i + 1; 520 521 (*cc->func)(argc, argv); 522 523 return (0); 524 525 subopts: 526 printf(". Select one of:\n"); 527 while (cc->string != NULL) { 528 if (cc->func != NULL || cc->sub != NULL) 529 printf("%s ", cc->string); 530 cc++; 531 } 532 printf("\n"); 533 534 return (1); 535} 536 537void 538verb(const char *fmt, ...) 539{ 540 va_list ap; 541 542 if (verbose) { 543 va_start(ap, fmt); 544 vfprintf(stderr, fmt, ap); 545 fprintf(stderr, "\n"); 546 va_end(ap); 547 } 548} 549 550void 551heading(const char *fmt, ...) 552{ 553 va_list ap; 554 555 if (need_heading) { 556 need_heading = 0; 557 if (!notitle) { 558 va_start(ap, fmt); 559 fprintf(stdout, fmt, ap); 560 va_end(ap); 561 } 562 } 563} 564 565void 566heading_init(void) 567{ 568 need_heading = 1; 569} 570 571/* 572 * stringify an enumerated value 573 */ 574const char * 575penum(int32_t value, const struct penum *strtab, char *buf) 576{ 577 while (strtab->str != NULL) { 578 if (strtab->value == value) { 579 strcpy(buf, strtab->str); 580 return (buf); 581 } 582 strtab++; 583 } 584 warnx("illegal value for enumerated variable '%d'", value); 585 strcpy(buf, "?"); 586 return (buf); 587} 588 589/* 590 * Parse command line options 591 */ 592int 593parse_options(int *pargc, char ***pargv, const struct option *opts) 594{ 595 const struct option *o, *m; 596 char *arg; 597 u_long ularg, ularg1; 598 long larg; 599 char *end; 600 601 if (*pargc == 0) 602 return (-1); 603 arg = (*pargv)[0]; 604 if (arg[0] != '-' || arg[1] == '\0') 605 return (-1); 606 if (arg[1] == '-' && arg[2] == '\0') { 607 (*pargv)++; 608 (*pargc)--; 609 return (-1); 610 } 611 612 m = NULL; 613 for (o = opts; o->optstr != NULL; o++) { 614 if (strlen(arg + 1) <= strlen(o->optstr) && 615 strncmp(arg + 1, o->optstr, strlen(arg + 1)) == 0) { 616 if (m != NULL) 617 errx(1, "ambiguous option '%s'", arg); 618 m = o; 619 } 620 } 621 if (m == NULL) 622 errx(1, "unknown option '%s'", arg); 623 624 (*pargv)++; 625 (*pargc)--; 626 627 if (m->opttype == OPT_NONE) 628 return (m - opts); 629 630 if (m->opttype == OPT_SIMPLE) { 631 *(int *)m->optarg = 1; 632 return (m - opts); 633 } 634 635 if (*pargc == 0) 636 errx(1, "option requires argument '%s'", arg); 637 optarg = *(*pargv)++; 638 (*pargc)--; 639 640 switch (m->opttype) { 641 642 case OPT_UINT: 643 ularg = strtoul(optarg, &end, 0); 644 if (*end != '\0') 645 errx(1, "bad unsigned integer argument for '%s'", arg); 646 if (ularg > UINT_MAX) 647 errx(1, "argument to large for option '%s'", arg); 648 *(u_int *)m->optarg = (u_int)ularg; 649 break; 650 651 case OPT_INT: 652 larg = strtol(optarg, &end, 0); 653 if (*end != '\0') 654 errx(1, "bad integer argument for '%s'", arg); 655 if (larg > INT_MAX || larg < INT_MIN) 656 errx(1, "argument out of range for option '%s'", arg); 657 *(int *)m->optarg = (int)larg; 658 break; 659 660 case OPT_UINT32: 661 ularg = strtoul(optarg, &end, 0); 662 if (*end != '\0') 663 errx(1, "bad unsigned integer argument for '%s'", arg); 664 if (ularg > UINT32_MAX) 665 errx(1, "argument to large for option '%s'", arg); 666 *(uint32_t *)m->optarg = (uint32_t)ularg; 667 break; 668 669 case OPT_INT32: 670 larg = strtol(optarg, &end, 0); 671 if (*end != '\0') 672 errx(1, "bad integer argument for '%s'", arg); 673 if (larg > INT32_MAX || larg < INT32_MIN) 674 errx(1, "argument out of range for option '%s'", arg); 675 *(int32_t *)m->optarg = (int32_t)larg; 676 break; 677 678 case OPT_UINT64: 679 *(uint64_t *)m->optarg = strtoull(optarg, &end, 0); 680 if (*end != '\0') 681 errx(1, "bad unsigned integer argument for '%s'", arg); 682 break; 683 684 case OPT_INT64: 685 *(int64_t *)m->optarg = strtoll(optarg, &end, 0); 686 if (*end != '\0') 687 errx(1, "bad integer argument for '%s'", arg); 688 break; 689 690 case OPT_FLAG: 691 if (strcasecmp(optarg, "enable") == 0 || 692 strcasecmp(optarg, "yes") == 0 || 693 strcasecmp(optarg, "true") == 0 || 694 strcasecmp(optarg, "on") == 0 || 695 strcmp(optarg, "1") == 0) 696 *(int *)m->optarg = 1; 697 else if (strcasecmp(optarg, "disable") == 0 || 698 strcasecmp(optarg, "no") == 0 || 699 strcasecmp(optarg, "false") == 0 || 700 strcasecmp(optarg, "off") == 0 || 701 strcmp(optarg, "0") == 0) 702 *(int *)m->optarg = 0; 703 else 704 errx(1, "bad boolean argument to '%s'", arg); 705 break; 706 707 case OPT_VCI: 708 ularg = strtoul(optarg, &end, 0); 709 if (*end == '.') { 710 ularg1 = strtoul(end + 1, &end, 0); 711 } else { 712 ularg1 = ularg; 713 ularg = 0; 714 } 715 if (*end != '\0') 716 errx(1, "bad VCI value for option '%s'", arg); 717 if (ularg > 0xff) 718 errx(1, "VPI value too large for option '%s'", arg); 719 if (ularg1 > 0xffff) 720 errx(1, "VCI value too large for option '%s'", arg); 721 ((u_int *)m->optarg)[0] = ularg; 722 ((u_int *)m->optarg)[1] = ularg1; 723 break; 724 725 case OPT_STRING: 726 if (m->optarg != NULL) 727 *(const char **)m->optarg = optarg; 728 break; 729 730 default: 731 errx(1, "(internal) bad option type %u for '%s'", 732 m->opttype, arg); 733 } 734 return (m - opts); 735}
|