1*c071f090Sflorian /* $OpenBSD: parser.c,v 1.11 2019/12/18 09:18:28 florian Exp $ */
25c077b0fSflorian
35c077b0fSflorian /*
45c077b0fSflorian * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
55c077b0fSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
65c077b0fSflorian *
75c077b0fSflorian * Permission to use, copy, modify, and distribute this software for any
85c077b0fSflorian * purpose with or without fee is hereby granted, provided that the above
95c077b0fSflorian * copyright notice and this permission notice appear in all copies.
105c077b0fSflorian *
115c077b0fSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
125c077b0fSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
135c077b0fSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
145c077b0fSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
155c077b0fSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
165c077b0fSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
175c077b0fSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
185c077b0fSflorian */
195c077b0fSflorian
205c077b0fSflorian #include <sys/types.h>
215c077b0fSflorian #include <sys/queue.h>
225c077b0fSflorian #include <sys/socket.h>
235c077b0fSflorian #include <netinet/in.h>
245c077b0fSflorian #include <arpa/inet.h>
255c077b0fSflorian #include <net/if.h>
265c077b0fSflorian #include <err.h>
275c077b0fSflorian #include <errno.h>
285c077b0fSflorian #include <event.h>
295c077b0fSflorian #include <imsg.h>
305c077b0fSflorian #include <limits.h>
315c077b0fSflorian #include <stdio.h>
325c077b0fSflorian #include <stdlib.h>
335c077b0fSflorian #include <string.h>
345c077b0fSflorian
355c077b0fSflorian #include "unwind.h"
365c077b0fSflorian #include "parser.h"
375c077b0fSflorian
385c077b0fSflorian enum token_type {
395c077b0fSflorian NOTOKEN,
405c077b0fSflorian ENDTOKEN,
415c077b0fSflorian KEYWORD
425c077b0fSflorian };
435c077b0fSflorian
445c077b0fSflorian struct token {
455c077b0fSflorian enum token_type type;
465c077b0fSflorian const char *keyword;
475c077b0fSflorian int value;
485c077b0fSflorian const struct token *next;
495c077b0fSflorian };
505c077b0fSflorian
515c077b0fSflorian static const struct token t_main[];
525c077b0fSflorian static const struct token t_log[];
5315fe126bSflorian static const struct token t_status[];
545c077b0fSflorian
555c077b0fSflorian static const struct token t_main[] = {
565c077b0fSflorian {KEYWORD, "reload", RELOAD, NULL},
5715fe126bSflorian {KEYWORD, "status", STATUS, t_status},
585c077b0fSflorian {KEYWORD, "log", NONE, t_log},
595c077b0fSflorian {ENDTOKEN, "", NONE, NULL}
605c077b0fSflorian };
615c077b0fSflorian
625c077b0fSflorian static const struct token t_log[] = {
635c077b0fSflorian {KEYWORD, "debug", LOG_DEBUG, NULL},
645c077b0fSflorian {KEYWORD, "verbose", LOG_VERBOSE, NULL},
655c077b0fSflorian {KEYWORD, "brief", LOG_BRIEF, NULL},
665c077b0fSflorian {ENDTOKEN, "", NONE, NULL}
675c077b0fSflorian };
685c077b0fSflorian
6915fe126bSflorian static const struct token t_status[] = {
7015fe126bSflorian {NOTOKEN, "", NONE, NULL},
7115fe126bSflorian {KEYWORD, "autoconf", AUTOCONF, NULL},
72*c071f090Sflorian {KEYWORD, "memory", MEM, NULL},
7315fe126bSflorian {ENDTOKEN, "", NONE, NULL}
7415fe126bSflorian };
7515fe126bSflorian
765c077b0fSflorian static const struct token *match_token(const char *, const struct token *,
775c077b0fSflorian struct parse_result *);
785c077b0fSflorian static void show_valid_args(const struct token *);
795c077b0fSflorian
805c077b0fSflorian struct parse_result *
parse(int argc,char * argv[])815c077b0fSflorian parse(int argc, char *argv[])
825c077b0fSflorian {
835c077b0fSflorian static struct parse_result res;
845c077b0fSflorian const struct token *table = t_main;
855c077b0fSflorian const struct token *match;
865c077b0fSflorian
875c077b0fSflorian memset(&res, 0, sizeof(res));
885c077b0fSflorian
895c077b0fSflorian while (argc >= 0) {
905c077b0fSflorian if ((match = match_token(argv[0], table, &res)) == NULL) {
915c077b0fSflorian fprintf(stderr, "valid commands/args:\n");
925c077b0fSflorian show_valid_args(table);
935c077b0fSflorian return (NULL);
945c077b0fSflorian }
955c077b0fSflorian
965c077b0fSflorian argc--;
975c077b0fSflorian argv++;
985c077b0fSflorian
995c077b0fSflorian if (match->type == NOTOKEN || match->next == NULL)
1005c077b0fSflorian break;
1015c077b0fSflorian
1025c077b0fSflorian table = match->next;
1035c077b0fSflorian }
1045c077b0fSflorian
1055c077b0fSflorian if (argc > 0) {
1065c077b0fSflorian fprintf(stderr, "superfluous argument: %s\n", argv[0]);
1075c077b0fSflorian return (NULL);
1085c077b0fSflorian }
1095c077b0fSflorian
1105c077b0fSflorian return (&res);
1115c077b0fSflorian }
1125c077b0fSflorian
1135c077b0fSflorian static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)1145c077b0fSflorian match_token(const char *word, const struct token *table,
1155c077b0fSflorian struct parse_result *res)
1165c077b0fSflorian {
1175c077b0fSflorian u_int i, match;
1185c077b0fSflorian const struct token *t = NULL;
1195c077b0fSflorian
1205c077b0fSflorian match = 0;
1215c077b0fSflorian
1225c077b0fSflorian for (i = 0; table[i].type != ENDTOKEN; i++) {
1235c077b0fSflorian switch (table[i].type) {
1245c077b0fSflorian case NOTOKEN:
1255c077b0fSflorian if (word == NULL || strlen(word) == 0) {
1265c077b0fSflorian match++;
1275c077b0fSflorian t = &table[i];
1285c077b0fSflorian }
1295c077b0fSflorian break;
1305c077b0fSflorian case KEYWORD:
1315c077b0fSflorian if (word != NULL && strncmp(word, table[i].keyword,
1325c077b0fSflorian strlen(word)) == 0) {
1335c077b0fSflorian match++;
1345c077b0fSflorian t = &table[i];
1355c077b0fSflorian if (t->value)
1365c077b0fSflorian res->action = t->value;
1375c077b0fSflorian }
1385c077b0fSflorian break;
1395c077b0fSflorian case ENDTOKEN:
1405c077b0fSflorian break;
1415c077b0fSflorian }
1425c077b0fSflorian }
1435c077b0fSflorian
1445c077b0fSflorian if (match != 1) {
1455c077b0fSflorian if (word == NULL)
1465c077b0fSflorian fprintf(stderr, "missing argument:\n");
1475c077b0fSflorian else if (match > 1)
1485c077b0fSflorian fprintf(stderr, "ambiguous argument: %s\n", word);
1495c077b0fSflorian else if (match < 1)
1505c077b0fSflorian fprintf(stderr, "unknown argument: %s\n", word);
1515c077b0fSflorian return (NULL);
1525c077b0fSflorian }
1535c077b0fSflorian
1545c077b0fSflorian return (t);
1555c077b0fSflorian }
1565c077b0fSflorian
1575c077b0fSflorian static void
show_valid_args(const struct token * table)1585c077b0fSflorian show_valid_args(const struct token *table)
1595c077b0fSflorian {
1605c077b0fSflorian int i;
1615c077b0fSflorian
1625c077b0fSflorian for (i = 0; table[i].type != ENDTOKEN; i++) {
1635c077b0fSflorian switch (table[i].type) {
1645c077b0fSflorian case NOTOKEN:
1655c077b0fSflorian fprintf(stderr, " <cr>\n");
1665c077b0fSflorian break;
1675c077b0fSflorian case KEYWORD:
1685c077b0fSflorian fprintf(stderr, " %s\n", table[i].keyword);
1695c077b0fSflorian break;
1705c077b0fSflorian case ENDTOKEN:
1715c077b0fSflorian break;
1725c077b0fSflorian }
1735c077b0fSflorian }
1745c077b0fSflorian }
175