parser.c revision 1.26
1/*	$OpenBSD: parser.c,v 1.26 2015/01/22 15:23:50 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#include <sys/socket.h>
23#include <sys/queue.h>
24
25#include <net/if.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28
29#include <err.h>
30#include <errno.h>
31#include <limits.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <event.h>
36
37#include <openssl/ssl.h>
38
39#include "relayd.h"
40
41#include "parser.h"
42
43enum token_type {
44	NOTOKEN,
45	ENDTOKEN,
46	HOSTID,
47	TABLEID,
48	RDRID,
49	KEYWORD,
50	PATH
51};
52
53struct token {
54	enum token_type		 type;
55	const char		*keyword;
56	int			 value;
57	const struct token	*next;
58};
59
60static const struct token t_main[];
61static const struct token t_show[];
62static const struct token t_rdr[];
63static const struct token t_table[];
64static const struct token t_host[];
65static const struct token t_rdr_id[];
66static const struct token t_table_id[];
67static const struct token t_host_id[];
68static const struct token t_log[];
69static const struct token t_load[];
70
71static const struct token t_main[] = {
72	{KEYWORD,	"monitor",	MONITOR,	NULL},
73	{KEYWORD,	"show",		NONE,		t_show},
74	{KEYWORD,	"load",		LOAD,		t_load},
75	{KEYWORD,	"poll",		POLL,		NULL},
76	{KEYWORD,	"reload",	RELOAD,		NULL},
77	{KEYWORD,	"stop",		SHUTDOWN,	NULL},
78	{KEYWORD,	"redirect",	NONE,		t_rdr},
79	{KEYWORD,	"table",	NONE,		t_table},
80	{KEYWORD,	"host",		NONE,		t_host},
81	{KEYWORD,	"log",		NONE,		t_log},
82	{ENDTOKEN,	"",		NONE,		NULL}
83};
84
85static const struct token t_show[] = {
86	{KEYWORD,	"summary",	SHOW_SUM,	NULL},
87	{KEYWORD,	"hosts",	SHOW_HOSTS,	NULL},
88	{KEYWORD,	"redirects",	SHOW_RDRS,	NULL},
89	{KEYWORD,	"relays",	SHOW_RELAYS,	NULL},
90	{KEYWORD,	"routers",	SHOW_ROUTERS,	NULL},
91	{KEYWORD,	"sessions",	SHOW_SESSIONS,	NULL},
92	{ENDTOKEN,	"",		NONE,		NULL}
93};
94
95static const struct token t_rdr[] = {
96	{NOTOKEN,	"",		NONE,		NULL},
97	{KEYWORD,	"disable",	RDR_DISABLE,	t_rdr_id},
98	{KEYWORD,	"enable",	RDR_ENABLE,	t_rdr_id},
99	{ENDTOKEN,	"",		NONE,		NULL}
100};
101
102static const struct token t_table[] = {
103	{NOTOKEN,	"",		NONE,		NULL},
104	{KEYWORD,	"disable",	TABLE_DISABLE,	t_table_id},
105	{KEYWORD,	"enable",	TABLE_ENABLE,	t_table_id},
106	{ENDTOKEN,	"",		NONE,		NULL}
107};
108
109static const struct token t_host[] = {
110	{NOTOKEN,	"",		NONE,		NULL},
111	{KEYWORD,	"disable",	HOST_DISABLE,	t_host_id},
112	{KEYWORD,	"enable",	HOST_ENABLE,	t_host_id},
113	{ENDTOKEN,	"",		NONE,		NULL}
114};
115
116static const struct token t_rdr_id[] = {
117	{RDRID,		"",		NONE,		NULL},
118	{ENDTOKEN,	"",		NONE,		NULL}
119};
120
121static const struct token t_table_id[] = {
122	{TABLEID,	"",		NONE,		NULL},
123	{ENDTOKEN,	"",		NONE,		NULL}
124};
125
126static const struct token t_host_id[] = {
127	{HOSTID,	"",		NONE,		NULL},
128	{ENDTOKEN,	"",		NONE,		NULL}
129};
130
131static const struct token t_log[] = {
132	{KEYWORD,	"verbose",	LOG_VERBOSE,	NULL},
133	{KEYWORD,	"brief",	LOG_BRIEF,	NULL},
134	{ENDTOKEN,	"",		NONE,		NULL}
135};
136
137static const struct token t_load[] = {
138	{PATH,		"",		NONE,		NULL},
139	{ENDTOKEN,	"",		NONE,		NULL}
140};
141
142static const struct token *match_token(const char *, const struct token *,
143    struct parse_result *);
144static void show_valid_args(const struct token *);
145
146struct parse_result *
147parse(int argc, char *argv[])
148{
149	static struct parse_result	res;
150	const struct token	*table = t_main;
151	const struct token	*match;
152
153	bzero(&res, sizeof(res));
154
155	while (argc >= 0) {
156		if ((match = match_token(argv[0], table, &res)) == NULL) {
157			fprintf(stderr, "valid commands/args:\n");
158			show_valid_args(table);
159			return (NULL);
160		}
161
162		argc--;
163		argv++;
164
165		if (match->type == NOTOKEN || match->next == NULL)
166			break;
167
168		table = match->next;
169	}
170
171	if (argc > 0) {
172		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
173		return (NULL);
174	}
175
176	return (&res);
177}
178
179static const struct token *
180match_token(const char *word, const struct token *table,
181    struct parse_result *res)
182{
183	u_int			 i, match;
184	const struct token	*t = NULL;
185	const char		*errstr;
186
187	match = 0;
188
189	for (i = 0; table[i].type != ENDTOKEN; i++) {
190		switch (table[i].type) {
191		case NOTOKEN:
192			if (word == NULL || strlen(word) == 0) {
193				match++;
194				t = &table[i];
195			}
196			break;
197		case KEYWORD:
198			if (word != NULL && strncmp(word, table[i].keyword,
199			    strlen(word)) == 0) {
200				match++;
201				t = &table[i];
202				if (t->value)
203					res->action = t->value;
204			}
205			break;
206		case HOSTID:
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 TABLEID:
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 RDRID:
231			if (word == NULL)
232				break;
233			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
234			if (errstr) {
235				strlcpy(res->id.name, word,
236				    sizeof(res->id.name));
237				res->id.id = EMPTY_ID;
238			}
239			t = &table[i];
240			match++;
241			break;
242		case PATH:
243			if (!match && word != NULL && strlen(word) > 0) {
244				res->path = strdup(word);
245				match++;
246				t = &table[i];
247			}
248			break;
249		case ENDTOKEN:
250			break;
251		}
252	}
253
254	if (match != 1) {
255		if (word == NULL)
256			fprintf(stderr, "missing argument:\n");
257		else if (match > 1)
258			fprintf(stderr, "ambiguous argument: %s\n", word);
259		else if (match < 1)
260			fprintf(stderr, "unknown argument: %s\n", word);
261		return (NULL);
262	}
263
264	return (t);
265}
266
267static void
268show_valid_args(const struct token *table)
269{
270	int	i;
271
272	for (i = 0; table[i].type != ENDTOKEN; i++) {
273		switch (table[i].type) {
274		case NOTOKEN:
275			fprintf(stderr, "  <cr>\n");
276			break;
277		case KEYWORD:
278			fprintf(stderr, "  %s\n", table[i].keyword);
279			break;
280		case RDRID:
281			fprintf(stderr, "  <redirectid>\n");
282			break;
283		case TABLEID:
284			fprintf(stderr, "  <tableid>\n");
285			break;
286		case HOSTID:
287			fprintf(stderr, "  <hostid>\n");
288			break;
289		case PATH:
290			fprintf(stderr, "  <path>\n");
291			break;
292		case ENDTOKEN:
293			break;
294		}
295	}
296}
297