parser.c revision 1.27
1/*	$OpenBSD: parser.c,v 1.27 2015/01/22 17:42:09 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	{NOTOKEN,	"",		NONE,		NULL},
85	{KEYWORD,	"disable",	RDR_DISABLE,	t_rdr_id},
86	{KEYWORD,	"enable",	RDR_ENABLE,	t_rdr_id},
87	{ENDTOKEN,	"",		NONE,		NULL}
88};
89
90static const struct token t_table[] = {
91	{NOTOKEN,	"",		NONE,		NULL},
92	{KEYWORD,	"disable",	TABLE_DISABLE,	t_table_id},
93	{KEYWORD,	"enable",	TABLE_ENABLE,	t_table_id},
94	{ENDTOKEN,	"",		NONE,		NULL}
95};
96
97static const struct token t_host[] = {
98	{NOTOKEN,	"",		NONE,		NULL},
99	{KEYWORD,	"disable",	HOST_DISABLE,	t_host_id},
100	{KEYWORD,	"enable",	HOST_ENABLE,	t_host_id},
101	{ENDTOKEN,	"",		NONE,		NULL}
102};
103
104static const struct token t_rdr_id[] = {
105	{RDRID,		"",		NONE,		NULL},
106	{ENDTOKEN,	"",		NONE,		NULL}
107};
108
109static const struct token t_table_id[] = {
110	{TABLEID,	"",		NONE,		NULL},
111	{ENDTOKEN,	"",		NONE,		NULL}
112};
113
114static const struct token t_host_id[] = {
115	{HOSTID,	"",		NONE,		NULL},
116	{ENDTOKEN,	"",		NONE,		NULL}
117};
118
119static const struct token t_log[] = {
120	{KEYWORD,	"verbose",	LOG_VERBOSE,	NULL},
121	{KEYWORD,	"brief",	LOG_BRIEF,	NULL},
122	{ENDTOKEN,	"",		NONE,		NULL}
123};
124
125static const struct token t_load[] = {
126	{PATH,		"",		NONE,		NULL},
127	{ENDTOKEN,	"",		NONE,		NULL}
128};
129
130static const struct token *match_token(const char *, const struct token *,
131    struct parse_result *);
132static void show_valid_args(const struct token *);
133
134struct parse_result *
135parse(int argc, char *argv[])
136{
137	static struct parse_result	res;
138	const struct token	*table = t_main;
139	const struct token	*match;
140
141	bzero(&res, sizeof(res));
142
143	while (argc >= 0) {
144		if ((match = match_token(argv[0], table, &res)) == NULL) {
145			fprintf(stderr, "valid commands/args:\n");
146			show_valid_args(table);
147			return (NULL);
148		}
149
150		argc--;
151		argv++;
152
153		if (match->type == NOTOKEN || match->next == NULL)
154			break;
155
156		table = match->next;
157	}
158
159	if (argc > 0) {
160		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
161		return (NULL);
162	}
163
164	return (&res);
165}
166
167static const struct token *
168match_token(const char *word, const struct token *table,
169    struct parse_result *res)
170{
171	u_int			 i, match;
172	const struct token	*t = NULL;
173	const char		*errstr;
174
175	match = 0;
176
177	for (i = 0; table[i].type != ENDTOKEN; i++) {
178		switch (table[i].type) {
179		case NOTOKEN:
180			if (word == NULL || strlen(word) == 0) {
181				match++;
182				t = &table[i];
183			}
184			break;
185		case KEYWORD:
186			if (word != NULL && strncmp(word, table[i].keyword,
187			    strlen(word)) == 0) {
188				match++;
189				t = &table[i];
190				if (t->value)
191					res->action = t->value;
192			}
193			break;
194		case HOSTID:
195			if (word == NULL)
196				break;
197			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
198			if (errstr) {
199				strlcpy(res->id.name, word,
200				    sizeof(res->id.name));
201				res->id.id = EMPTY_ID;
202			}
203			t = &table[i];
204			match++;
205			break;
206		case TABLEID:
207			if (word == NULL)
208				break;
209			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
210			if (errstr) {
211				strlcpy(res->id.name, word,
212				    sizeof(res->id.name));
213				res->id.id = EMPTY_ID;
214			}
215			t = &table[i];
216			match++;
217			break;
218		case RDRID:
219			if (word == NULL)
220				break;
221			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
222			if (errstr) {
223				strlcpy(res->id.name, word,
224				    sizeof(res->id.name));
225				res->id.id = EMPTY_ID;
226			}
227			t = &table[i];
228			match++;
229			break;
230		case PATH:
231			if (!match && word != NULL && strlen(word) > 0) {
232				res->path = strdup(word);
233				match++;
234				t = &table[i];
235			}
236			break;
237		case ENDTOKEN:
238			break;
239		}
240	}
241
242	if (match != 1) {
243		if (word == NULL)
244			fprintf(stderr, "missing argument:\n");
245		else if (match > 1)
246			fprintf(stderr, "ambiguous argument: %s\n", word);
247		else if (match < 1)
248			fprintf(stderr, "unknown argument: %s\n", word);
249		return (NULL);
250	}
251
252	return (t);
253}
254
255static void
256show_valid_args(const struct token *table)
257{
258	int	i;
259
260	for (i = 0; table[i].type != ENDTOKEN; i++) {
261		switch (table[i].type) {
262		case NOTOKEN:
263			fprintf(stderr, "  <cr>\n");
264			break;
265		case KEYWORD:
266			fprintf(stderr, "  %s\n", table[i].keyword);
267			break;
268		case RDRID:
269			fprintf(stderr, "  <redirectid>\n");
270			break;
271		case TABLEID:
272			fprintf(stderr, "  <tableid>\n");
273			break;
274		case HOSTID:
275			fprintf(stderr, "  <hostid>\n");
276			break;
277		case PATH:
278			fprintf(stderr, "  <path>\n");
279			break;
280		case ENDTOKEN:
281			break;
282		}
283	}
284}
285