xref: /openbsd-src/usr.sbin/relayctl/parser.c (revision a49b8563304b44b374aafc0a3ada7016b28f8a0b)
1*a49b8563Sreyk /*	$OpenBSD: parser.c,v 1.28 2018/05/11 20:33:54 reyk Exp $	*/
2feb9ff76Sreyk 
3feb9ff76Sreyk /*
436f5dc5eSpyr  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5feb9ff76Sreyk  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
6feb9ff76Sreyk  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7feb9ff76Sreyk  *
8feb9ff76Sreyk  * Permission to use, copy, modify, and distribute this software for any
9feb9ff76Sreyk  * purpose with or without fee is hereby granted, provided that the above
10feb9ff76Sreyk  * copyright notice and this permission notice appear in all copies.
11feb9ff76Sreyk  *
12feb9ff76Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13feb9ff76Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14feb9ff76Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15feb9ff76Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16feb9ff76Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17feb9ff76Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18feb9ff76Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19feb9ff76Sreyk  */
20feb9ff76Sreyk 
21feb9ff76Sreyk #include <sys/types.h>
2253967d9eSreyk 
23feb9ff76Sreyk #include <limits.h>
24feb9ff76Sreyk #include <stdio.h>
25feb9ff76Sreyk #include <stdlib.h>
26feb9ff76Sreyk #include <string.h>
27e8fb3979Spyr 
28748ceb64Sreyk #include "relayd.h"
29feb9ff76Sreyk #include "parser.h"
30feb9ff76Sreyk 
31feb9ff76Sreyk enum token_type {
32feb9ff76Sreyk 	NOTOKEN,
33feb9ff76Sreyk 	ENDTOKEN,
34feb9ff76Sreyk 	HOSTID,
35feb9ff76Sreyk 	TABLEID,
369591a9f7Spyr 	RDRID,
37a2195becSreyk 	KEYWORD,
38a2195becSreyk 	PATH
39feb9ff76Sreyk };
40feb9ff76Sreyk 
41feb9ff76Sreyk struct token {
42feb9ff76Sreyk 	enum token_type		 type;
43feb9ff76Sreyk 	const char		*keyword;
44feb9ff76Sreyk 	int			 value;
45feb9ff76Sreyk 	const struct token	*next;
46feb9ff76Sreyk };
47feb9ff76Sreyk 
48feb9ff76Sreyk static const struct token t_main[];
492edd718bSreyk static const struct token t_show[];
509591a9f7Spyr static const struct token t_rdr[];
51feb9ff76Sreyk static const struct token t_table[];
52feb9ff76Sreyk static const struct token t_host[];
539591a9f7Spyr static const struct token t_rdr_id[];
54feb9ff76Sreyk static const struct token t_table_id[];
55feb9ff76Sreyk static const struct token t_host_id[];
56f579a0f7Sjsg static const struct token t_log[];
57a2195becSreyk static const struct token t_load[];
58feb9ff76Sreyk 
59feb9ff76Sreyk static const struct token t_main[] = {
601569a65fSpyr 	{KEYWORD,	"monitor",	MONITOR,	NULL},
6150cbd9dfSpyr 	{KEYWORD,	"show",		NONE,		t_show},
62a2195becSreyk 	{KEYWORD,	"load",		LOAD,		t_load},
63cd65ce7bSpyr 	{KEYWORD,	"poll",		POLL,		NULL},
642ec23074Spyr 	{KEYWORD,	"reload",	RELOAD,		NULL},
65feb9ff76Sreyk 	{KEYWORD,	"stop",		SHUTDOWN,	NULL},
669591a9f7Spyr 	{KEYWORD,	"redirect",	NONE,		t_rdr},
67269395e8Spyr 	{KEYWORD,	"table",	NONE,		t_table},
68269395e8Spyr 	{KEYWORD,	"host",		NONE,		t_host},
69f579a0f7Sjsg 	{KEYWORD,	"log",		NONE,		t_log},
70feb9ff76Sreyk 	{ENDTOKEN,	"",		NONE,		NULL}
71feb9ff76Sreyk };
72feb9ff76Sreyk 
732edd718bSreyk static const struct token t_show[] = {
742edd718bSreyk 	{KEYWORD,	"summary",	SHOW_SUM,	NULL},
752edd718bSreyk 	{KEYWORD,	"hosts",	SHOW_HOSTS,	NULL},
76dec6607bSreyk 	{KEYWORD,	"redirects",	SHOW_RDRS,	NULL},
772edd718bSreyk 	{KEYWORD,	"relays",	SHOW_RELAYS,	NULL},
78417c432fSreyk 	{KEYWORD,	"routers",	SHOW_ROUTERS,	NULL},
79fa0d8478Sreyk 	{KEYWORD,	"sessions",	SHOW_SESSIONS,	NULL},
802edd718bSreyk 	{ENDTOKEN,	"",		NONE,		NULL}
812edd718bSreyk };
822edd718bSreyk 
839591a9f7Spyr static const struct token t_rdr[] = {
849591a9f7Spyr 	{KEYWORD,	"disable",	RDR_DISABLE,	t_rdr_id},
859591a9f7Spyr 	{KEYWORD,	"enable",	RDR_ENABLE,	t_rdr_id},
86feb9ff76Sreyk 	{ENDTOKEN,	"",		NONE,		NULL}
87feb9ff76Sreyk };
88feb9ff76Sreyk 
89feb9ff76Sreyk static const struct token t_table[] = {
90feb9ff76Sreyk 	{KEYWORD,	"disable",	TABLE_DISABLE,	t_table_id},
91feb9ff76Sreyk 	{KEYWORD,	"enable",	TABLE_ENABLE,	t_table_id},
92feb9ff76Sreyk 	{ENDTOKEN,	"",		NONE,		NULL}
93feb9ff76Sreyk };
94feb9ff76Sreyk 
95feb9ff76Sreyk static const struct token t_host[] = {
96feb9ff76Sreyk 	{KEYWORD,	"disable",	HOST_DISABLE,	t_host_id},
97feb9ff76Sreyk 	{KEYWORD,	"enable",	HOST_ENABLE,	t_host_id},
98feb9ff76Sreyk 	{ENDTOKEN,	"",		NONE,		NULL}
99feb9ff76Sreyk };
100feb9ff76Sreyk 
1019591a9f7Spyr static const struct token t_rdr_id[] = {
1029591a9f7Spyr 	{RDRID,		"",		NONE,		NULL},
103feb9ff76Sreyk 	{ENDTOKEN,	"",		NONE,		NULL}
104feb9ff76Sreyk };
105feb9ff76Sreyk 
106feb9ff76Sreyk static const struct token t_table_id[] = {
107feb9ff76Sreyk 	{TABLEID,	"",		NONE,		NULL},
108feb9ff76Sreyk 	{ENDTOKEN,	"",		NONE,		NULL}
109feb9ff76Sreyk };
110feb9ff76Sreyk 
111feb9ff76Sreyk static const struct token t_host_id[] = {
112feb9ff76Sreyk 	{HOSTID,	"",		NONE,		NULL},
113feb9ff76Sreyk 	{ENDTOKEN,	"",		NONE,		NULL}
114feb9ff76Sreyk };
115feb9ff76Sreyk 
116f579a0f7Sjsg static const struct token t_log[] = {
117f579a0f7Sjsg 	{KEYWORD,	"verbose",	LOG_VERBOSE,	NULL},
118f579a0f7Sjsg 	{KEYWORD,	"brief",	LOG_BRIEF,	NULL},
119f579a0f7Sjsg 	{ENDTOKEN,	"",		NONE,		NULL}
120f579a0f7Sjsg };
121f579a0f7Sjsg 
122a2195becSreyk static const struct token t_load[] = {
123a2195becSreyk 	{PATH,		"",		NONE,		NULL},
124a2195becSreyk 	{ENDTOKEN,	"",		NONE,		NULL}
125a2195becSreyk };
126a2195becSreyk 
1276be5843eStedu static const struct token *match_token(const char *, const struct token *,
1286be5843eStedu     struct parse_result *);
1296be5843eStedu static void show_valid_args(const struct token *);
130feb9ff76Sreyk 
131feb9ff76Sreyk struct parse_result *
parse(int argc,char * argv[])132feb9ff76Sreyk parse(int argc, char *argv[])
133feb9ff76Sreyk {
1346be5843eStedu 	static struct parse_result	res;
135feb9ff76Sreyk 	const struct token	*table = t_main;
136feb9ff76Sreyk 	const struct token	*match;
137feb9ff76Sreyk 
138feb9ff76Sreyk 	bzero(&res, sizeof(res));
139feb9ff76Sreyk 
1406ee11063Sclaudio 	while (argc >= 0) {
1416be5843eStedu 		if ((match = match_token(argv[0], table, &res)) == NULL) {
142feb9ff76Sreyk 			fprintf(stderr, "valid commands/args:\n");
143feb9ff76Sreyk 			show_valid_args(table);
144feb9ff76Sreyk 			return (NULL);
145feb9ff76Sreyk 		}
146feb9ff76Sreyk 
147feb9ff76Sreyk 		argc--;
148feb9ff76Sreyk 		argv++;
149feb9ff76Sreyk 
150feb9ff76Sreyk 		if (match->type == NOTOKEN || match->next == NULL)
151feb9ff76Sreyk 			break;
152feb9ff76Sreyk 
153feb9ff76Sreyk 		table = match->next;
154feb9ff76Sreyk 	}
155feb9ff76Sreyk 
156feb9ff76Sreyk 	if (argc > 0) {
157feb9ff76Sreyk 		fprintf(stderr, "superfluous argument: %s\n", argv[0]);
158feb9ff76Sreyk 		return (NULL);
159feb9ff76Sreyk 	}
160feb9ff76Sreyk 
161feb9ff76Sreyk 	return (&res);
162feb9ff76Sreyk }
163feb9ff76Sreyk 
1646be5843eStedu static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)1656be5843eStedu match_token(const char *word, const struct token *table,
1666be5843eStedu     struct parse_result *res)
167feb9ff76Sreyk {
168feb9ff76Sreyk 	u_int			 i, match;
169feb9ff76Sreyk 	const struct token	*t = NULL;
170feb9ff76Sreyk 	const char		*errstr;
171feb9ff76Sreyk 
172feb9ff76Sreyk 	match = 0;
173feb9ff76Sreyk 
174feb9ff76Sreyk 	for (i = 0; table[i].type != ENDTOKEN; i++) {
175feb9ff76Sreyk 		switch (table[i].type) {
176feb9ff76Sreyk 		case NOTOKEN:
177feb9ff76Sreyk 			if (word == NULL || strlen(word) == 0) {
178feb9ff76Sreyk 				match++;
179feb9ff76Sreyk 				t = &table[i];
180feb9ff76Sreyk 			}
181feb9ff76Sreyk 			break;
182feb9ff76Sreyk 		case KEYWORD:
183feb9ff76Sreyk 			if (word != NULL && strncmp(word, table[i].keyword,
184feb9ff76Sreyk 			    strlen(word)) == 0) {
185feb9ff76Sreyk 				match++;
186feb9ff76Sreyk 				t = &table[i];
187feb9ff76Sreyk 				if (t->value)
1886be5843eStedu 					res->action = t->value;
189feb9ff76Sreyk 			}
190feb9ff76Sreyk 			break;
191feb9ff76Sreyk 		case HOSTID:
1926ee11063Sclaudio 			if (word == NULL)
1936ee11063Sclaudio 				break;
1946be5843eStedu 			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
195ef1f2334Sreyk 			if (errstr) {
1962b295804Sreyk 				strlcpy(res->id.name, word,
1972b295804Sreyk 				    sizeof(res->id.name));
1986be5843eStedu 				res->id.id = EMPTY_ID;
199ef1f2334Sreyk 			}
200feb9ff76Sreyk 			t = &table[i];
201feb9ff76Sreyk 			match++;
202feb9ff76Sreyk 			break;
203feb9ff76Sreyk 		case TABLEID:
2046ee11063Sclaudio 			if (word == NULL)
2056ee11063Sclaudio 				break;
2066be5843eStedu 			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
207ef1f2334Sreyk 			if (errstr) {
2082b295804Sreyk 				strlcpy(res->id.name, word,
2092b295804Sreyk 				    sizeof(res->id.name));
2106be5843eStedu 				res->id.id = EMPTY_ID;
211ef1f2334Sreyk 			}
212feb9ff76Sreyk 			t = &table[i];
213feb9ff76Sreyk 			match++;
214feb9ff76Sreyk 			break;
2159591a9f7Spyr 		case RDRID:
2166ee11063Sclaudio 			if (word == NULL)
2176ee11063Sclaudio 				break;
2186be5843eStedu 			res->id.id = strtonum(word, 0, UINT_MAX, &errstr);
219ef1f2334Sreyk 			if (errstr) {
2202b295804Sreyk 				strlcpy(res->id.name, word,
2212b295804Sreyk 				    sizeof(res->id.name));
2226be5843eStedu 				res->id.id = EMPTY_ID;
223ef1f2334Sreyk 			}
224feb9ff76Sreyk 			t = &table[i];
225feb9ff76Sreyk 			match++;
226feb9ff76Sreyk 			break;
227a2195becSreyk 		case PATH:
228a2195becSreyk 			if (!match && word != NULL && strlen(word) > 0) {
229a2195becSreyk 				res->path = strdup(word);
230a2195becSreyk 				match++;
231a2195becSreyk 				t = &table[i];
232a2195becSreyk 			}
233a2195becSreyk 			break;
234feb9ff76Sreyk 		case ENDTOKEN:
235feb9ff76Sreyk 			break;
236feb9ff76Sreyk 		}
237feb9ff76Sreyk 	}
238feb9ff76Sreyk 
239feb9ff76Sreyk 	if (match != 1) {
2406ee11063Sclaudio 		if (word == NULL)
2416ee11063Sclaudio 			fprintf(stderr, "missing argument:\n");
2426ee11063Sclaudio 		else if (match > 1)
243feb9ff76Sreyk 			fprintf(stderr, "ambiguous argument: %s\n", word);
2446ee11063Sclaudio 		else if (match < 1)
245feb9ff76Sreyk 			fprintf(stderr, "unknown argument: %s\n", word);
246feb9ff76Sreyk 		return (NULL);
247feb9ff76Sreyk 	}
248feb9ff76Sreyk 
249feb9ff76Sreyk 	return (t);
250feb9ff76Sreyk }
251feb9ff76Sreyk 
2526be5843eStedu static void
show_valid_args(const struct token * table)253e331d0fcSjsg show_valid_args(const struct token *table)
254feb9ff76Sreyk {
255feb9ff76Sreyk 	int	i;
256feb9ff76Sreyk 
257feb9ff76Sreyk 	for (i = 0; table[i].type != ENDTOKEN; i++) {
258feb9ff76Sreyk 		switch (table[i].type) {
259feb9ff76Sreyk 		case NOTOKEN:
260feb9ff76Sreyk 			fprintf(stderr, "  <cr>\n");
261feb9ff76Sreyk 			break;
262feb9ff76Sreyk 		case KEYWORD:
263feb9ff76Sreyk 			fprintf(stderr, "  %s\n", table[i].keyword);
264feb9ff76Sreyk 			break;
2659591a9f7Spyr 		case RDRID:
266c84cf264Sreyk 			fprintf(stderr, "  <redirectid>\n");
267feb9ff76Sreyk 			break;
268feb9ff76Sreyk 		case TABLEID:
269feb9ff76Sreyk 			fprintf(stderr, "  <tableid>\n");
270feb9ff76Sreyk 			break;
271feb9ff76Sreyk 		case HOSTID:
272feb9ff76Sreyk 			fprintf(stderr, "  <hostid>\n");
273feb9ff76Sreyk 			break;
274a2195becSreyk 		case PATH:
275a2195becSreyk 			fprintf(stderr, "  <path>\n");
276a2195becSreyk 			break;
277feb9ff76Sreyk 		case ENDTOKEN:
278feb9ff76Sreyk 			break;
279feb9ff76Sreyk 		}
280feb9ff76Sreyk 	}
281feb9ff76Sreyk }
282