dhclient - Try harder to re-initialize parsing state.
[dragonfly.git] / sbin / dhclient / conflex.c
... / ...
CommitLineData
1/* $OpenBSD: src/sbin/dhclient/conflex.c,v 1.14 2011/12/10 17:36:40 krw Exp $ */
2
3/* Lexical scanner for dhclient config file... */
4
5/*
6 * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43#include <ctype.h>
44
45#include "dhcpd.h"
46#include "dhctoken.h"
47
48int lexline;
49int lexchar;
50char *token_line;
51char *prev_line;
52char *cur_line;
53char *tlname;
54
55static char line1[81];
56static char line2[81];
57static uint lpos;
58static int line;
59static int tlpos;
60static int tline;
61static int token;
62static int ugflag;
63static char *tval;
64static char tokbuf[1500];
65
66static int get_char(FILE *);
67static int get_token(FILE *);
68static void skip_to_eol(FILE *);
69static int read_string(FILE *);
70static int read_number(int, FILE *);
71static int read_num_or_name(int, FILE *);
72int kw_cmp(const void *, const void *);
73static int intern(char *, int);
74
75void
76new_parse(char *name)
77{
78 /*
79 * Initialize all parsing state, as we are starting to parse a
80 * new file, 'name'.
81 */
82
83 bzero(line1, sizeof(line1));
84 bzero(line2, sizeof(line2));
85 bzero(tokbuf, sizeof(tokbuf));
86
87 lpos = line = 1;
88 tlpos = tline = token = ugflag = 0;
89 tval = NULL;
90
91 lexline = lexchar = 0;
92 cur_line = line1;
93 prev_line = line2;
94 token_line = cur_line;
95 tlname = name;
96
97 warnings_occurred = 0;
98}
99
100static int
101get_char(FILE *cfile)
102{
103 int c = getc(cfile);
104 if (!ugflag) {
105 if (c == '\n') {
106 if (cur_line == line1) {
107 cur_line = line2;
108 prev_line = line1;
109 } else {
110 cur_line = line2;
111 prev_line = line1;
112 }
113 line++;
114 lpos = 1;
115 cur_line[0] = 0;
116 } else if (c != EOF) {
117 if (lpos < sizeof(line1)) {
118 cur_line[lpos - 1] = c;
119 cur_line[lpos] = 0;
120 }
121 lpos++;
122 }
123 } else
124 ugflag = 0;
125 return (c);
126}
127
128static int
129get_token(FILE *cfile)
130{
131 int c, ttok;
132 static char tb[2];
133 int l, p;
134
135 do {
136 l = line;
137 p = lpos;
138
139 c = get_char(cfile);
140
141 if (isascii(c) && isspace(c))
142 continue;
143 if (c == '#') {
144 skip_to_eol(cfile);
145 continue;
146 }
147 if (c == '"') {
148 lexline = l;
149 lexchar = p;
150 ttok = read_string(cfile);
151 break;
152 }
153 if ((isascii(c) && isdigit(c)) || c == '-') {
154 lexline = l;
155 lexchar = p;
156 ttok = read_number(c, cfile);
157 break;
158 } else if (isascii(c) && isalpha(c)) {
159 lexline = l;
160 lexchar = p;
161 ttok = read_num_or_name(c, cfile);
162 break;
163 } else {
164 lexline = l;
165 lexchar = p;
166 tb[0] = c;
167 tb[1] = 0;
168 tval = tb;
169 ttok = c;
170 break;
171 }
172 } while (1);
173 return (ttok);
174}
175
176int
177next_token(char **rval, FILE *cfile)
178{
179 int rv;
180
181 if (token) {
182 if (lexline != tline)
183 token_line = cur_line;
184 lexchar = tlpos;
185 lexline = tline;
186 rv = token;
187 token = 0;
188 } else {
189 rv = get_token(cfile);
190 token_line = cur_line;
191 }
192 if (rval)
193 *rval = tval;
194
195 return (rv);
196}
197
198int
199peek_token(char **rval, FILE *cfile)
200{
201 int x;
202
203 if (!token) {
204 tlpos = lexchar;
205 tline = lexline;
206 token = get_token(cfile);
207 if (lexline != tline)
208 token_line = prev_line;
209 x = lexchar;
210 lexchar = tlpos;
211 tlpos = x;
212 x = lexline;
213 lexline = tline;
214 tline = x;
215 }
216 if (rval)
217 *rval = tval;
218
219 return (token);
220}
221
222static void
223skip_to_eol(FILE *cfile)
224{
225 int c;
226
227 do {
228 c = get_char(cfile);
229 if (c == EOF)
230 return;
231 if (c == '\n')
232 return;
233 } while (1);
234}
235
236static int
237read_string(FILE *cfile)
238{
239 uint i;
240 int c, bs = 0;
241
242 for (i = 0; i < sizeof(tokbuf); i++) {
243 c = get_char(cfile);
244 if (c == EOF) {
245 parse_warn("eof in string constant");
246 break;
247 }
248 if (bs) {
249 bs = 0;
250 tokbuf[i] = c;
251 } else if (c == '\\')
252 bs = 1;
253 else if (c == '"')
254 break;
255 else
256 tokbuf[i] = c;
257 }
258 /*
259 * Normally, I'd feel guilty about this, but we're talking about
260 * strings that'll fit in a DHCP packet here...
261 */
262 if (i == sizeof(tokbuf)) {
263 parse_warn("string constant larger than internal buffer");
264 i--;
265 }
266 tokbuf[i] = 0;
267 tval = tokbuf;
268 return (TOK_STRING);
269}
270
271static int
272read_number(int c, FILE *cfile)
273{
274 uint i = 0;
275 int seenx = 0, token = TOK_NUMBER;
276
277 tokbuf[i++] = c;
278 for (; i < sizeof(tokbuf); i++) {
279 c = get_char(cfile);
280 if (!seenx && c == 'x')
281 seenx = 1;
282 else if (!isascii(c) || !isxdigit(c)) {
283 ungetc(c, cfile);
284 ugflag = 1;
285 break;
286 }
287 tokbuf[i] = c;
288 }
289 if (i == sizeof(tokbuf)) {
290 parse_warn("numeric token larger than internal buffer");
291 i--;
292 }
293 tokbuf[i] = 0;
294 tval = tokbuf;
295
296 return (token);
297}
298
299static int
300read_num_or_name(int c, FILE *cfile)
301{
302 uint i = 0;
303 int rv = TOK_NUMBER_OR_NAME;
304
305 tokbuf[i++] = c;
306 for (; i < sizeof(tokbuf); i++) {
307 c = get_char(cfile);
308 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
309 ungetc(c, cfile);
310 ugflag = 1;
311 break;
312 }
313 if (!isxdigit(c))
314 rv = TOK_NAME;
315 tokbuf[i] = c;
316 }
317 if (i == sizeof(tokbuf)) {
318 parse_warn("token larger than internal buffer");
319 i--;
320 }
321 tokbuf[i] = 0;
322 tval = tokbuf;
323
324 return (intern(tval, rv));
325}
326
327static const struct keywords {
328 const char *k_name;
329 int k_val;
330} keywords[] = {
331 { "alias", TOK_ALIAS },
332 { "append", TOK_APPEND },
333 { "backoff-cutoff", TOK_BACKOFF_CUTOFF },
334 { "bootp", TOK_BOOTP },
335 { "default", TOK_DEFAULT },
336 { "deny", TOK_DENY },
337 { "ethernet", TOK_ETHERNET },
338 { "expire", TOK_EXPIRE },
339 { "fddi", TOK_FDDI },
340 { "filename", TOK_FILENAME },
341 { "fixed-address", TOK_FIXED_ADDR },
342 { "hardware", TOK_HARDWARE },
343 { "initial-interval", TOK_INITIAL_INTERVAL },
344 { "interface", TOK_INTERFACE },
345 { "lease", TOK_LEASE },
346 { "link-timeout", TOK_LINK_TIMEOUT },
347 { "media", TOK_MEDIA },
348 { "medium", TOK_MEDIUM },
349 { "option", TOK_OPTION },
350 { "prepend", TOK_PREPEND },
351 { "rebind", TOK_REBIND },
352 { "reboot", TOK_REBOOT },
353 { "reject", TOK_REJECT },
354 { "renew", TOK_RENEW },
355 { "request", TOK_REQUEST },
356 { "require", TOK_REQUIRE },
357 { "retry", TOK_RETRY },
358 { "script", TOK_SCRIPT },
359 { "select-timeout", TOK_SELECT_TIMEOUT },
360 { "send", TOK_SEND },
361 { "server-name", TOK_SERVER_NAME },
362 { "supersede", TOK_SUPERSEDE },
363 { "timeout", TOK_TIMEOUT },
364 { "token-ring", TOK_TOKEN_RING }
365};
366
367int
368kw_cmp(const void *k, const void *e)
369{
370 return (strcasecmp(k, ((const struct keywords *)e)->k_name));
371}
372
373static int
374intern(char *atom, int dfv)
375{
376 const struct keywords *p;
377
378 p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]),
379 sizeof(keywords[0]), kw_cmp);
380 if (p)
381 return (p->k_val);
382 return (dfv);
383}