1 /* $OpenBSD: parse.y,v 1.8 2015/07/21 16:12:04 tedu Exp $ */
3 * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
42 #define YYSTYPE yystype
49 void yyerror(const char *, ...);
55 %token TPERMIT TDENY TAS TCMD TARGS
56 %token TNOPASS TKEEPENV
66 rule: action ident target cmd {
68 r = calloc(1, sizeof(*r));
70 errx(1, "can't allocate rule");
71 r->action = $1.action;
72 r->options = $1.options;
73 r->envlist = $1.envlist;
77 r->cmdargs = $4.cmdargs;
78 if (nrules == maxrules) {
83 if (!(rules = reallocarray(rules, maxrules,
85 errx(1, "can't allocate rules");
90 action: TPERMIT options {
92 $$.options = $2.options;
93 $$.envlist = $2.envlist;
100 $$.options = $1.options | $2.options;
101 $$.envlist = $1.envlist;
104 errx(1, "can't have two keepenv sections");
106 $$.envlist = $2.envlist;
112 $$.options = KEEPENV;
113 } | TKEEPENV '{' envlist '}' {
114 $$.options = KEEPENV;
115 $$.envlist = $3.envlist;
118 envlist: /* empty */ {
119 if (!($$.envlist = calloc(1, sizeof(char *))))
120 errx(1, "can't allocate envlist");
121 } | envlist TSTRING {
122 int nenv = arraylen($1.envlist);
123 if (!($$.envlist = reallocarray($1.envlist, nenv + 2,
125 errx(1, "can't allocate envlist");
126 $$.envlist[nenv] = $2.str;
127 $$.envlist[nenv + 1] = NULL;
135 target: /* optional */ {
141 cmd: /* optional */ {
144 } | TCMD TSTRING args {
146 $$.cmdargs = $3.cmdargs;
152 $$.cmdargs = $2.cmdargs;
155 argslist: /* empty */ {
156 if (!($$.cmdargs = calloc(1, sizeof(char *))))
157 errx(1, "can't allocate args");
158 } | argslist TSTRING {
159 int nargs = arraylen($1.cmdargs);
160 if (!($$.cmdargs = reallocarray($1.cmdargs, nargs + 2, sizeof(char *))))
161 errx(1, "can't allocate args");
162 $$.cmdargs[nargs] = $2.str;
163 $$.cmdargs[nargs + 1] = NULL;
169 yyerror(const char *fmt, ...)
182 { "permit", TPERMIT },
186 { "nopass", TNOPASS },
187 { "keepenv", TKEEPENV },
193 static int colno = 1, lineno = 1;
195 char buf[1024], *ebuf, *p, *str;
196 int i, c, quotes = 0, escape = 0, qpos = 0, nonkw = 0;
199 ebuf = buf + sizeof(buf);
202 /* skip whitespace first */
203 for (c = getc(yyfp); c == ' ' || c == '\t'; c = getc(yyfp))
206 /* check for special one-character constructions */
216 /* skip comments; NUL is allowed; no continuation */
217 while ((c = getc(yyfp)) != '\n')
227 /* parsing next word */
228 for (;; c = getc(yyfp), colno++) {
231 yyerror("unallowed character NUL at "
232 "line %d, column %d", lineno, colno);
242 yyerror("unterminated quotes at line %d, column %d",
252 yyerror("unterminated escape at line %d, column %d",
255 yyerror("unterminated quotes at line %d, column %d",
263 if (!escape && !quotes)
278 yyerror("too long line %d", lineno);
288 * There could be a number of reasons for empty buffer, and we handle
289 * all of them here, to avoid cluttering the main loop.
293 else if (!qpos) /* accept, e.g., empty args: cmd foo args "" */
297 for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
298 if (strcmp(buf, keywords[i].word) == 0)
299 return keywords[i].token;
302 if ((str = strdup(buf)) == NULL)