xref: /openbsd-src/usr.sbin/unwindctl/parser.c (revision c071f09071f839d58d840d707112a4e1152c6f24)
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