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
31 enum token_type {
32 NOTOKEN,
33 ENDTOKEN,
34 HOSTID,
35 TABLEID,
36 RDRID,
37 KEYWORD,
38 PATH
39 };
40
41 struct token {
42 enum token_type type;
43 const char *keyword;
44 int value;
45 const struct token *next;
46 };
47
48 static const struct token t_main[];
49 static const struct token t_show[];
50 static const struct token t_rdr[];
51 static const struct token t_table[];
52 static const struct token t_host[];
53 static const struct token t_rdr_id[];
54 static const struct token t_table_id[];
55 static const struct token t_host_id[];
56 static const struct token t_log[];
57 static const struct token t_load[];
58
59 static 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
73 static 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
83 static 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
89 static 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
95 static 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
101 static const struct token t_rdr_id[] = {
102 {RDRID, "", NONE, NULL},
103 {ENDTOKEN, "", NONE, NULL}
104 };
105
106 static const struct token t_table_id[] = {
107 {TABLEID, "", NONE, NULL},
108 {ENDTOKEN, "", NONE, NULL}
109 };
110
111 static const struct token t_host_id[] = {
112 {HOSTID, "", NONE, NULL},
113 {ENDTOKEN, "", NONE, NULL}
114 };
115
116 static const struct token t_log[] = {
117 {KEYWORD, "verbose", LOG_VERBOSE, NULL},
118 {KEYWORD, "brief", LOG_BRIEF, NULL},
119 {ENDTOKEN, "", NONE, NULL}
120 };
121
122 static const struct token t_load[] = {
123 {PATH, "", NONE, NULL},
124 {ENDTOKEN, "", NONE, NULL}
125 };
126
127 static const struct token *match_token(const char *, const struct token *,
128 struct parse_result *);
129 static void show_valid_args(const struct token *);
130
131 struct parse_result *
parse(int argc,char * argv[])132 parse(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
164 static const struct token *
match_token(const char * word,const struct token * table,struct parse_result * res)165 match_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
252 static void
show_valid_args(const struct token * table)253 show_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