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