summaryrefslogtreecommitdiffstats
path: root/sbin/atm/atmconfig/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/atm/atmconfig/main.c')
-rw-r--r--sbin/atm/atmconfig/main.c519
1 files changed, 519 insertions, 0 deletions
diff --git a/sbin/atm/atmconfig/main.c b/sbin/atm/atmconfig/main.c
new file mode 100644
index 0000000..5430fbb
--- /dev/null
+++ b/sbin/atm/atmconfig/main.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2001-2003
+ * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Hartmut Brandt <harti@freebsd.org>
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
+#include <inttypes.h>
+#include "atmconfig.h"
+#include "private.h"
+
+/* verbosity level */
+int verbose;
+
+/* notitle option */
+static int notitle;
+
+/* need to put heading before next output */
+static int need_heading;
+
+/*
+ * TOP LEVEL commands
+ */
+static void help_func(int argc, char *argv[]) __dead2;
+
+static const struct cmdtab main_tab[] = {
+ { "help", NULL, help_func },
+ { "options", NULL, NULL },
+ { "commands", NULL, NULL },
+ { "diag", diag_tab, NULL },
+ { "natm", natm_tab, NULL },
+ { NULL, NULL, NULL }
+};
+
+static int
+substr(const char *s1, const char *s2)
+{
+ return (strlen(s1) <= strlen(s2) && strncmp(s1, s2, strlen(s1)) == 0);
+}
+
+/*
+ * Function to print help. The help argument is in argv[0] here.
+ */
+static void
+help_func(int argc, char *argv[])
+{
+ FILE *hp;
+ const char *start, *end;
+ char *fname;
+ off_t match, last_match;
+ char line[LINE_MAX];
+ char key[100];
+ int level, i;
+
+ /*
+ * Find the help file
+ */
+ hp = NULL;
+ for (start = PATH_HELP; *start != '\0'; start = end + 1) {
+ for (end = start; *end != ':' && *end != '\0'; end++)
+ ;
+ if (start == end) {
+ if (asprintf(&fname, "%s", FILE_HELP) == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&fname, "%.*s/%s", (int)(end - start),
+ start, FILE_HELP) == -1)
+ err(1, NULL);
+ }
+ if ((hp = fopen(fname, "r")) != NULL)
+ break;
+ free(fname);
+ }
+ if (hp == NULL)
+ errx(1, "help file not found");
+
+ if (argc == 0) {
+ argv[0] = __DECONST(char *, "intro");
+ argc = 1;
+ }
+
+ optind = 0;
+ match = -1;
+ last_match = -1;
+ for (;;) {
+ /* read next line */
+ if (fgets(line, sizeof(line), hp) == NULL) {
+ if (ferror(hp))
+ err(1, fname);
+ /* EOF */
+ clearerr(hp);
+ level = 999;
+ goto stop;
+ }
+ if (line[0] != '^')
+ continue;
+
+ if (sscanf(line + 1, "%d%99s", &level, key) != 2)
+ errx(1, "error in help file '%s'", line);
+
+ if (level < optind) {
+ stop:
+ /* next higher level entry - stop this level */
+ if (match == -1) {
+ /* not found */
+ goto not_found;
+ }
+ /* go back to the match */
+ if (fseeko(hp, match, SEEK_SET) == -1)
+ err(1, fname);
+ last_match = match;
+ match = -1;
+
+ /* go to next key */
+ if (++optind >= argc)
+ break;
+ }
+ if (level == optind) {
+ if (substr(argv[optind], key)) {
+ if (match != -1) {
+ printf("Ambiguous topic.");
+ goto list_topics;
+ }
+ if ((match = ftello(hp)) == -1)
+ err(1, fname);
+ }
+ }
+ }
+ if (last_match == -1) {
+ if (fseek(hp, 0L, SEEK_SET) == -1)
+ err(1, fname);
+ } else {
+ if (fseeko(hp, last_match, SEEK_SET) == -1)
+ err(1, fname);
+ }
+
+ for (;;) {
+ if (fgets(line, sizeof(line), hp) == NULL) {
+ if (ferror(hp))
+ err(1, fname);
+ break;
+ }
+ if (line[0] == '#')
+ continue;
+ if (line[0] == '^')
+ break;
+ printf("%s", line);
+ }
+
+ exit(0);
+
+ not_found:
+ printf("Topic not found.");
+
+ list_topics:
+ printf(" Use one of:\natmconfig");
+ for (i = 0; i < optind; i++)
+ printf(" %s", argv[i]);
+ printf(" [");
+ /* list all the keys at this level */
+ if (last_match == -1) {
+ if (fseek(hp, 0L, SEEK_SET) == -1)
+ err(1, fname);
+ } else {
+ if (fseeko(hp, last_match, SEEK_SET) == -1)
+ err(1, fname);
+ }
+
+ for (;;) {
+ /* read next line */
+ if (fgets(line, sizeof(line), hp) == NULL) {
+ if (ferror(hp))
+ err(1, fname);
+ break;
+ }
+ if (line[0] == '#' || line[0] != '^')
+ continue;
+
+ if (sscanf(line + 1, "%d%99s", &level, key) != 2)
+ errx(1, "error in help file '%s'", line);
+
+ if (level < optind)
+ break;
+ if (level == optind)
+ printf(" %s", key);
+ }
+ printf(" ]\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt, i;
+ const struct cmdtab *match, *cc, *tab;
+
+ while ((opt = getopt(argc, argv, "htv")) != -1)
+ switch (opt) {
+
+ case 'h':
+ help_func(0, argv);
+
+ case 'v':
+ verbose++;
+ break;
+
+ case 't':
+ notitle = 1;
+ break;
+ }
+
+ if (argv[optind] == NULL)
+ help_func(0, argv);
+
+ argc -= optind;
+ argv += optind;
+
+ cc = main_tab;
+ i = 0;
+ for (;;) {
+ /*
+ * Scan the table for a match
+ */
+ tab = cc;
+ match = NULL;
+ while (cc->string != NULL) {
+ if (substr(argv[i], cc->string)) {
+ if (match != NULL) {
+ printf("Ambiguous option '%s'",
+ argv[i]);
+ cc = tab;
+ goto subopts;
+ }
+ match = cc;
+ }
+ cc++;
+ }
+ if ((cc = match) == NULL) {
+ printf("Unknown option '%s'", argv[i]);
+ cc = tab;
+ goto subopts;
+ }
+
+ /*
+ * Have a match. If there is no subtable, there must
+ * be either a handler or the command is only a help entry.
+ */
+ if (cc->sub == NULL) {
+ if (cc->func != NULL)
+ break;
+ printf("Unknown option '%s'", argv[i]);
+ cc = tab;
+ goto subopts;
+ }
+
+ /*
+ * Look at the next argument. If it doesn't exist or it
+ * looks like a switch, terminate the scan here.
+ */
+ if (argv[i + 1] == NULL || argv[i + 1][0] == '-') {
+ if (cc->func != NULL)
+ break;
+ printf("Need sub-option for '%s'", argv[i]);
+ cc = cc->sub;
+ goto subopts;
+ }
+
+ cc = cc->sub;
+ i++;
+ }
+
+ argc -= i + 1;
+ argv += i + 1;
+
+ (*cc->func)(argc, argv);
+
+ return (0);
+
+ subopts:
+ printf(". Select one of:\n");
+ while (cc->string != NULL) {
+ if (cc->func != NULL || cc->sub != NULL)
+ printf("%s ", cc->string);
+ cc++;
+ }
+ printf("\n");
+
+ return (1);
+}
+
+void
+verb(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (verbose) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+}
+
+void
+heading(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (need_heading) {
+ need_heading = 0;
+ if (!notitle) {
+ va_start(ap, fmt);
+ fprintf(stdout, fmt, ap);
+ va_end(ap);
+ }
+ }
+}
+
+void
+heading_init(void)
+{
+ need_heading = 1;
+}
+
+/*
+ * stringify an enumerated value
+ */
+const char *
+penum(int32_t value, const struct penum *strtab, char *buf)
+{
+ while (strtab->str != NULL) {
+ if (strtab->value == value) {
+ strcpy(buf, strtab->str);
+ return (buf);
+ }
+ strtab++;
+ }
+ warnx("illegal value for enumerated variable '%d'", value);
+ strcpy(buf, "?");
+ return (buf);
+}
+
+/*
+ * Parse command line options
+ */
+int
+parse_options(int *pargc, char ***pargv, const struct option *opts)
+{
+ const struct option *o, *m;
+ char *arg;
+ u_long ularg, ularg1;
+ long larg;
+ char *end;
+
+ if (*pargc == 0)
+ return (-1);
+ arg = (*pargv)[0];
+ if (arg[0] != '-' || arg[1] == '\0')
+ return (-1);
+ if (arg[1] == '-' && arg[2] == '\0') {
+ (*pargv)++;
+ (*pargc)--;
+ return (-1);
+ }
+
+ m = NULL;
+ for (o = opts; o->optstr != NULL; o++) {
+ if (strlen(arg + 1) <= strlen(o->optstr) &&
+ strncmp(arg + 1, o->optstr, strlen(arg + 1)) == 0) {
+ if (m != NULL)
+ errx(1, "ambiguous option '%s'", arg);
+ m = o;
+ }
+ }
+ if (m == NULL)
+ errx(1, "unknown option '%s'", arg);
+
+ (*pargv)++;
+ (*pargc)--;
+
+ if (m->opttype == OPT_NONE)
+ return (m - opts);
+
+ if (m->opttype == OPT_SIMPLE) {
+ *(int *)m->optarg = 1;
+ return (m - opts);
+ }
+
+ if (*pargc == 0)
+ errx(1, "option requires argument '%s'", arg);
+ optarg = *(*pargv)++;
+ (*pargc)--;
+
+ switch (m->opttype) {
+
+ case OPT_UINT:
+ ularg = strtoul(optarg, &end, 0);
+ if (*end != '\0')
+ errx(1, "bad unsigned integer argument for '%s'", arg);
+ if (ularg > UINT_MAX)
+ errx(1, "argument to large for option '%s'", arg);
+ *(u_int *)m->optarg = (u_int)ularg;
+ break;
+
+ case OPT_INT:
+ larg = strtol(optarg, &end, 0);
+ if (*end != '\0')
+ errx(1, "bad integer argument for '%s'", arg);
+ if (larg > INT_MAX || larg < INT_MIN)
+ errx(1, "argument out of range for option '%s'", arg);
+ *(int *)m->optarg = (int)larg;
+ break;
+
+ case OPT_UINT32:
+ ularg = strtoul(optarg, &end, 0);
+ if (*end != '\0')
+ errx(1, "bad unsigned integer argument for '%s'", arg);
+ if (ularg > UINT32_MAX)
+ errx(1, "argument to large for option '%s'", arg);
+ *(uint32_t *)m->optarg = (uint32_t)ularg;
+ break;
+
+ case OPT_INT32:
+ larg = strtol(optarg, &end, 0);
+ if (*end != '\0')
+ errx(1, "bad integer argument for '%s'", arg);
+ if (larg > INT32_MAX || larg < INT32_MIN)
+ errx(1, "argument out of range for option '%s'", arg);
+ *(int32_t *)m->optarg = (int32_t)larg;
+ break;
+
+ case OPT_UINT64:
+ *(uint64_t *)m->optarg = strtoull(optarg, &end, 0);
+ if (*end != '\0')
+ errx(1, "bad unsigned integer argument for '%s'", arg);
+ break;
+
+ case OPT_INT64:
+ *(int64_t *)m->optarg = strtoll(optarg, &end, 0);
+ if (*end != '\0')
+ errx(1, "bad integer argument for '%s'", arg);
+ break;
+
+ case OPT_FLAG:
+ if (strcasecmp(optarg, "enable") == 0 ||
+ strcasecmp(optarg, "yes") == 0 ||
+ strcasecmp(optarg, "true") == 0 ||
+ strcasecmp(optarg, "on") == 0 ||
+ strcmp(optarg, "1") == 0)
+ *(int *)m->optarg = 1;
+ else if (strcasecmp(optarg, "disable") == 0 ||
+ strcasecmp(optarg, "no") == 0 ||
+ strcasecmp(optarg, "false") == 0 ||
+ strcasecmp(optarg, "off") == 0 ||
+ strcmp(optarg, "0") == 0)
+ *(int *)m->optarg = 0;
+ else
+ errx(1, "bad boolean argument to '%s'", arg);
+ break;
+
+ case OPT_VCI:
+ ularg = strtoul(optarg, &end, 0);
+ if (*end == '.') {
+ ularg1 = strtoul(end + 1, &end, 0);
+ } else {
+ ularg1 = ularg;
+ ularg = 0;
+ }
+ if (*end != '\0')
+ errx(1, "bad VCI value for option '%s'", arg);
+ if (ularg > 0xff)
+ errx(1, "VPI value too large for option '%s'", arg);
+ if (ularg1 > 0xffff)
+ errx(1, "VCI value too large for option '%s'", arg);
+ ((u_int *)m->optarg)[0] = ularg;
+ ((u_int *)m->optarg)[1] = ularg1;
+ break;
+
+ case OPT_STRING:
+ if (m->optarg != NULL)
+ *(const char **)m->optarg = optarg;
+ break;
+
+ default:
+ errx(1, "(internal) bad option type %u for '%s'",
+ m->opttype, arg);
+ }
+ return (m - opts);
+}
OpenPOWER on IntegriCloud