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