xref: /openbsd/usr.sbin/ldomctl/parse.y (revision 693255e2)
1*693255e2Skn /*	$OpenBSD: parse.y,v 1.16 2020/02/20 20:38:44 kn Exp $	*/
297d8cafcSkettenis 
397d8cafcSkettenis /*
497d8cafcSkettenis  * Copyright (c) 2012 Mark Kettenis <kettenis@openbsd.org>
597d8cafcSkettenis  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
697d8cafcSkettenis  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
797d8cafcSkettenis  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
897d8cafcSkettenis  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
997d8cafcSkettenis  *
1097d8cafcSkettenis  * Permission to use, copy, modify, and distribute this software for any
1197d8cafcSkettenis  * purpose with or without fee is hereby granted, provided that the above
1297d8cafcSkettenis  * copyright notice and this permission notice appear in all copies.
1397d8cafcSkettenis  *
1497d8cafcSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1597d8cafcSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1697d8cafcSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1797d8cafcSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1897d8cafcSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1997d8cafcSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2097d8cafcSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2197d8cafcSkettenis  */
2297d8cafcSkettenis 
2397d8cafcSkettenis %{
2497d8cafcSkettenis #include <sys/types.h>
2597d8cafcSkettenis #include <sys/socket.h>
2697d8cafcSkettenis #include <sys/queue.h>
2797d8cafcSkettenis 
2897d8cafcSkettenis #include <net/if.h>
2997d8cafcSkettenis #include <netinet/in.h>
3097d8cafcSkettenis #include <netinet/if_ether.h>
3197d8cafcSkettenis 
3297d8cafcSkettenis #include <ctype.h>
3397d8cafcSkettenis #include <err.h>
3497d8cafcSkettenis #include <errno.h>
3597d8cafcSkettenis #include <limits.h>
3697d8cafcSkettenis #include <stdarg.h>
3797d8cafcSkettenis #include <stdio.h>
3897d8cafcSkettenis #include <stdlib.h>
3997d8cafcSkettenis #include <string.h>
40d73a4c4fSkn #include <util.h>
4197d8cafcSkettenis 
4297d8cafcSkettenis #include "ldomctl.h"
43d73a4c4fSkn #include "ldom_util.h"
4497d8cafcSkettenis 
4597d8cafcSkettenis TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
4697d8cafcSkettenis static struct file {
4797d8cafcSkettenis 	TAILQ_ENTRY(file)	 entry;
4897d8cafcSkettenis 	FILE			*stream;
4997d8cafcSkettenis 	char			*name;
5097d8cafcSkettenis 	int			 lineno;
5197d8cafcSkettenis 	int			 errors;
5297d8cafcSkettenis } *file, *topfile;
5397d8cafcSkettenis struct file	*pushfile(const char *);
5497d8cafcSkettenis int		 popfile(void);
5597d8cafcSkettenis int		 yyparse(void);
5697d8cafcSkettenis int		 yylex(void);
570f79392cSdoug int		 yyerror(const char *, ...)
580f79392cSdoug     __attribute__((__format__ (printf, 1, 2)))
590f79392cSdoug     __attribute__((__nonnull__ (1)));
6097d8cafcSkettenis int		 kw_cmp(const void *, const void *);
6197d8cafcSkettenis int		 lookup(char *);
6297d8cafcSkettenis int		 lgetc(int);
6397d8cafcSkettenis int		 lungetc(int);
6497d8cafcSkettenis int		 findeol(void);
6597d8cafcSkettenis 
6697d8cafcSkettenis struct ldom_config		*conf;
6797d8cafcSkettenis 
6859eb6c85Skettenis struct vcpu_opts {
6959eb6c85Skettenis 	uint64_t	count;
7059eb6c85Skettenis 	uint64_t	stride;
7159eb6c85Skettenis } vcpu_opts;
7259eb6c85Skettenis 
73*693255e2Skn struct vdisk_opts {
74*693255e2Skn 	const char	*devalias;
75*693255e2Skn } vdisk_opts;
76*693255e2Skn 
7759eb6c85Skettenis struct vnet_opts {
7897d8cafcSkettenis 	uint64_t	mac_addr;
7997d8cafcSkettenis 	uint64_t	mtu;
8059eb6c85Skettenis } vnet_opts;
8159eb6c85Skettenis 
8259eb6c85Skettenis void		vcput_opts_default(void);
83*693255e2Skn void		vdisk_opts_default(void);
8459eb6c85Skettenis void		vnet_opts_default(void);
8597d8cafcSkettenis 
8697d8cafcSkettenis typedef struct {
8797d8cafcSkettenis 	union {
8897d8cafcSkettenis 		int64_t			 number;
8997d8cafcSkettenis 		char			*string;
9059eb6c85Skettenis 		struct vcpu_opts	 vcpu_opts;
91*693255e2Skn 		struct vdisk_opts	 vdisk_opts;
9259eb6c85Skettenis 		struct vnet_opts	 vnet_opts;
9397d8cafcSkettenis 	} v;
9497d8cafcSkettenis 	int lineno;
9597d8cafcSkettenis } YYSTYPE;
9697d8cafcSkettenis 
9797d8cafcSkettenis %}
9897d8cafcSkettenis 
9997d8cafcSkettenis %token	DOMAIN
100*693255e2Skn %token	VCPU MEMORY VDISK DEVALIAS VNET VARIABLE IODEVICE
10197d8cafcSkettenis %token	MAC_ADDR MTU
10297d8cafcSkettenis %token	ERROR
10397d8cafcSkettenis %token	<v.string>		STRING
10497d8cafcSkettenis %token	<v.number>		NUMBER
10597d8cafcSkettenis %type	<v.number>		memory
10659eb6c85Skettenis %type	<v.vcpu_opts>		vcpu
107*693255e2Skn %type	<v.vdisk_opts>		vdisk_opts vdisk_opts_l vdisk_opt
108*693255e2Skn %type	<v.vdisk_opts>		devalias
10959eb6c85Skettenis %type	<v.vnet_opts>		vnet_opts vnet_opts_l vnet_opt
11059eb6c85Skettenis %type	<v.vnet_opts>		mac_addr
11159eb6c85Skettenis %type	<v.vnet_opts>		mtu
11297d8cafcSkettenis %%
11397d8cafcSkettenis 
11497d8cafcSkettenis grammar		: /* empty */
11597d8cafcSkettenis 		| grammar '\n'
11697d8cafcSkettenis 		| grammar domain '\n'
11797d8cafcSkettenis 		| grammar error '\n'		{ file->errors++; }
11897d8cafcSkettenis 		;
11997d8cafcSkettenis 
12097d8cafcSkettenis domain		: DOMAIN STRING optnl '{' optnl	{
1214dacfa80Skn 			struct domain *odomain;
1224dacfa80Skn 			SIMPLEQ_FOREACH(odomain, &conf->domain_list, entry)
1234dacfa80Skn 				if (strcmp(odomain->name, $2) == 0) {
1244dacfa80Skn 					yyerror("duplicate domain name: %s", $2);
1254dacfa80Skn 					YYERROR;
1264dacfa80Skn 				}
12797d8cafcSkettenis 			domain = xzalloc(sizeof(struct domain));
12897d8cafcSkettenis 			domain->name = $2;
12997d8cafcSkettenis 			SIMPLEQ_INIT(&domain->vdisk_list);
13097d8cafcSkettenis 			SIMPLEQ_INIT(&domain->vnet_list);
1318e765095Skettenis 			SIMPLEQ_INIT(&domain->var_list);
1328cfaec25Skettenis 			SIMPLEQ_INIT(&domain->iodev_list);
13397d8cafcSkettenis 		}
13497d8cafcSkettenis 		    domainopts_l '}' {
135a4193c97Skn 			if (strcmp(domain->name, "primary") != 0) {
136a4193c97Skn 				if (domain->vcpu == 0) {
137a4193c97Skn 					yyerror("vcpu is required: %s",
138a4193c97Skn 					    domain->name);
139a4193c97Skn 					YYERROR;
140a4193c97Skn 				}
141a4193c97Skn 				if ( domain->memory == 0) {
142a4193c97Skn 					yyerror("memory is required: %s",
143a4193c97Skn 					    domain->name);
144a4193c97Skn 					YYERROR;
145a4193c97Skn 				}
146a4193c97Skn 				if (SIMPLEQ_EMPTY(&domain->vdisk_list) &&
147a4193c97Skn 				    SIMPLEQ_EMPTY(&domain->vnet_list) &&
148a4193c97Skn 				    SIMPLEQ_EMPTY(&domain->iodev_list)) {
149a4193c97Skn 					yyerror("at least one bootable device"
150a4193c97Skn 					    " is required: %s", domain->name);
151a4193c97Skn 					YYERROR;
152a4193c97Skn 				}
153a4193c97Skn 			}
15497d8cafcSkettenis 			SIMPLEQ_INSERT_TAIL(&conf->domain_list, domain, entry);
15597d8cafcSkettenis 			domain = NULL;
15697d8cafcSkettenis 		}
15797d8cafcSkettenis 		;
15897d8cafcSkettenis 
15997d8cafcSkettenis domainopts_l	: domainopts_l domainoptsl
16097d8cafcSkettenis 		| domainoptsl
16197d8cafcSkettenis 		;
16297d8cafcSkettenis 
16397d8cafcSkettenis domainoptsl	: domainopts nl
16497d8cafcSkettenis 		;
16597d8cafcSkettenis 
16659eb6c85Skettenis domainopts	: VCPU vcpu {
16759eb6c85Skettenis 			domain->vcpu = $2.count;
16859eb6c85Skettenis 			domain->vcpu_stride = $2.stride;
16997d8cafcSkettenis 		}
17097d8cafcSkettenis 		| MEMORY memory {
17197d8cafcSkettenis 			domain->memory = $2;
17297d8cafcSkettenis 		}
173*693255e2Skn 		| VDISK STRING vdisk_opts {
17497d8cafcSkettenis 			struct vdisk *vdisk = xmalloc(sizeof(struct vdisk));
17597d8cafcSkettenis 			vdisk->path = $2;
17697d8cafcSkettenis 			SIMPLEQ_INSERT_TAIL(&domain->vdisk_list, vdisk, entry);
17797d8cafcSkettenis 		}
17897d8cafcSkettenis 		| VNET vnet_opts {
17997d8cafcSkettenis 			struct vnet *vnet = xmalloc(sizeof(struct vnet));
18097d8cafcSkettenis 			vnet->mac_addr = $2.mac_addr;
18197d8cafcSkettenis 			vnet->mtu = $2.mtu;
18297d8cafcSkettenis 			SIMPLEQ_INSERT_TAIL(&domain->vnet_list, vnet, entry);
18397d8cafcSkettenis 		}
1848e765095Skettenis 		| VARIABLE STRING '=' STRING {
1858e765095Skettenis 			struct var *var = xmalloc(sizeof(struct var));
1868e765095Skettenis 			var->name = $2;
1878e765095Skettenis 			var->str = $4;
1888e765095Skettenis 			SIMPLEQ_INSERT_TAIL(&domain->var_list, var, entry);
1898e765095Skettenis 		}
1908cfaec25Skettenis 		| IODEVICE STRING {
1918cfaec25Skettenis 			struct iodev *iodev = xmalloc(sizeof(struct iodev));
1928cfaec25Skettenis 			iodev->path = $2;
1938cfaec25Skettenis 			SIMPLEQ_INSERT_TAIL(&domain->iodev_list, iodev, entry);
1948cfaec25Skettenis 		    }
19597d8cafcSkettenis 		;
19697d8cafcSkettenis 
197*693255e2Skn vdisk_opts	:	{ vdisk_opts_default(); }
198*693255e2Skn 		  vdisk_opts_l
199*693255e2Skn 			{ $$ = vdisk_opts; }
200*693255e2Skn 		|	{ vdisk_opts_default(); $$ = vdisk_opts; }
201*693255e2Skn 		;
202*693255e2Skn vdisk_opts_l	: vdisk_opts_l vdisk_opt
203*693255e2Skn 		| vdisk_opt
204*693255e2Skn 		;
205*693255e2Skn vdisk_opt	: devalias
206*693255e2Skn 		;
207*693255e2Skn 
208*693255e2Skn devalias	: DEVALIAS '=' STRING {
209*693255e2Skn 			vdisk_opts.devalias = $3;
210*693255e2Skn 		}
211*693255e2Skn 		;
212*693255e2Skn 
21359eb6c85Skettenis vnet_opts	:	{ vnet_opts_default(); }
21497d8cafcSkettenis 		  vnet_opts_l
21559eb6c85Skettenis 			{ $$ = vnet_opts; }
21659eb6c85Skettenis 		|	{ vnet_opts_default(); $$ = vnet_opts; }
21797d8cafcSkettenis 		;
21897d8cafcSkettenis vnet_opts_l	: vnet_opts_l vnet_opt
21997d8cafcSkettenis 		| vnet_opt
22097d8cafcSkettenis 		;
22197d8cafcSkettenis vnet_opt	: mac_addr
22297d8cafcSkettenis 		| mtu
22397d8cafcSkettenis 		;
22497d8cafcSkettenis 
22597d8cafcSkettenis mac_addr	: MAC_ADDR '=' STRING {
22697d8cafcSkettenis 			struct ether_addr *ea;
22797d8cafcSkettenis 
22897d8cafcSkettenis 			if ((ea = ether_aton($3)) == NULL) {
22932cf627cSotto 				yyerror("invalid address: %s", $3);
23097d8cafcSkettenis 				YYERROR;
23197d8cafcSkettenis 			}
23297d8cafcSkettenis 
23359eb6c85Skettenis 			vnet_opts.mac_addr =
23497d8cafcSkettenis 			    (uint64_t)ea->ether_addr_octet[0] << 40 |
23597d8cafcSkettenis 			    (uint64_t)ea->ether_addr_octet[1] << 32 |
23697d8cafcSkettenis 			    ea->ether_addr_octet[2] << 24 |
23797d8cafcSkettenis 			    ea->ether_addr_octet[3] << 16 |
23897d8cafcSkettenis 			    ea->ether_addr_octet[4] << 8 |
23997d8cafcSkettenis 			    ea->ether_addr_octet[5];
24097d8cafcSkettenis 		}
24197d8cafcSkettenis 		;
24297d8cafcSkettenis 
24397d8cafcSkettenis mtu		: MTU '=' NUMBER {
24459eb6c85Skettenis 			vnet_opts.mtu = $3;
24559eb6c85Skettenis 		}
24659eb6c85Skettenis 		;
24759eb6c85Skettenis 
24859eb6c85Skettenis vcpu		: STRING {
24959eb6c85Skettenis 			const char *errstr;
25059eb6c85Skettenis 			char *colon;
25159eb6c85Skettenis 
25259eb6c85Skettenis 			vcpu_opts_default();
25359eb6c85Skettenis 			colon = strchr($1, ':');
25459eb6c85Skettenis 			if (colon == NULL) {
25559eb6c85Skettenis 				yyerror("bogus stride in %s", $1);
25659eb6c85Skettenis 				YYERROR;
25759eb6c85Skettenis 			}
25859eb6c85Skettenis 			*colon++ = '\0';
25959eb6c85Skettenis 			vcpu_opts.count = strtonum($1, 0, INT_MAX, &errstr);
26059eb6c85Skettenis 			if (errstr) {
26159eb6c85Skettenis 				yyerror("number %s is %s", $1, errstr);
26259eb6c85Skettenis 				YYERROR;
26359eb6c85Skettenis 			}
26459eb6c85Skettenis 			vcpu_opts.stride = strtonum(colon, 0, INT_MAX, &errstr);
26559eb6c85Skettenis 			if (errstr) {
26659eb6c85Skettenis 				yyerror("number %s is %s", colon, errstr);
26759eb6c85Skettenis 				YYERROR;
26859eb6c85Skettenis 			}
26959eb6c85Skettenis 			$$ = vcpu_opts;
27059eb6c85Skettenis 		}
27159eb6c85Skettenis 		| NUMBER {
27259eb6c85Skettenis 			vcpu_opts_default();
27359eb6c85Skettenis 			vcpu_opts.count = $1;
27459eb6c85Skettenis 			$$ = vcpu_opts;
27597d8cafcSkettenis 		}
27697d8cafcSkettenis 		;
27797d8cafcSkettenis 
27897d8cafcSkettenis memory		: NUMBER {
27997d8cafcSkettenis 			$$ = $1;
28097d8cafcSkettenis 		}
28197d8cafcSkettenis 		| STRING {
282d73a4c4fSkn 			if (scan_scaled($1, &$$) == -1) {
283d73a4c4fSkn 				yyerror("invalid size: %s", $1);
28497d8cafcSkettenis 				YYERROR;
28597d8cafcSkettenis 			}
28697d8cafcSkettenis 		}
28797d8cafcSkettenis 		;
28897d8cafcSkettenis 
28997d8cafcSkettenis optnl		: '\n' optnl
29097d8cafcSkettenis 		|
29197d8cafcSkettenis 		;
29297d8cafcSkettenis 
29397d8cafcSkettenis nl		: '\n' optnl		/* one newline or more */
29497d8cafcSkettenis 		;
29597d8cafcSkettenis 
29697d8cafcSkettenis %%
29797d8cafcSkettenis 
29897d8cafcSkettenis void
29959eb6c85Skettenis vcpu_opts_default(void)
30097d8cafcSkettenis {
30159eb6c85Skettenis 	vcpu_opts.count = -1;
30259eb6c85Skettenis 	vcpu_opts.stride = 1;
30359eb6c85Skettenis }
30459eb6c85Skettenis 
30559eb6c85Skettenis void
306*693255e2Skn vdisk_opts_default(void)
307*693255e2Skn {
308*693255e2Skn 	vdisk_opts.devalias = NULL;
309*693255e2Skn }
310*693255e2Skn 
311*693255e2Skn void
31259eb6c85Skettenis vnet_opts_default(void)
31359eb6c85Skettenis {
31459eb6c85Skettenis 	vnet_opts.mac_addr = -1;
31559eb6c85Skettenis 	vnet_opts.mtu = 1500;
31697d8cafcSkettenis }
31797d8cafcSkettenis 
31897d8cafcSkettenis struct keywords {
31997d8cafcSkettenis 	const char	*k_name;
32097d8cafcSkettenis 	int		 k_val;
32197d8cafcSkettenis };
32297d8cafcSkettenis 
32397d8cafcSkettenis int
32497d8cafcSkettenis yyerror(const char *fmt, ...)
32597d8cafcSkettenis {
32697d8cafcSkettenis 	va_list		 ap;
32797d8cafcSkettenis 
32897d8cafcSkettenis 	file->errors++;
32997d8cafcSkettenis 	va_start(ap, fmt);
33097d8cafcSkettenis 	fprintf(stderr, "%s:%d ", file->name, yylval.lineno);
33197d8cafcSkettenis 	vfprintf(stderr, fmt, ap);
33297d8cafcSkettenis 	fprintf(stderr, "\n");
33397d8cafcSkettenis 	va_end(ap);
33497d8cafcSkettenis 	return (0);
33597d8cafcSkettenis }
33697d8cafcSkettenis 
33797d8cafcSkettenis int
33897d8cafcSkettenis kw_cmp(const void *k, const void *e)
33997d8cafcSkettenis {
34097d8cafcSkettenis 	return (strcmp(k, ((const struct keywords *)e)->k_name));
34197d8cafcSkettenis }
34297d8cafcSkettenis 
34397d8cafcSkettenis int
34497d8cafcSkettenis lookup(char *s)
34597d8cafcSkettenis {
34697d8cafcSkettenis 	/* this has to be sorted always */
34797d8cafcSkettenis 	static const struct keywords keywords[] = {
348*693255e2Skn 		{ "devalias",		DEVALIAS},
34997d8cafcSkettenis 		{ "domain",		DOMAIN},
3508cfaec25Skettenis 		{ "iodevice",		IODEVICE},
35197d8cafcSkettenis 		{ "mac-addr",		MAC_ADDR},
35297d8cafcSkettenis 		{ "memory",		MEMORY},
35397d8cafcSkettenis 		{ "mtu",		MTU},
3548e765095Skettenis 		{ "variable",		VARIABLE},
35597d8cafcSkettenis 		{ "vcpu",		VCPU},
35697d8cafcSkettenis 		{ "vdisk",		VDISK},
35797d8cafcSkettenis 		{ "vnet",		VNET}
35897d8cafcSkettenis 	};
35997d8cafcSkettenis 	const struct keywords	*p;
36097d8cafcSkettenis 
36197d8cafcSkettenis 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
36297d8cafcSkettenis 	    sizeof(keywords[0]), kw_cmp);
36397d8cafcSkettenis 
36497d8cafcSkettenis 	if (p)
36597d8cafcSkettenis 		return (p->k_val);
36697d8cafcSkettenis 	else
36797d8cafcSkettenis 		return (STRING);
36897d8cafcSkettenis }
36997d8cafcSkettenis 
37097d8cafcSkettenis #define MAXPUSHBACK	128
37197d8cafcSkettenis 
372015d7b4dSbenno u_char	*parsebuf;
37397d8cafcSkettenis int	 parseindex;
374015d7b4dSbenno u_char	 pushback_buffer[MAXPUSHBACK];
37597d8cafcSkettenis int	 pushback_index = 0;
37697d8cafcSkettenis 
37797d8cafcSkettenis int
37897d8cafcSkettenis lgetc(int quotec)
37997d8cafcSkettenis {
38097d8cafcSkettenis 	int		c, next;
38197d8cafcSkettenis 
38297d8cafcSkettenis 	if (parsebuf) {
38397d8cafcSkettenis 		/* Read character from the parsebuffer instead of input. */
38497d8cafcSkettenis 		if (parseindex >= 0) {
38597d8cafcSkettenis 			c = parsebuf[parseindex++];
38697d8cafcSkettenis 			if (c != '\0')
38797d8cafcSkettenis 				return (c);
38897d8cafcSkettenis 			parsebuf = NULL;
38997d8cafcSkettenis 		} else
39097d8cafcSkettenis 			parseindex++;
39197d8cafcSkettenis 	}
39297d8cafcSkettenis 
39397d8cafcSkettenis 	if (pushback_index)
39497d8cafcSkettenis 		return (pushback_buffer[--pushback_index]);
39597d8cafcSkettenis 
39697d8cafcSkettenis 	if (quotec) {
39797d8cafcSkettenis 		if ((c = getc(file->stream)) == EOF) {
39897d8cafcSkettenis 			yyerror("reached end of file while parsing "
39997d8cafcSkettenis 			    "quoted string");
40097d8cafcSkettenis 			if (file == topfile || popfile() == EOF)
40197d8cafcSkettenis 				return (EOF);
40297d8cafcSkettenis 			return (quotec);
40397d8cafcSkettenis 		}
40497d8cafcSkettenis 		return (c);
40597d8cafcSkettenis 	}
40697d8cafcSkettenis 
40797d8cafcSkettenis 	while ((c = getc(file->stream)) == '\\') {
40897d8cafcSkettenis 		next = getc(file->stream);
40997d8cafcSkettenis 		if (next != '\n') {
41097d8cafcSkettenis 			c = next;
41197d8cafcSkettenis 			break;
41297d8cafcSkettenis 		}
41397d8cafcSkettenis 		yylval.lineno = file->lineno;
41497d8cafcSkettenis 		file->lineno++;
41597d8cafcSkettenis 	}
41697d8cafcSkettenis 
41797d8cafcSkettenis 	while (c == EOF) {
41897d8cafcSkettenis 		if (file == topfile || popfile() == EOF)
41997d8cafcSkettenis 			return (EOF);
42097d8cafcSkettenis 		c = getc(file->stream);
42197d8cafcSkettenis 	}
42297d8cafcSkettenis 	return (c);
42397d8cafcSkettenis }
42497d8cafcSkettenis 
42597d8cafcSkettenis int
42697d8cafcSkettenis lungetc(int c)
42797d8cafcSkettenis {
42897d8cafcSkettenis 	if (c == EOF)
42997d8cafcSkettenis 		return (EOF);
43097d8cafcSkettenis 	if (parsebuf) {
43197d8cafcSkettenis 		parseindex--;
43297d8cafcSkettenis 		if (parseindex >= 0)
43397d8cafcSkettenis 			return (c);
43497d8cafcSkettenis 	}
43597d8cafcSkettenis 	if (pushback_index < MAXPUSHBACK-1)
43697d8cafcSkettenis 		return (pushback_buffer[pushback_index++] = c);
43797d8cafcSkettenis 	else
43897d8cafcSkettenis 		return (EOF);
43997d8cafcSkettenis }
44097d8cafcSkettenis 
44197d8cafcSkettenis int
44297d8cafcSkettenis findeol(void)
44397d8cafcSkettenis {
44497d8cafcSkettenis 	int	c;
44597d8cafcSkettenis 
44697d8cafcSkettenis 	parsebuf = NULL;
44797d8cafcSkettenis 
44897d8cafcSkettenis 	/* skip to either EOF or the first real EOL */
44997d8cafcSkettenis 	while (1) {
45097d8cafcSkettenis 		if (pushback_index)
45197d8cafcSkettenis 			c = pushback_buffer[--pushback_index];
45297d8cafcSkettenis 		else
45397d8cafcSkettenis 			c = lgetc(0);
45497d8cafcSkettenis 		if (c == '\n') {
45597d8cafcSkettenis 			file->lineno++;
45697d8cafcSkettenis 			break;
45797d8cafcSkettenis 		}
45897d8cafcSkettenis 		if (c == EOF)
45997d8cafcSkettenis 			break;
46097d8cafcSkettenis 	}
46197d8cafcSkettenis 	return (ERROR);
46297d8cafcSkettenis }
46397d8cafcSkettenis 
46497d8cafcSkettenis int
46597d8cafcSkettenis yylex(void)
46697d8cafcSkettenis {
467015d7b4dSbenno 	u_char	 buf[8096];
468015d7b4dSbenno 	u_char	*p;
46997d8cafcSkettenis 	int	 quotec, next, c;
47097d8cafcSkettenis 	int	 token;
47197d8cafcSkettenis 
47297d8cafcSkettenis 	p = buf;
47397d8cafcSkettenis 	while ((c = lgetc(0)) == ' ' || c == '\t')
47497d8cafcSkettenis 		; /* nothing */
47597d8cafcSkettenis 
47697d8cafcSkettenis 	yylval.lineno = file->lineno;
47797d8cafcSkettenis 	if (c == '#')
47897d8cafcSkettenis 		while ((c = lgetc(0)) != '\n' && c != EOF)
47997d8cafcSkettenis 			; /* nothing */
48097d8cafcSkettenis 
48197d8cafcSkettenis 	switch (c) {
48297d8cafcSkettenis 	case '\'':
48397d8cafcSkettenis 	case '"':
48497d8cafcSkettenis 		quotec = c;
48597d8cafcSkettenis 		while (1) {
48697d8cafcSkettenis 			if ((c = lgetc(quotec)) == EOF)
48797d8cafcSkettenis 				return (0);
48897d8cafcSkettenis 			if (c == '\n') {
48997d8cafcSkettenis 				file->lineno++;
49097d8cafcSkettenis 				continue;
49197d8cafcSkettenis 			} else if (c == '\\') {
49297d8cafcSkettenis 				if ((next = lgetc(quotec)) == EOF)
49397d8cafcSkettenis 					return (0);
494a1533359Ssashan 				if (next == quotec || next == ' ' ||
495a1533359Ssashan 				    next == '\t')
49697d8cafcSkettenis 					c = next;
49797d8cafcSkettenis 				else if (next == '\n') {
49897d8cafcSkettenis 					file->lineno++;
49997d8cafcSkettenis 					continue;
50097d8cafcSkettenis 				} else
50197d8cafcSkettenis 					lungetc(next);
50297d8cafcSkettenis 			} else if (c == quotec) {
50397d8cafcSkettenis 				*p = '\0';
50497d8cafcSkettenis 				break;
50541eef22fSjsg 			} else if (c == '\0') {
50641eef22fSjsg 				yyerror("syntax error");
50741eef22fSjsg 				return (findeol());
50897d8cafcSkettenis 			}
50997d8cafcSkettenis 			if (p + 1 >= buf + sizeof(buf) - 1) {
51097d8cafcSkettenis 				yyerror("string too long");
51197d8cafcSkettenis 				return (findeol());
51297d8cafcSkettenis 			}
513015d7b4dSbenno 			*p++ = c;
51497d8cafcSkettenis 		}
51597d8cafcSkettenis 		yylval.v.string = xstrdup(buf);
51697d8cafcSkettenis 		return (STRING);
51797d8cafcSkettenis 	}
51897d8cafcSkettenis 
51997d8cafcSkettenis #define allowed_to_end_number(x) \
52097d8cafcSkettenis 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
52197d8cafcSkettenis 
52297d8cafcSkettenis 	if (c == '-' || isdigit(c)) {
52397d8cafcSkettenis 		do {
52497d8cafcSkettenis 			*p++ = c;
525915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
52697d8cafcSkettenis 				yyerror("string too long");
52797d8cafcSkettenis 				return (findeol());
52897d8cafcSkettenis 			}
52997d8cafcSkettenis 		} while ((c = lgetc(0)) != EOF && isdigit(c));
53097d8cafcSkettenis 		lungetc(c);
53197d8cafcSkettenis 		if (p == buf + 1 && buf[0] == '-')
53297d8cafcSkettenis 			goto nodigits;
53397d8cafcSkettenis 		if (c == EOF || allowed_to_end_number(c)) {
53497d8cafcSkettenis 			const char *errstr = NULL;
53597d8cafcSkettenis 
53697d8cafcSkettenis 			*p = '\0';
53797d8cafcSkettenis 			yylval.v.number = strtonum(buf, LLONG_MIN,
53897d8cafcSkettenis 			    LLONG_MAX, &errstr);
53997d8cafcSkettenis 			if (errstr) {
54097d8cafcSkettenis 				yyerror("\"%s\" invalid number: %s",
54197d8cafcSkettenis 				    buf, errstr);
54297d8cafcSkettenis 				return (findeol());
54397d8cafcSkettenis 			}
54497d8cafcSkettenis 			return (NUMBER);
54597d8cafcSkettenis 		} else {
54697d8cafcSkettenis nodigits:
54797d8cafcSkettenis 			while (p > buf + 1)
54897d8cafcSkettenis 				lungetc(*--p);
54997d8cafcSkettenis 			c = *--p;
55097d8cafcSkettenis 			if (c == '-')
55197d8cafcSkettenis 				return (c);
55297d8cafcSkettenis 		}
55397d8cafcSkettenis 	}
55497d8cafcSkettenis 
55597d8cafcSkettenis #define allowed_in_string(x) \
55697d8cafcSkettenis 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
55797d8cafcSkettenis 	x != '{' && x != '}' && x != '<' && x != '>' && \
55897d8cafcSkettenis 	x != '!' && x != '=' && x != '/' && x != '#' && \
55997d8cafcSkettenis 	x != ','))
56097d8cafcSkettenis 
56197d8cafcSkettenis 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
56297d8cafcSkettenis 		do {
56397d8cafcSkettenis 			*p++ = c;
564915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
56597d8cafcSkettenis 				yyerror("string too long");
56697d8cafcSkettenis 				return (findeol());
56797d8cafcSkettenis 			}
56897d8cafcSkettenis 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
56997d8cafcSkettenis 		lungetc(c);
57097d8cafcSkettenis 		*p = '\0';
57197d8cafcSkettenis 		if ((token = lookup(buf)) == STRING)
57297d8cafcSkettenis 			yylval.v.string = xstrdup(buf);
57397d8cafcSkettenis 		return (token);
57497d8cafcSkettenis 	}
57597d8cafcSkettenis 	if (c == '\n') {
57697d8cafcSkettenis 		yylval.lineno = file->lineno;
57797d8cafcSkettenis 		file->lineno++;
57897d8cafcSkettenis 	}
57997d8cafcSkettenis 	if (c == EOF)
58097d8cafcSkettenis 		return (0);
58197d8cafcSkettenis 	return (c);
58297d8cafcSkettenis }
58397d8cafcSkettenis 
58497d8cafcSkettenis struct file *
58597d8cafcSkettenis pushfile(const char *name)
58697d8cafcSkettenis {
58797d8cafcSkettenis 	struct file	*nfile;
58897d8cafcSkettenis 
58997d8cafcSkettenis 	nfile = xzalloc(sizeof(struct file));
59097d8cafcSkettenis 	nfile->name = xstrdup(name);
59197d8cafcSkettenis 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
5926a3d55f9Skrw 		warn("%s: %s", __func__, nfile->name);
59397d8cafcSkettenis 		free(nfile->name);
59497d8cafcSkettenis 		free(nfile);
59597d8cafcSkettenis 		return (NULL);
59697d8cafcSkettenis 	}
59797d8cafcSkettenis 	nfile->lineno = 1;
59897d8cafcSkettenis 	TAILQ_INSERT_TAIL(&files, nfile, entry);
59997d8cafcSkettenis 	return (nfile);
60097d8cafcSkettenis }
60197d8cafcSkettenis 
60297d8cafcSkettenis int
60397d8cafcSkettenis popfile(void)
60497d8cafcSkettenis {
60597d8cafcSkettenis 	struct file	*prev;
60697d8cafcSkettenis 
60797d8cafcSkettenis 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
60897d8cafcSkettenis 		prev->errors += file->errors;
60997d8cafcSkettenis 
61097d8cafcSkettenis 	TAILQ_REMOVE(&files, file, entry);
61197d8cafcSkettenis 	fclose(file->stream);
61297d8cafcSkettenis 	free(file->name);
61397d8cafcSkettenis 	free(file);
61497d8cafcSkettenis 	file = prev;
61597d8cafcSkettenis 	return (file ? 0 : EOF);
61697d8cafcSkettenis }
61797d8cafcSkettenis 
61897d8cafcSkettenis int
61997d8cafcSkettenis parse_config(const char *filename, struct ldom_config *xconf)
62097d8cafcSkettenis {
62197d8cafcSkettenis 	int		 errors = 0;
62297d8cafcSkettenis 
62397d8cafcSkettenis 	conf = xconf;
62497d8cafcSkettenis 
62597d8cafcSkettenis 	if ((file = pushfile(filename)) == NULL) {
62697d8cafcSkettenis 		return (-1);
62797d8cafcSkettenis 	}
62897d8cafcSkettenis 	topfile = file;
62997d8cafcSkettenis 
63097d8cafcSkettenis 	yyparse();
63197d8cafcSkettenis 	errors = file->errors;
63297d8cafcSkettenis 	popfile();
63397d8cafcSkettenis 
63497d8cafcSkettenis 	return (errors ? -1 : 0);
63597d8cafcSkettenis }
636