xref: /freebsd/usr.sbin/jail/jaillex.l (revision 4c0d7cdf5d3b64e235140553601c0dd5827429a7)
1 %{
2 /*-
3  * Copyright (c) 2011 James Gritton
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <err.h>
32 #include <stddef.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
36 #include "jailp.h"
37 #include "y.tab.h"
38 
39 #define YY_NO_INPUT
40 #define YY_NO_UNPUT
41 
42 extern int yynerrs;
43 
44 static ssize_t text2lval(size_t triml, size_t trimr, int tovar);
45 
46 static int instr;
47 static int lineno = 1;
48 %}
49 
50 %start _ DQ
51 
52 %%
53 
54 			/* Whitespace or equivalent */
55 <_>[ \t]+		instr = 0;
56 <_>#.*			;
57 <_>\/\/.*		;
58 <_>\/\*([^*]|(\*+([^*\/])))*\*+\/ {
59 				const char *s;
60 
61 				for (s = yytext; s < yytext + yyleng; s++)
62 					if (*s == '\n')
63 						lineno++;
64 				instr = 0;
65 			}
66 <_>\n			{
67 				lineno++;
68 				instr = 0;
69 			}
70 
71 			/* Reserved tokens */
72 <_>\+=			{
73 				instr = 0;
74 				return PLEQ;
75 			}
76 <_>[,;={}]		{
77 				instr = 0;
78 				return yytext[0];
79 			}
80 
81 			/* Atomic (unquoted) strings */
82 <_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ |
83 <_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) |
84 <_,DQ>[$*+/\\]		{
85 				(void)text2lval(0, 0, 0);
86 				return instr ? STR1 : (instr = 1, STR);
87 			}
88 
89 			/* Single and double quoted strings */
90 <_>'([^\'\\]|\\(.|\n))*' {
91 				(void)text2lval(1, 1, 0);
92 				return instr ? STR1 : (instr = 1, STR);
93 			}
94 <_>\"([^"\\]|\\(.|\n))*\" |
95 <DQ>[^\"$\\]([^"\\]|\\(.|\n))*\" {
96 				size_t skip;
97 				ssize_t atvar;
98 
99 				skip = yytext[0] == '"' ? 1 : 0;
100 				atvar = text2lval(skip, 1, 1);
101 				if (atvar < 0)
102 					BEGIN _;
103 				else {
104 					/*
105 					 * The string has a variable inside it.
106 					 * Go into DQ mode to get the variable
107 					 * and then the rest of the string.
108 					 */
109 					BEGIN DQ;
110 					yyless(atvar);
111 				}
112 				return instr ? STR1 : (instr = 1, STR);
113 			}
114 <DQ>\"			BEGIN _;
115 
116 			/* Variables, single-word or bracketed */
117 <_,DQ>$[A-Za-z_][A-Za-z_0-9]* {
118 				(void)text2lval(1, 0, 0);
119 				return instr ? VAR1 : (instr = 1, VAR);
120 			}
121 <_>$\{([^\n{}]|\\(.|\n))*\} |
122 <DQ>$\{([^\n\"{}]|\\(.|\n))*\} {
123 				(void)text2lval(2, 1, 0);
124 				return instr ? VAR1 : (instr = 1, VAR);
125 			}
126 
127 			/* Partially formed bits worth complaining about */
128 <_>\/\*([^*]|(\*+([^*\/])))*\** {
129 				warnx("%s line %d: unterminated comment",
130 				    cfname, lineno);
131 				yynerrs++;
132 			}
133 <_>'([^\n'\\]|\\.)*	|
134 <_>\"([^\n\"\\]|\\.)*	{
135 				warnx("%s line %d: unterminated string",
136 				    cfname, lineno);
137 				yynerrs++;
138 			}
139 <_>$\{([^\n{}]|\\.)*	|
140 <DQ>$\{([^\n\"{}]|\\.)*	{
141 				warnx("%s line %d: unterminated variable",
142 				    cfname, lineno);
143 				yynerrs++;
144 			}
145 
146 			/* A hack because "<0>" rules aren't allowed */
147 <_>.			return yytext[0];
148 .|\n			{
149 				BEGIN _;
150 				yyless(0);
151 			}
152 
153 %%
154 
155 void
156 yyerror(const char *s)
157 {
158 	if (!yytext)
159 		warnx("%s line %d: %s", cfname, lineno, s);
160 	else if (!yytext[0])
161 		warnx("%s: unexpected EOF", cfname);
162 	else
163 		warnx("%s line %d: %s: %s", cfname, lineno, yytext, s);
164 }
165 
166 /*
167  * Copy string from yytext to yylval, handling backslash escapes,
168  * and optionally stopping at the beginning of a variable.
169  */
170 static ssize_t
171 text2lval(size_t triml, size_t trimr, int tovar)
172 {
173 	char *d;
174 	const char *s, *se;
175 
176 	yylval.cs = d = emalloc(yyleng - trimr - triml + 1);
177 	se = yytext + (yyleng - trimr);
178 	for (s = yytext + triml; s < se; s++, d++) {
179 		if (*s != '\\') {
180 			if (tovar && *s == '$') {
181 				*d = '\0';
182 				return s - yytext;
183 			}
184 			if (*s == '\n')
185 				lineno++;
186 			*d = *s;
187 			continue;
188 		}
189 		s++;
190 		if (*s >= '0' && *s <= '7') {
191 			*d = *s - '0';
192 			if (s + 1 < se && s[1] >= '0' && s[1] <= '7') {
193 				*d = 010 * *d + (*++s - '0');
194 				if (s + 1 < se && s[1] >= '0' && s[1] <= '7')
195 					*d = 010 * *d + (*++s - '0');
196 			}
197 			continue;
198 		}
199 		switch (*s) {
200 		case 'a':	*d = '\a';	break;
201 		case 'b':	*d = '\b';	break;
202 		case 'f':	*d = '\f';	break;
203 		case 'n':	*d = '\n';	break;
204 		case 'r':	*d = '\r';	break;
205 		case 't':	*d = '\t';	break;
206 		case 'v':	*d = '\v';	break;
207 		case '\n':	d--; lineno++;	break;
208 		default:	*d = *s;	break;
209 		case 'x':
210 			*d = 0;
211 			if (s + 1 >= se)
212 				break;
213 			if (s[1] >= '0' && s[1] <= '9')
214 				*d = *++s - '0';
215 			else if (s[1] >= 'A' && s[1] <= 'F')
216 				*d = *++s + (0xA - 'A');
217 			else if (s[1] >= 'a' && s[1] <= 'a')
218 				*d = *++s + (0xa - 'a');
219 			else
220 				break;
221 			if (s + 1 >= se)
222 				break;
223 			if (s[1] >= '0' && s[1] <= '9')
224 				*d = *d * 0x10 + (*++s - '0');
225 			else if (s[1] >= 'A' && s[1] <= 'F')
226 				*d = *d * 0x10 + (*++s + (0xA - 'A'));
227 			else if (s[1] >= 'a' && s[1] <= 'a')
228 				*d = *d * 0x10 + (*++s + (0xa - 'a'));
229 		}
230 	}
231 	*d = '\0';
232 	return -1;
233 }
234