Deleted Added
sdiff udiff text old ( 119172 ) new ( 132493 )
full compact
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 $");
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>
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/*
72 * Function to print help. The help argument is in argv[0] here.
73 */
74static void
75help_func(int argc, char *argv[])
76{
77 FILE *hp;
78 const char *start, *end;
79 char *fname;
80 off_t match, last_match;
81 char line[LINE_MAX];
82 char key[100];
83 int level, i;
84
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");
106
107 if (argc == 0) {
108 if ((argv[0] = strdup("intro")) == NULL)
109 err(1, NULL);
110 argc = 1;
111 }
112
113 optind = 0;
114 match = -1;
115 last_match = -1;
116 for (;;) {
117 /* read next line */
118 if (fgets(line, sizeof(line), hp) == NULL) {
119 if (ferror(hp))
120 err(1, fname);
121 /* EOF */
122 clearerr(hp);
123 level = 999;
124 goto stop;
125 }
126 if (line[0] != '^')
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 */
135 if (match == -1) {
136 /* not found */
137 goto not_found;
138 }
139 /* go back to the match */
140 if (fseeko(hp, match, SEEK_SET) == -1)
141 err(1, fname);
142 last_match = match;
143 match = -1;
144
145 /* go to next key */
146 if (++optind >= argc)
147 break;
148 }
149 if (level == optind) {
150 if (substr(argv[optind], key)) {
151 if (match != -1) {
152 printf("Ambiguous topic.");
153 goto list_topics;
154 }
155 if ((match = ftello(hp)) == -1)
156 err(1, fname);
157 }
158 }
159 }
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
168 for (;;) {
169 if (fgets(line, sizeof(line), hp) == NULL) {
170 if (ferror(hp))
171 err(1, fname);
172 break;
173 }
174 if (line[0] == '#')
175 continue;
176 if (line[0] == '^')
177 break;
178 printf("%s", line);
179 }
180
181 exit(0);
182
183 not_found:
184 printf("Topic not found.");
185
186 list_topics:
187 printf(" Use one of:\natmconfig");
188 for (i = 0; i < optind; i++)
189 printf(" %s", argv[i]);
190 printf(" [");
191 /* 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 }
199
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] != '^')
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;
215 if (level == optind)
216 printf(" %s", key);
217 }
218 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}