1*a15cd296Sflorian /* $OpenBSD: parse.c,v 1.29 2024/06/27 16:39:31 florian Exp $ */
2e853bc5dShenning
3e853bc5dShenning /*
4e853bc5dShenning * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
5e853bc5dShenning * All rights reserved.
6e853bc5dShenning *
7e853bc5dShenning * Redistribution and use in source and binary forms, with or without
8e853bc5dShenning * modification, are permitted provided that the following conditions
9e853bc5dShenning * are met:
10e853bc5dShenning *
11e853bc5dShenning * 1. Redistributions of source code must retain the above copyright
12e853bc5dShenning * notice, this list of conditions and the following disclaimer.
13e853bc5dShenning * 2. Redistributions in binary form must reproduce the above copyright
14e853bc5dShenning * notice, this list of conditions and the following disclaimer in the
15e853bc5dShenning * documentation and/or other materials provided with the distribution.
16e853bc5dShenning * 3. Neither the name of The Internet Software Consortium nor the names
17e853bc5dShenning * of its contributors may be used to endorse or promote products derived
18e853bc5dShenning * from this software without specific prior written permission.
19e853bc5dShenning *
20e853bc5dShenning * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21e853bc5dShenning * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22e853bc5dShenning * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23e853bc5dShenning * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24e853bc5dShenning * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25e853bc5dShenning * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26e853bc5dShenning * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27e853bc5dShenning * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28e853bc5dShenning * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29e853bc5dShenning * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30e853bc5dShenning * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31e853bc5dShenning * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e853bc5dShenning * SUCH DAMAGE.
33e853bc5dShenning *
34e853bc5dShenning * This software has been written for the Internet Software Consortium
35e853bc5dShenning * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36e853bc5dShenning * Enterprises. To learn more about the Internet Software Consortium,
37e853bc5dShenning * see ``http://www.vix.com/isc''. To learn more about Vixie
38e853bc5dShenning * Enterprises, see ``http://www.vix.com''.
39e853bc5dShenning */
40e853bc5dShenning
41837cddffSkrw #include <sys/types.h>
42837cddffSkrw #include <sys/socket.h>
4311b1f78aSkrw
44837cddffSkrw #include <net/if.h>
45837cddffSkrw
46837cddffSkrw #include <netinet/in.h>
474c718f6aSdtucker #include <netinet/if_ether.h>
48837cddffSkrw
49837cddffSkrw #include <ctype.h>
50c525a185Skrw #include <errno.h>
51f0a65fa0Skrw #include <stdarg.h>
52837cddffSkrw #include <stdint.h>
53837cddffSkrw #include <stdio.h>
54837cddffSkrw #include <stdlib.h>
55837cddffSkrw #include <string.h>
56f0a65fa0Skrw #include <syslog.h>
57579e3f2dSguenther #include <time.h>
58f0a65fa0Skrw #include <unistd.h>
59837cddffSkrw
60837cddffSkrw #include "dhcp.h"
61837cddffSkrw #include "tree.h"
62e853bc5dShenning #include "dhcpd.h"
63e853bc5dShenning #include "dhctoken.h"
64c525a185Skrw #include "log.h"
65e853bc5dShenning
6662767975Shshoexer /*
6762767975Shshoexer * Skip to the semicolon ending the current statement. If we encounter
68c824f21bShenning * braces, the matching closing brace terminates the statement. If we
69c824f21bShenning * encounter a right brace but haven't encountered a left brace, return
70c824f21bShenning * leaving the brace in the token buffer for the caller. If we see a
71c824f21bShenning * semicolon and haven't seen a left brace, return. This lets us skip
72c824f21bShenning * over:
73c824f21bShenning *
74c824f21bShenning * statement;
75c824f21bShenning * statement foo bar { }
76c824f21bShenning * statement foo bar { statement { } }
77c824f21bShenning * statement}
78c824f21bShenning *
79c824f21bShenning * ...et cetera.
80c824f21bShenning */
81c824f21bShenning void
skip_to_semi(FILE * cfile)82c824f21bShenning skip_to_semi(FILE *cfile)
83e853bc5dShenning {
84e853bc5dShenning int token;
85e853bc5dShenning char *val;
86e853bc5dShenning int brace_count = 0;
87e853bc5dShenning
88e853bc5dShenning do {
89e853bc5dShenning token = peek_token(&val, cfile);
90f3ec5800Sderaadt if (token == '}') {
91e853bc5dShenning if (brace_count) {
92e853bc5dShenning token = next_token(&val, cfile);
93e853bc5dShenning if (!--brace_count)
94e853bc5dShenning return;
95e853bc5dShenning } else
96e853bc5dShenning return;
97f3ec5800Sderaadt } else if (token == '{') {
98e853bc5dShenning brace_count++;
99f3ec5800Sderaadt } else if (token == ';' && !brace_count) {
100e853bc5dShenning token = next_token(&val, cfile);
101e853bc5dShenning return;
102fbc5e94dShenning } else if (token == '\n') {
103c824f21bShenning /*
104c824f21bShenning * EOL only happens when parsing
105c824f21bShenning * /etc/resolv.conf, and we treat it like a
106c824f21bShenning * semicolon because the resolv.conf file is
107c824f21bShenning * line-oriented.
108c824f21bShenning */
109e853bc5dShenning token = next_token(&val, cfile);
110e853bc5dShenning return;
111e853bc5dShenning }
112e853bc5dShenning token = next_token(&val, cfile);
113e853bc5dShenning } while (token != EOF);
114e853bc5dShenning }
115e853bc5dShenning
116c824f21bShenning int
parse_semi(FILE * cfile)117c824f21bShenning parse_semi(FILE *cfile)
118e853bc5dShenning {
119e853bc5dShenning int token;
120e853bc5dShenning char *val;
121e853bc5dShenning
122e853bc5dShenning token = next_token(&val, cfile);
123f3ec5800Sderaadt if (token != ';') {
124e853bc5dShenning parse_warn("semicolon expected.");
125e853bc5dShenning skip_to_semi(cfile);
126c824f21bShenning return (0);
127e853bc5dShenning }
128c824f21bShenning return (1);
129e853bc5dShenning }
130e853bc5dShenning
131c824f21bShenning /*
132c824f21bShenning * string-parameter :== STRING SEMI
133c824f21bShenning */
134c824f21bShenning char *
parse_string(FILE * cfile)135c824f21bShenning parse_string(FILE *cfile)
136e853bc5dShenning {
1378e1c2028Sderaadt char *val, *s;
138e853bc5dShenning int token;
139e853bc5dShenning
140e853bc5dShenning token = next_token(&val, cfile);
141f3ec5800Sderaadt if (token != TOK_STRING) {
142e853bc5dShenning parse_warn("filename must be a string");
143e853bc5dShenning skip_to_semi(cfile);
144c824f21bShenning return (NULL);
145e853bc5dShenning }
1467a904ddaSkrw s = strdup(val);
1477a904ddaSkrw if (s == NULL)
148c525a185Skrw fatalx("no memory for string %s.", val);
149e853bc5dShenning
150ff19af11Sstevesk if (!parse_semi(cfile)) {
151ff19af11Sstevesk free(s);
152c824f21bShenning return (NULL);
153ff19af11Sstevesk }
154c824f21bShenning return (s);
155e853bc5dShenning }
156e853bc5dShenning
157c824f21bShenning /*
158c824f21bShenning * hostname :== identifier | hostname DOT identifier
159c824f21bShenning */
160c824f21bShenning char *
parse_host_name(FILE * cfile)161c824f21bShenning parse_host_name(FILE *cfile)
162e853bc5dShenning {
1638e1c2028Sderaadt char *val, *s, *t;
1648e1c2028Sderaadt int token, len = 0;
165c824f21bShenning pair c = NULL;
166e853bc5dShenning
167e853bc5dShenning /* Read a dotted hostname... */
168e853bc5dShenning do {
169e853bc5dShenning /* Read a token, which should be an identifier. */
170e853bc5dShenning token = next_token(&val, cfile);
17111b1f78aSkrw if (!is_identifier(token)) {
172e853bc5dShenning parse_warn("expecting an identifier in hostname");
173e853bc5dShenning skip_to_semi(cfile);
174c824f21bShenning return (NULL);
175e853bc5dShenning }
176e853bc5dShenning /* Store this identifier... */
1777a904ddaSkrw s = strdup(val);
1787a904ddaSkrw if (s == NULL)
179c525a185Skrw fatalx("can't allocate temp space for hostname.");
180e853bc5dShenning c = cons((caddr_t) s, c);
181e853bc5dShenning len += strlen(s) + 1;
182c824f21bShenning /*
183c824f21bShenning * Look for a dot; if it's there, keep going, otherwise
184c824f21bShenning * we're done.
185c824f21bShenning */
186e853bc5dShenning token = peek_token(&val, cfile);
187f3ec5800Sderaadt if (token == '.')
188e853bc5dShenning token = next_token(&val, cfile);
189f3ec5800Sderaadt } while (token == '.');
190e853bc5dShenning
191e853bc5dShenning /* Assemble the hostname together into a string. */
192c824f21bShenning if (!(s = malloc(len)))
193c525a185Skrw fatalx("can't allocate space for hostname.");
194e853bc5dShenning t = s + len;
195c824f21bShenning *--t = '\0';
196e853bc5dShenning while (c) {
197e853bc5dShenning pair cdr = c->cdr;
198c824f21bShenning int l = strlen((char *)c->car);
1998e1c2028Sderaadt
200e853bc5dShenning t -= l;
201c824f21bShenning memcpy(t, (char *)c->car, l);
202e853bc5dShenning /* Free up temp space. */
203e853bc5dShenning free(c->car);
204e853bc5dShenning free(c);
205e853bc5dShenning c = cdr;
206e853bc5dShenning if (t != s)
207e853bc5dShenning *--t = '.';
208e853bc5dShenning }
209c824f21bShenning return (s);
210e853bc5dShenning }
211e853bc5dShenning
212c824f21bShenning /*
213c824f21bShenning * hardware-parameter :== HARDWARE ETHERNET csns SEMI
214c824f21bShenning * csns :== NUMBER | csns COLON NUMBER
215c824f21bShenning */
216c824f21bShenning void
parse_hardware_param(FILE * cfile,struct hardware * hardware)217c824f21bShenning parse_hardware_param(FILE *cfile, struct hardware *hardware)
218e853bc5dShenning {
219e853bc5dShenning char *val;
2204c718f6aSdtucker int token, hlen = 0;
2214c718f6aSdtucker unsigned char *e, *t = NULL;
222e853bc5dShenning
223e853bc5dShenning token = next_token(&val, cfile);
224e853bc5dShenning switch (token) {
225f3ec5800Sderaadt case TOK_ETHERNET:
226e853bc5dShenning hardware->htype = HTYPE_ETHER;
227e853bc5dShenning break;
2285b44f46dSreyk case TOK_IPSEC_TUNNEL:
2295b44f46dSreyk hardware->htype = HTYPE_IPSEC_TUNNEL;
2305b44f46dSreyk break;
231e853bc5dShenning default:
232e853bc5dShenning parse_warn("expecting a network hardware type");
233e853bc5dShenning skip_to_semi(cfile);
234e853bc5dShenning return;
235e853bc5dShenning }
236e853bc5dShenning
2374c718f6aSdtucker
2384c718f6aSdtucker /* Try looking up in /etc/ethers first. */
2394c718f6aSdtucker if (hardware->htype == HTYPE_ETHER) {
2404c718f6aSdtucker token = peek_token(&val, cfile);
2414c718f6aSdtucker hlen = sizeof(struct ether_addr);
2424c718f6aSdtucker if ((e = malloc(hlen)) == NULL)
2434c718f6aSdtucker fatalx("can't allocate space for ethernet address.");
2444c718f6aSdtucker if (ether_hostton(val, (struct ether_addr *)e) == 0) {
2454c718f6aSdtucker (void)next_token(&val, cfile); /* consume token */
2464c718f6aSdtucker t = e;
2474c718f6aSdtucker } else
2484c718f6aSdtucker free(e);
2494c718f6aSdtucker }
2504c718f6aSdtucker
251c824f21bShenning /*
252c824f21bShenning * Parse the hardware address information. Technically, it
253c824f21bShenning * would make a lot of sense to restrict the length of the data
254c824f21bShenning * we'll accept here to the length of a particular hardware
255c824f21bShenning * address type. Unfortunately, there are some broken clients
256c824f21bShenning * out there that put bogus data in the chaddr buffer, and we
257c824f21bShenning * accept that data in the lease file rather than simply failing
258c824f21bShenning * on such clients. Yuck.
259c824f21bShenning */
2604c718f6aSdtucker if (!t)
261f3ec5800Sderaadt t = parse_numeric_aggregate(cfile, NULL, &hlen, ':', 16, 8);
2624c718f6aSdtucker
263e853bc5dShenning if (!t)
264e853bc5dShenning return;
265c824f21bShenning if (hlen > sizeof(hardware->haddr)) {
266e853bc5dShenning free(t);
267e853bc5dShenning parse_warn("hardware address too long");
268e853bc5dShenning } else {
269e853bc5dShenning hardware->hlen = hlen;
27035318e8fSkrw memcpy((unsigned char *)&hardware->haddr[0], t,
27135318e8fSkrw hardware->hlen);
272c824f21bShenning if (hlen < sizeof(hardware->haddr))
273e853bc5dShenning memset(&hardware->haddr[hlen], 0,
274c824f21bShenning sizeof(hardware->haddr) - hlen);
275e853bc5dShenning free(t);
276e853bc5dShenning }
277e853bc5dShenning
278e853bc5dShenning token = next_token(&val, cfile);
279f3ec5800Sderaadt if (token != ';') {
280e853bc5dShenning parse_warn("expecting semicolon.");
281e853bc5dShenning skip_to_semi(cfile);
282e853bc5dShenning }
283e853bc5dShenning }
284e853bc5dShenning
285c824f21bShenning /*
286c824f21bShenning * lease-time :== NUMBER SEMI
287c824f21bShenning */
288c824f21bShenning void
parse_lease_time(FILE * cfile,time_t * timep)289c824f21bShenning parse_lease_time(FILE *cfile, time_t *timep)
290e853bc5dShenning {
29111b1f78aSkrw const char *errstr;
292e853bc5dShenning char *val;
293ca617185Skrw uint32_t value;
294e853bc5dShenning
29588c7b412Snaddy next_token(&val, cfile);
29611b1f78aSkrw
29711b1f78aSkrw value = strtonum(val, 0, UINT32_MAX, &errstr);
29811b1f78aSkrw if (errstr) {
29911b1f78aSkrw parse_warn("lease time is %s: %s", errstr, val);
300e853bc5dShenning skip_to_semi(cfile);
301e853bc5dShenning return;
302e853bc5dShenning }
303e853bc5dShenning
3049fbb22a7Skrw *timep = value;
3059fbb22a7Skrw
306e853bc5dShenning parse_semi(cfile);
307e853bc5dShenning }
308e853bc5dShenning
309c824f21bShenning /*
310c824f21bShenning * No BNF for numeric aggregates - that's defined by the caller. What
311c824f21bShenning * this function does is to parse a sequence of numbers separated by the
312c824f21bShenning * token specified in separator. If max is zero, any number of numbers
313c824f21bShenning * will be parsed; otherwise, exactly max numbers are expected. Base
314c824f21bShenning * and size tell us how to internalize the numbers once they've been
315c824f21bShenning * tokenized.
316c824f21bShenning */
317c824f21bShenning unsigned char *
parse_numeric_aggregate(FILE * cfile,unsigned char * buf,int * max,int separator,int base,int size)318c824f21bShenning parse_numeric_aggregate(FILE *cfile, unsigned char *buf, int *max,
319c824f21bShenning int separator, int base, int size)
320e853bc5dShenning {
3218e1c2028Sderaadt char *val, *t;
3228e1c2028Sderaadt int token, count = 0;
323e853bc5dShenning unsigned char *bufp = buf, *s = NULL;
324c824f21bShenning pair c = NULL;
325e853bc5dShenning
326e853bc5dShenning if (!bufp && *max) {
327c824f21bShenning bufp = malloc(*max * size / 8);
328e853bc5dShenning if (!bufp)
329c525a185Skrw fatalx("can't allocate space for numeric aggregate");
330e853bc5dShenning } else
331e853bc5dShenning s = bufp;
332e853bc5dShenning
333e853bc5dShenning do {
334e853bc5dShenning if (count) {
335e853bc5dShenning token = peek_token(&val, cfile);
336e853bc5dShenning if (token != separator) {
337e853bc5dShenning if (!*max)
338e853bc5dShenning break;
339f3ec5800Sderaadt if (token != '{' && token != '}')
340e853bc5dShenning token = next_token(&val, cfile);
341e853bc5dShenning parse_warn("too few numbers.");
342f3ec5800Sderaadt if (token != ';')
343e853bc5dShenning skip_to_semi(cfile);
344c824f21bShenning return (NULL);
345e853bc5dShenning }
346e853bc5dShenning token = next_token(&val, cfile);
347e853bc5dShenning }
348e853bc5dShenning token = next_token(&val, cfile);
349e853bc5dShenning
350e853bc5dShenning if (token == EOF) {
351e853bc5dShenning parse_warn("unexpected end of file");
352e853bc5dShenning break;
353e853bc5dShenning }
35411b1f78aSkrw if (token != TOK_NUMBER && token != TOK_NUMBER_OR_NAME) {
355e853bc5dShenning parse_warn("expecting numeric value.");
356e853bc5dShenning skip_to_semi(cfile);
357c824f21bShenning return (NULL);
358e853bc5dShenning }
359c824f21bShenning /*
360c824f21bShenning * If we can, convert the number now; otherwise, build a
361c824f21bShenning * linked list of all the numbers.
362c824f21bShenning */
363e853bc5dShenning if (s) {
364e853bc5dShenning convert_num(s, val, base, size);
365e853bc5dShenning s += size / 8;
366e853bc5dShenning } else {
3677a904ddaSkrw t = strdup(val);
3687a904ddaSkrw if (t == NULL)
369c525a185Skrw fatalx("no temp space for number.");
370e853bc5dShenning c = cons(t, c);
371e853bc5dShenning }
372e853bc5dShenning } while (++count != *max);
373e853bc5dShenning
374e853bc5dShenning /* If we had to cons up a list, convert it now. */
375e853bc5dShenning if (c) {
376c824f21bShenning bufp = malloc(count * size / 8);
377e853bc5dShenning if (!bufp)
378c525a185Skrw fatalx("can't allocate space for numeric aggregate.");
379e853bc5dShenning s = bufp + count - size / 8;
380e853bc5dShenning *max = count;
381e853bc5dShenning }
382e853bc5dShenning while (c) {
383e853bc5dShenning pair cdr = c->cdr;
384c824f21bShenning convert_num(s, (char *)c->car, base, size);
385e853bc5dShenning s -= size / 8;
386e853bc5dShenning /* Free up temp space. */
387e853bc5dShenning free(c->car);
388e853bc5dShenning free(c);
389e853bc5dShenning c = cdr;
390e853bc5dShenning }
391c824f21bShenning return (bufp);
392e853bc5dShenning }
393e853bc5dShenning
394c824f21bShenning void
convert_num(unsigned char * buf,char * str,int base,int size)395c824f21bShenning convert_num(unsigned char *buf, char *str, int base, int size)
396e853bc5dShenning {
3978e1c2028Sderaadt int negative = 0, tval, max;
398e853bc5dShenning u_int32_t val = 0;
39959cf623dSstevesk char *ptr = str;
400e853bc5dShenning
401e853bc5dShenning if (*ptr == '-') {
402e853bc5dShenning negative = 1;
403c824f21bShenning ptr++;
404e853bc5dShenning }
40559cf623dSstevesk
406e853bc5dShenning /* If base wasn't specified, figure it out from the data. */
407e853bc5dShenning if (!base) {
408e853bc5dShenning if (ptr[0] == '0') {
409e853bc5dShenning if (ptr[1] == 'x') {
410e853bc5dShenning base = 16;
411e853bc5dShenning ptr += 2;
4120101699dSderaadt } else if (isascii((unsigned char)ptr[1]) &&
4130101699dSderaadt isdigit((unsigned char)ptr[1])) {
414e853bc5dShenning base = 8;
415e853bc5dShenning ptr += 1;
416c824f21bShenning } else
417e853bc5dShenning base = 10;
418c824f21bShenning } else
419e853bc5dShenning base = 10;
420e853bc5dShenning }
42159cf623dSstevesk
422e853bc5dShenning do {
423e853bc5dShenning tval = *ptr++;
424e853bc5dShenning /* XXX assumes ASCII... */
425e853bc5dShenning if (tval >= 'a')
426e853bc5dShenning tval = tval - 'a' + 10;
427e853bc5dShenning else if (tval >= 'A')
428e853bc5dShenning tval = tval - 'A' + 10;
429e853bc5dShenning else if (tval >= '0')
430e853bc5dShenning tval -= '0';
431e853bc5dShenning else {
432c525a185Skrw log_warnx("Bogus number: %s.", str);
433e853bc5dShenning break;
434e853bc5dShenning }
435e853bc5dShenning if (tval >= base) {
436c525a185Skrw log_warnx("Bogus number: %s: digit %d not in base %d",
437e853bc5dShenning str, tval, base);
438e853bc5dShenning break;
439e853bc5dShenning }
440e853bc5dShenning val = val * base + tval;
441e853bc5dShenning } while (*ptr);
442e853bc5dShenning
443e853bc5dShenning if (negative)
444e853bc5dShenning max = (1 << (size - 1));
445e853bc5dShenning else
446e853bc5dShenning max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
447e853bc5dShenning if (val > max) {
448e853bc5dShenning switch (base) {
449e853bc5dShenning case 8:
450c525a185Skrw log_warnx("value %s%o exceeds max (%d) for precision.",
451e853bc5dShenning negative ? "-" : "", val, max);
452e853bc5dShenning break;
453e853bc5dShenning case 16:
454c525a185Skrw log_warnx("value %s%x exceeds max (%d) for precision.",
455e853bc5dShenning negative ? "-" : "", val, max);
456e853bc5dShenning break;
457e853bc5dShenning default:
458c525a185Skrw log_warnx("value %s%u exceeds max (%d) for precision.",
459e853bc5dShenning negative ? "-" : "", val, max);
460e853bc5dShenning break;
461e853bc5dShenning }
462e853bc5dShenning }
46359cf623dSstevesk
4648e1c2028Sderaadt if (negative) {
465e853bc5dShenning switch (size) {
466e853bc5dShenning case 8:
467e853bc5dShenning *buf = -(unsigned long)val;
468e853bc5dShenning break;
469e853bc5dShenning case 16:
470e853bc5dShenning putShort(buf, -(unsigned long)val);
471e853bc5dShenning break;
472e853bc5dShenning case 32:
473e853bc5dShenning putLong(buf, -(unsigned long)val);
474e853bc5dShenning break;
475e853bc5dShenning default:
476c525a185Skrw log_warnx("Unexpected integer size: %d", size);
477e853bc5dShenning break;
478e853bc5dShenning }
4798e1c2028Sderaadt } else {
480e853bc5dShenning switch (size) {
481e853bc5dShenning case 8:
482e853bc5dShenning *buf = (u_int8_t)val;
483e853bc5dShenning break;
484e853bc5dShenning case 16:
485e853bc5dShenning putUShort(buf, (u_int16_t)val);
486e853bc5dShenning break;
487e853bc5dShenning case 32:
488e853bc5dShenning putULong(buf, val);
489e853bc5dShenning break;
490e853bc5dShenning default:
491c525a185Skrw log_warnx("Unexpected integer size: %d", size);
492e853bc5dShenning break;
493e853bc5dShenning }
494e853bc5dShenning }
4958e1c2028Sderaadt }
496e853bc5dShenning
497c824f21bShenning /*
498c824f21bShenning * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
499ca617185Skrw * NUMBER COLON NUMBER COLON NUMBER UTC SEMI
500c824f21bShenning *
501ca617185Skrw * Dates are always in UTC; first number is day of week; next is
502c824f21bShenning * year/month/day; next is hours:minutes:seconds on a 24-hour
503c824f21bShenning * clock.
504c824f21bShenning */
505c824f21bShenning time_t
parse_date(FILE * cfile)506c824f21bShenning parse_date(FILE *cfile)
507e853bc5dShenning {
50859cf623dSstevesk struct tm tm;
509ca617185Skrw char timestr[26]; /* "w yyyy/mm/dd hh:mm:ss UTC" */
510ca617185Skrw char *val, *p;
511ca617185Skrw size_t n;
512ca617185Skrw time_t guess;
513ca617185Skrw int token;
514e853bc5dShenning
515ca617185Skrw memset(timestr, 0, sizeof(timestr));
516ca617185Skrw
517ca617185Skrw do {
518ca617185Skrw token = peek_token(NULL, cfile);
519ca617185Skrw switch (token) {
520ca617185Skrw case TOK_NAME:
521ca617185Skrw case TOK_NUMBER:
52211b1f78aSkrw case TOK_NUMBER_OR_NAME:
523ca617185Skrw case '/':
524ca617185Skrw case ':':
525e853bc5dShenning token = next_token(&val, cfile);
526ca617185Skrw n = strlcat(timestr, val, sizeof(timestr));
527ca617185Skrw if (n >= sizeof(timestr)) {
528ca617185Skrw /* XXX Will break after year 9999! */
529ca617185Skrw parse_warn("time string too long");
530e853bc5dShenning skip_to_semi(cfile);
53159cf623dSstevesk return (0);
532e853bc5dShenning }
533ca617185Skrw break;
534ca617185Skrw case';':
535ca617185Skrw break;
536ca617185Skrw default:
537ca617185Skrw parse_warn("invalid time string");
538e853bc5dShenning skip_to_semi(cfile);
53959cf623dSstevesk return (0);
540e853bc5dShenning }
541ca617185Skrw } while (token != ';');
542e853bc5dShenning
543ca617185Skrw parse_semi(cfile);
544ca617185Skrw
545ca617185Skrw memset(&tm, 0, sizeof(tm)); /* 'cuz strptime ignores tm_isdt. */
546ca617185Skrw p = strptime(timestr, DB_TIMEFMT, &tm);
547ca617185Skrw if (p == NULL || *p != '\0') {
548ca617185Skrw p = strptime(timestr, OLD_DB_TIMEFMT, &tm);
549ca617185Skrw if (p == NULL || *p != '\0') {
550ca617185Skrw parse_warn("unparseable time string");
551ca617185Skrw return (0);
552ca617185Skrw }
553ca617185Skrw }
554ca617185Skrw
555ca617185Skrw guess = timegm(&tm);
556ca617185Skrw if (guess == -1) {
557ca617185Skrw parse_warn("time could not be represented");
55859cf623dSstevesk return (0);
559e853bc5dShenning }
56059cf623dSstevesk
561c824f21bShenning return (guess);
562e853bc5dShenning }
563f0a65fa0Skrw
564c525a185Skrw int warnings_occurred;
565c525a185Skrw
566f0a65fa0Skrw int
parse_warn(char * fmt,...)567f0a65fa0Skrw parse_warn(char *fmt, ...)
568f0a65fa0Skrw {
569c525a185Skrw static char fbuf[1024];
570c525a185Skrw static char mbuf[1024];
571e1f80b9aSkrw static char spaces[81];
572f0a65fa0Skrw va_list list;
573e1f80b9aSkrw int i;
574f0a65fa0Skrw
575f0a65fa0Skrw snprintf(fbuf, sizeof(fbuf), "%s line %d: %s", tlname, lexline, mbuf);
576f0a65fa0Skrw va_start(list, fmt);
577f0a65fa0Skrw vsnprintf(mbuf, sizeof(mbuf), fbuf, list);
578f0a65fa0Skrw va_end(list);
579f0a65fa0Skrw
580c525a185Skrw log_warnx("%s", mbuf);
581c525a185Skrw log_warnx("%s", token_line);
582e1f80b9aSkrw if (lexchar < sizeof(spaces)) {
583e1f80b9aSkrw memset(spaces, 0, sizeof(spaces));
584e1f80b9aSkrw for (i = 0; i < lexchar - 1; i++) {
585e1f80b9aSkrw if (token_line[i] == '\t')
586e1f80b9aSkrw spaces[i] = '\t';
587e1f80b9aSkrw else
588e1f80b9aSkrw spaces[i] = ' ';
589f0a65fa0Skrw }
590e1f80b9aSkrw }
591e1f80b9aSkrw log_warnx("%s^", spaces);
592f0a65fa0Skrw
593f0a65fa0Skrw warnings_occurred = 1;
594f0a65fa0Skrw
595f0a65fa0Skrw return (0);
596f0a65fa0Skrw }
597