1/*	$OpenBSD: parser.c,v 1.28 2018/05/11 20:33:54 reyk Exp $	*/
2
3/*
4 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/types.h>
22
23#include <limits.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "relayd.h"
29#include "parser.h"
30
31enum token_type {
32	NOTOKEN,
33	ENDTOKEN,
34	HOSTID,
35	TABLEID,
36	RDRID,
37	KEYWORD,
38	PATH
39};
40
41struct token {
42	enum token_type		 type;
43	const char		*keyword;
44	int			 value;
45	const struct token	*next;
46};
47
48static const struct token t_main[];
49static const struct token t_show[];
50static const struct token t_rdr[];
51static const struct token t_table[];
52static const struct token t_host[];
53static const struct token t_rdr_id[];
54static const struct token t_table_id[];
55static const struct token t_host_id[];
56static const struct token t_log[];
57static const struct token t_load[];
58
59static const struct token t_main[] = {
60	{KEYWORD,	"monitor",	MONITOR,	NULL},
61	{KEYWORD,	"show",		NONE,		t_show},
62	{KEYWORD,	"load",		LOAD,		t_load},
63	{KEYWORD,	"poll",		POLL,		NULL},
64	{KEYWORD,	"reload",	RELOAD,		NULL},
65	{KEYWORD,	"stop",		SHUTDOWN,	NULL},
66	{KEYWORD,	"redirect",	NONE,		t_rdr},
67	{KEYWORD,	"table",	NONE,		t_table},
68	{KEYWORD,	"host",		NONE,		t_host},
69	{KEYWORD,	"log",		NONE,		t_log},
70	{ENDTOKEN,	"",		NONE,		NULL}
71};
72
73static const struct token t_show[] = {
74	{KEYWORD,	"summary",	SHOW_SUM,	NULL},
75	{KEYWORD,	"hosts",	SHOW_HOSTS,	NULL},
76	{KEYWORD,	"redirects",	SHOW_RDRS,	NULL},
77	{KEYWORD,	"relays",	SHOW_RELAYS,	NULL},
78	{KEYWORD,	"routers",	SHOW_ROUTERS,	NULL},
79	{KEYWORD,	"sessions",	SHOW_SESSIONS,	NULL},
80	{ENDTOKEN,	"",		NONE,		NULL}
81};
82
83static const struct token t_rdr[] = {
84	{KEYWORD,	"disable",	RDR_DISABLE,	t_rdr_id},
85	{KEYWORD,	"enable",	RDR_ENABLE,	t_rdr_id},
86	{ENDTOKEN,	"",		NONE,		NULL}
87};
88
89static const struct token t_table[] = {
90	{KEYWORD,	"disable",	TABLE_DISABLE,	t_table_id},
91	{KEYWORD,	"enable",	TABLE_ENABLE,	t_table_id},
92	{ENDTOKEN,	"",		NONE,		NULL}
93};
94
95static const struct token t_host[] = {
96	{KEYWORD,	"disable",	HOST_DISABLE,	t_host_id},
97	{KEYWORD,	"enable",	HOST_ENABLE,	t_host_id},
98	{ENDTOKEN,	"",		NONE,		NULL}
99};
100
101static const struct token t_rdr_id[] = {
102	{RDRID,		"",		NONE,		NULL},
103	{ENDTOKEN,	"",		NONE,		NULL}
104};
105
106static const struct token t_table_id[] = {
107	{TABLEID,	"",		NONE,		NULL},
108	{ENDTOKEN,	"",		NONE,		NULL}
109};
110
111static const struct token t_host_id[] = {
112	{HOSTID,	"",		NONE,		NULL},
113	{ENDTOKEN,	"",		NONE,		NULL}
114};
115
116static const struct token t_log[] = {
117	{KEYWORD,	"verbose",	LOG_VERBOSE,	NULL},
118	{KEYWORD,	"brief",	LOG_BRIEF,	NULL},
119	{ENDTOKEN,	"",		NONE,		NULL}
120};
121
122static const struct token t_load[] = {
123	{PATH,		"",		NONE,		NULL},
124	{ENDTOKEN,	"",		NONE,		NULL}
125};
126
127static const struct token *match_token(const char *, const struct token *,
128    struct parse_result *);
129static void show_valid_args(const struct token *);
130
131struct parse_result *
132parse(int argc, char *argv[])
133{
134	static struct parse_result	res;
135	const struct token	*table = t_main;
136	const struct token	*match;
137
138	bzero(&res, sizeof(res));
139
140	while (argc >= 0) {
141		if ((match = match_token(argv[0], table, &res)) == NULL) {
142			fprintf(stderr, "valid commands/args:\n");
143			show_valid_args(table);
144			return (NULL);
145		}
146
147		argc--;
148		argv++;
149
150		if (match->type == NOTOKEN || match->next == NULL)
151			break;
152
153		table = match->next;
154	}
155
156	if (argc > 0) {
157		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
158		return (NULL);
159	}
160
161	return (&res);
162}
163
164static const struct token *
165match_token(const char *word, const struct token *table,
166    struct parse_result *res)
167{
168	u_int			 i, match;
169	const struct token	*t = NULL;
170	const char		*errstr;
171
172	match = 0;
173
174	for (i = 0; table[i].type != ENDTOKEN; i++) {
175		switch (table[i].type) {
176		case NOTOKEN:
177			if (word == NULL || strlen(word) == 0) {
178				match++;
179				t = &table[i];
180			}
181			break;
182		case KEYWORD:
183			if (word != NULL && strncmp(word, table[i].keyword,
184			    strlen(word)) == 0) {
185				match++;
186				t = &table[i];
187				if (t->value)
188					res->action = t->value;
189			}
190			break;
191		case HOSTID:
192			if (word == NULL)
193				break;
194			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
195			if (errstr) {
196				strlcpy(res->id.name, word,
197				    sizeof(res->id.name));
198				res->id.id = EMPTY_ID;
199			}
200			t = &table[i];
201			match++;
202			break;
203		case TABLEID:
204			if (word == NULL)
205				break;
206			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
207			if (errstr) {
208				strlcpy(res->id.name, word,
209				    sizeof(res->id.name));
210				res->id.id = EMPTY_ID;
211			}
212			t = &table[i];
213			match++;
214			break;
215		case RDRID:
216			if (word == NULL)
217				break;
218			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
219			if (errstr) {
220				strlcpy(res->id.name, word,
221				    sizeof(res->id.name));
222				res->id.id = EMPTY_ID;
223			}
224			t = &table[i];
225			match++;
226			break;
227		case PATH:
228			if (!match && word != NULL && strlen(word) > 0) {
229				res->path = strdup(word);
230				match++;
231				t = &table[i];
232			}
233			break;
234		case ENDTOKEN:
235			break;
236		}
237	}
238
239	if (match != 1) {
240		if (word == NULL)
241			fprintf(stderr, "missing argument:\n");
242		else if (match > 1)
243			fprintf(stderr, "ambiguous argument: %s\n", word);
244		else if (match < 1)
245			fprintf(stderr, "unknown argument: %s\n", word);
246		return (NULL);
247	}
248
249	return (t);
250}
251
252static void
253show_valid_args(const struct token *table)
254{
255	int	i;
256
257	for (i = 0; table[i].type != ENDTOKEN; i++) {
258		switch (table[i].type) {
259		case NOTOKEN:
260			fprintf(stderr, "  <cr>\n");
261			break;
262		case KEYWORD:
263			fprintf(stderr, "  %s\n", table[i].keyword);
264			break;
265		case RDRID:
266			fprintf(stderr, "  <redirectid>\n");
267			break;
268		case TABLEID:
269			fprintf(stderr, "  <tableid>\n");
270			break;
271		case HOSTID:
272			fprintf(stderr, "  <hostid>\n");
273			break;
274		case PATH:
275			fprintf(stderr, "  <path>\n");
276			break;
277		case ENDTOKEN:
278			break;
279		}
280	}
281}
282