xref: /openbsd/usr.sbin/ldomctl/parse.y (revision ee96180d)
1*ee96180dSkn /*	$OpenBSD: parse.y,v 1.25 2022/10/06 21:35:52 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;
6753681a8bSkn struct domain			*domain;
6897d8cafcSkettenis 
6959eb6c85Skettenis struct vcpu_opts {
7059eb6c85Skettenis 	uint64_t	count;
7159eb6c85Skettenis 	uint64_t	stride;
7259eb6c85Skettenis } vcpu_opts;
7359eb6c85Skettenis 
74693255e2Skn struct vdisk_opts {
75693255e2Skn 	const char	*devalias;
76693255e2Skn } vdisk_opts;
77693255e2Skn 
7859eb6c85Skettenis struct vnet_opts {
7997d8cafcSkettenis 	uint64_t	mac_addr;
8097d8cafcSkettenis 	uint64_t	mtu;
81a3b2112fSkn 	const char	*devalias;
8259eb6c85Skettenis } vnet_opts;
8359eb6c85Skettenis 
8451179309Skn void		vcpu_opts_default(void);
85693255e2Skn void		vdisk_opts_default(void);
8659eb6c85Skettenis void		vnet_opts_default(void);
8797d8cafcSkettenis 
8897d8cafcSkettenis typedef struct {
8997d8cafcSkettenis 	union {
9097d8cafcSkettenis 		int64_t			 number;
9197d8cafcSkettenis 		char			*string;
9259eb6c85Skettenis 		struct vcpu_opts	 vcpu_opts;
93693255e2Skn 		struct vdisk_opts	 vdisk_opts;
9459eb6c85Skettenis 		struct vnet_opts	 vnet_opts;
9597d8cafcSkettenis 	} v;
9697d8cafcSkettenis 	int lineno;
9797d8cafcSkettenis } YYSTYPE;
9897d8cafcSkettenis 
9997d8cafcSkettenis %}
10097d8cafcSkettenis 
10197d8cafcSkettenis %token	DOMAIN
102693255e2Skn %token	VCPU MEMORY VDISK DEVALIAS VNET VARIABLE IODEVICE
10397d8cafcSkettenis %token	MAC_ADDR MTU
10497d8cafcSkettenis %token	ERROR
10597d8cafcSkettenis %token	<v.string>		STRING
10697d8cafcSkettenis %token	<v.number>		NUMBER
10797d8cafcSkettenis %type	<v.number>		memory
10859eb6c85Skettenis %type	<v.vcpu_opts>		vcpu
109693255e2Skn %type	<v.vdisk_opts>		vdisk_opts vdisk_opts_l vdisk_opt
110a3b2112fSkn %type	<v.vdisk_opts>		vdisk_devalias
11159eb6c85Skettenis %type	<v.vnet_opts>		vnet_opts vnet_opts_l vnet_opt
11259eb6c85Skettenis %type	<v.vnet_opts>		mac_addr
11359eb6c85Skettenis %type	<v.vnet_opts>		mtu
114a3b2112fSkn %type	<v.vnet_opts>		vnet_devalias
11597d8cafcSkettenis %%
11697d8cafcSkettenis 
11797d8cafcSkettenis grammar		: /* empty */
11897d8cafcSkettenis 		| grammar '\n'
11997d8cafcSkettenis 		| grammar domain '\n'
12097d8cafcSkettenis 		| grammar error '\n'		{ file->errors++; }
12197d8cafcSkettenis 		;
12297d8cafcSkettenis 
12397d8cafcSkettenis domain		: DOMAIN STRING optnl '{' optnl	{
1244dacfa80Skn 			struct domain *odomain;
1254dacfa80Skn 			SIMPLEQ_FOREACH(odomain, &conf->domain_list, entry)
1264dacfa80Skn 				if (strcmp(odomain->name, $2) == 0) {
1274dacfa80Skn 					yyerror("duplicate domain name: %s", $2);
1284dacfa80Skn 					YYERROR;
1294dacfa80Skn 				}
13097d8cafcSkettenis 			domain = xzalloc(sizeof(struct domain));
13197d8cafcSkettenis 			domain->name = $2;
13297d8cafcSkettenis 			SIMPLEQ_INIT(&domain->vdisk_list);
13397d8cafcSkettenis 			SIMPLEQ_INIT(&domain->vnet_list);
1348e765095Skettenis 			SIMPLEQ_INIT(&domain->var_list);
1358cfaec25Skettenis 			SIMPLEQ_INIT(&domain->iodev_list);
13697d8cafcSkettenis 		}
13797d8cafcSkettenis 		    domainopts_l '}' {
138a4193c97Skn 			if (strcmp(domain->name, "primary") != 0) {
139a4193c97Skn 				if (domain->vcpu == 0) {
140a4193c97Skn 					yyerror("vcpu is required: %s",
141a4193c97Skn 					    domain->name);
142a4193c97Skn 					YYERROR;
143a4193c97Skn 				}
144a4193c97Skn 				if ( domain->memory == 0) {
145a4193c97Skn 					yyerror("memory is required: %s",
146a4193c97Skn 					    domain->name);
147a4193c97Skn 					YYERROR;
148a4193c97Skn 				}
149a4193c97Skn 				if (SIMPLEQ_EMPTY(&domain->vdisk_list) &&
150a4193c97Skn 				    SIMPLEQ_EMPTY(&domain->vnet_list) &&
151a4193c97Skn 				    SIMPLEQ_EMPTY(&domain->iodev_list)) {
152a4193c97Skn 					yyerror("at least one bootable device"
153a4193c97Skn 					    " is required: %s", domain->name);
154a4193c97Skn 					YYERROR;
155a4193c97Skn 				}
156a4193c97Skn 			}
15797d8cafcSkettenis 			SIMPLEQ_INSERT_TAIL(&conf->domain_list, domain, entry);
15897d8cafcSkettenis 			domain = NULL;
15997d8cafcSkettenis 		}
16097d8cafcSkettenis 		;
16197d8cafcSkettenis 
16297d8cafcSkettenis domainopts_l	: domainopts_l domainoptsl
16397d8cafcSkettenis 		| domainoptsl
16497d8cafcSkettenis 		;
16597d8cafcSkettenis 
16697d8cafcSkettenis domainoptsl	: domainopts nl
16797d8cafcSkettenis 		;
16897d8cafcSkettenis 
16959eb6c85Skettenis domainopts	: VCPU vcpu {
170da59641dSkn 			if (domain->vcpu) {
171da59641dSkn 				yyerror("duplicate vcpu option");
172da59641dSkn 				YYERROR;
173da59641dSkn 			}
17459eb6c85Skettenis 			domain->vcpu = $2.count;
17559eb6c85Skettenis 			domain->vcpu_stride = $2.stride;
17697d8cafcSkettenis 		}
17797d8cafcSkettenis 		| MEMORY memory {
178da59641dSkn 			if (domain->memory) {
179da59641dSkn 				yyerror("duplicate memory option");
180da59641dSkn 				YYERROR;
181da59641dSkn 			}
18297d8cafcSkettenis 			domain->memory = $2;
18397d8cafcSkettenis 		}
184693255e2Skn 		| VDISK STRING vdisk_opts {
185ae0acb23Skn 			if (strcmp(domain->name, "primary") == 0) {
186ae0acb23Skn 				yyerror("vdisk option invalid for primary"
187ae0acb23Skn 				    " domain");
188ae0acb23Skn 				YYERROR;
189ae0acb23Skn 			}
19097d8cafcSkettenis 			struct vdisk *vdisk = xmalloc(sizeof(struct vdisk));
19197d8cafcSkettenis 			vdisk->path = $2;
192b37e2bbcSkn 			vdisk->devalias = $3.devalias;
19397d8cafcSkettenis 			SIMPLEQ_INSERT_TAIL(&domain->vdisk_list, vdisk, entry);
19497d8cafcSkettenis 		}
19597d8cafcSkettenis 		| VNET vnet_opts {
196ae0acb23Skn 			if (strcmp(domain->name, "primary") == 0) {
197ae0acb23Skn 				yyerror("vnet option invalid for primary"
198ae0acb23Skn 				    " domain");
199ae0acb23Skn 				YYERROR;
200ae0acb23Skn 			}
20197d8cafcSkettenis 			struct vnet *vnet = xmalloc(sizeof(struct vnet));
20297d8cafcSkettenis 			vnet->mac_addr = $2.mac_addr;
20397d8cafcSkettenis 			vnet->mtu = $2.mtu;
204a3b2112fSkn 			vnet->devalias = $2.devalias;
20597d8cafcSkettenis 			SIMPLEQ_INSERT_TAIL(&domain->vnet_list, vnet, entry);
20697d8cafcSkettenis 		}
2078e765095Skettenis 		| VARIABLE STRING '=' STRING {
2088e765095Skettenis 			struct var *var = xmalloc(sizeof(struct var));
2098e765095Skettenis 			var->name = $2;
2108e765095Skettenis 			var->str = $4;
2118e765095Skettenis 			SIMPLEQ_INSERT_TAIL(&domain->var_list, var, entry);
2128e765095Skettenis 		}
2138cfaec25Skettenis 		| IODEVICE STRING {
214ae0acb23Skn 			if (strcmp(domain->name, "primary") == 0) {
215ae0acb23Skn 				yyerror("iodevice option invalid for primary"
216ae0acb23Skn 				    " domain");
217ae0acb23Skn 				YYERROR;
218ae0acb23Skn 			}
219da59641dSkn 			struct domain *odomain;
220da59641dSkn 			struct iodev *iodev;
221da59641dSkn 			SIMPLEQ_FOREACH(odomain, &conf->domain_list, entry)
222da59641dSkn 				SIMPLEQ_FOREACH(iodev, &odomain->iodev_list, entry)
223*ee96180dSkn 					if (strcmp(iodev->dev, $2) == 0) {
224da59641dSkn 						yyerror("iodevice %s already"
2258efa5877Skn 						    " assigned", $2);
226da59641dSkn 						YYERROR;
227da59641dSkn 					}
228da59641dSkn 			iodev = xmalloc(sizeof(struct iodev));
229*ee96180dSkn 			iodev->dev = $2;
2308cfaec25Skettenis 			SIMPLEQ_INSERT_TAIL(&domain->iodev_list, iodev, entry);
2318cfaec25Skettenis 		}
23297d8cafcSkettenis 		;
23397d8cafcSkettenis 
234693255e2Skn vdisk_opts	:	{ vdisk_opts_default(); }
235693255e2Skn 		  vdisk_opts_l
236693255e2Skn 			{ $$ = vdisk_opts; }
237693255e2Skn 		|	{ vdisk_opts_default(); $$ = vdisk_opts; }
238693255e2Skn 		;
239693255e2Skn vdisk_opts_l	: vdisk_opts_l vdisk_opt
240693255e2Skn 		| vdisk_opt
241693255e2Skn 		;
242a3b2112fSkn vdisk_opt	: vdisk_devalias
243693255e2Skn 		;
244693255e2Skn 
245a3b2112fSkn vdisk_devalias	: DEVALIAS '=' STRING {
246693255e2Skn 			vdisk_opts.devalias = $3;
247693255e2Skn 		}
248693255e2Skn 		;
249693255e2Skn 
25059eb6c85Skettenis vnet_opts	:	{ vnet_opts_default(); }
25197d8cafcSkettenis 		  vnet_opts_l
25259eb6c85Skettenis 			{ $$ = vnet_opts; }
25359eb6c85Skettenis 		|	{ vnet_opts_default(); $$ = vnet_opts; }
25497d8cafcSkettenis 		;
25597d8cafcSkettenis vnet_opts_l	: vnet_opts_l vnet_opt
25697d8cafcSkettenis 		| vnet_opt
25797d8cafcSkettenis 		;
25897d8cafcSkettenis vnet_opt	: mac_addr
25997d8cafcSkettenis 		| mtu
260a3b2112fSkn 		| vnet_devalias
26197d8cafcSkettenis 		;
26297d8cafcSkettenis 
26397d8cafcSkettenis mac_addr	: MAC_ADDR '=' STRING {
26497d8cafcSkettenis 			struct ether_addr *ea;
26597d8cafcSkettenis 
26697d8cafcSkettenis 			if ((ea = ether_aton($3)) == NULL) {
26732cf627cSotto 				yyerror("invalid address: %s", $3);
26897d8cafcSkettenis 				YYERROR;
26997d8cafcSkettenis 			}
27097d8cafcSkettenis 
27159eb6c85Skettenis 			vnet_opts.mac_addr =
27297d8cafcSkettenis 			    (uint64_t)ea->ether_addr_octet[0] << 40 |
27397d8cafcSkettenis 			    (uint64_t)ea->ether_addr_octet[1] << 32 |
27497d8cafcSkettenis 			    ea->ether_addr_octet[2] << 24 |
27597d8cafcSkettenis 			    ea->ether_addr_octet[3] << 16 |
27697d8cafcSkettenis 			    ea->ether_addr_octet[4] << 8 |
27797d8cafcSkettenis 			    ea->ether_addr_octet[5];
27897d8cafcSkettenis 		}
27997d8cafcSkettenis 		;
28097d8cafcSkettenis 
28197d8cafcSkettenis mtu		: MTU '=' NUMBER {
28259eb6c85Skettenis 			vnet_opts.mtu = $3;
28359eb6c85Skettenis 		}
28459eb6c85Skettenis 		;
28559eb6c85Skettenis 
286a3b2112fSkn vnet_devalias	: DEVALIAS '=' STRING {
287a3b2112fSkn 			vnet_opts.devalias = $3;
288a3b2112fSkn 		}
289a3b2112fSkn 		;
290a3b2112fSkn 
29159eb6c85Skettenis vcpu		: STRING {
29259eb6c85Skettenis 			const char *errstr;
29359eb6c85Skettenis 			char *colon;
29459eb6c85Skettenis 
29559eb6c85Skettenis 			vcpu_opts_default();
29659eb6c85Skettenis 			colon = strchr($1, ':');
29759eb6c85Skettenis 			if (colon == NULL) {
29859eb6c85Skettenis 				yyerror("bogus stride in %s", $1);
29959eb6c85Skettenis 				YYERROR;
30059eb6c85Skettenis 			}
30159eb6c85Skettenis 			*colon++ = '\0';
30259eb6c85Skettenis 			vcpu_opts.count = strtonum($1, 0, INT_MAX, &errstr);
30359eb6c85Skettenis 			if (errstr) {
30459eb6c85Skettenis 				yyerror("number %s is %s", $1, errstr);
30559eb6c85Skettenis 				YYERROR;
30659eb6c85Skettenis 			}
30759eb6c85Skettenis 			vcpu_opts.stride = strtonum(colon, 0, INT_MAX, &errstr);
30859eb6c85Skettenis 			if (errstr) {
30959eb6c85Skettenis 				yyerror("number %s is %s", colon, errstr);
31059eb6c85Skettenis 				YYERROR;
31159eb6c85Skettenis 			}
31259eb6c85Skettenis 			$$ = vcpu_opts;
31359eb6c85Skettenis 		}
31459eb6c85Skettenis 		| NUMBER {
31559eb6c85Skettenis 			vcpu_opts_default();
31659eb6c85Skettenis 			vcpu_opts.count = $1;
31759eb6c85Skettenis 			$$ = vcpu_opts;
31897d8cafcSkettenis 		}
31997d8cafcSkettenis 		;
32097d8cafcSkettenis 
32197d8cafcSkettenis memory		: NUMBER {
32297d8cafcSkettenis 			$$ = $1;
32397d8cafcSkettenis 		}
32497d8cafcSkettenis 		| STRING {
325d73a4c4fSkn 			if (scan_scaled($1, &$$) == -1) {
326d73a4c4fSkn 				yyerror("invalid size: %s", $1);
32797d8cafcSkettenis 				YYERROR;
32897d8cafcSkettenis 			}
32997d8cafcSkettenis 		}
33097d8cafcSkettenis 		;
33197d8cafcSkettenis 
33297d8cafcSkettenis optnl		: '\n' optnl
33397d8cafcSkettenis 		|
33497d8cafcSkettenis 		;
33597d8cafcSkettenis 
33697d8cafcSkettenis nl		: '\n' optnl		/* one newline or more */
33797d8cafcSkettenis 		;
33897d8cafcSkettenis 
33997d8cafcSkettenis %%
34097d8cafcSkettenis 
34197d8cafcSkettenis void
34259eb6c85Skettenis vcpu_opts_default(void)
34397d8cafcSkettenis {
34459eb6c85Skettenis 	vcpu_opts.count = -1;
34559eb6c85Skettenis 	vcpu_opts.stride = 1;
34659eb6c85Skettenis }
34759eb6c85Skettenis 
34859eb6c85Skettenis void
vdisk_opts_default(void)349693255e2Skn vdisk_opts_default(void)
350693255e2Skn {
351693255e2Skn 	vdisk_opts.devalias = NULL;
352693255e2Skn }
353693255e2Skn 
354693255e2Skn void
vnet_opts_default(void)35559eb6c85Skettenis vnet_opts_default(void)
35659eb6c85Skettenis {
35759eb6c85Skettenis 	vnet_opts.mac_addr = -1;
35859eb6c85Skettenis 	vnet_opts.mtu = 1500;
359a3b2112fSkn 	vnet_opts.devalias = NULL;
36097d8cafcSkettenis }
36197d8cafcSkettenis 
36297d8cafcSkettenis struct keywords {
36397d8cafcSkettenis 	const char	*k_name;
36497d8cafcSkettenis 	int		 k_val;
36597d8cafcSkettenis };
36697d8cafcSkettenis 
36797d8cafcSkettenis int
yyerror(const char * fmt,...)36897d8cafcSkettenis yyerror(const char *fmt, ...)
36997d8cafcSkettenis {
37097d8cafcSkettenis 	va_list		 ap;
37197d8cafcSkettenis 
37297d8cafcSkettenis 	file->errors++;
37397d8cafcSkettenis 	va_start(ap, fmt);
37497d8cafcSkettenis 	fprintf(stderr, "%s:%d ", file->name, yylval.lineno);
37597d8cafcSkettenis 	vfprintf(stderr, fmt, ap);
37697d8cafcSkettenis 	fprintf(stderr, "\n");
37797d8cafcSkettenis 	va_end(ap);
37897d8cafcSkettenis 	return (0);
37997d8cafcSkettenis }
38097d8cafcSkettenis 
38197d8cafcSkettenis int
kw_cmp(const void * k,const void * e)38297d8cafcSkettenis kw_cmp(const void *k, const void *e)
38397d8cafcSkettenis {
38497d8cafcSkettenis 	return (strcmp(k, ((const struct keywords *)e)->k_name));
38597d8cafcSkettenis }
38697d8cafcSkettenis 
38797d8cafcSkettenis int
lookup(char * s)38897d8cafcSkettenis lookup(char *s)
38997d8cafcSkettenis {
39097d8cafcSkettenis 	/* this has to be sorted always */
39197d8cafcSkettenis 	static const struct keywords keywords[] = {
392693255e2Skn 		{ "devalias",		DEVALIAS},
39397d8cafcSkettenis 		{ "domain",		DOMAIN},
3948cfaec25Skettenis 		{ "iodevice",		IODEVICE},
39597d8cafcSkettenis 		{ "mac-addr",		MAC_ADDR},
39697d8cafcSkettenis 		{ "memory",		MEMORY},
39797d8cafcSkettenis 		{ "mtu",		MTU},
3988e765095Skettenis 		{ "variable",		VARIABLE},
39997d8cafcSkettenis 		{ "vcpu",		VCPU},
40097d8cafcSkettenis 		{ "vdisk",		VDISK},
40197d8cafcSkettenis 		{ "vnet",		VNET}
40297d8cafcSkettenis 	};
40397d8cafcSkettenis 	const struct keywords	*p;
40497d8cafcSkettenis 
40597d8cafcSkettenis 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
40697d8cafcSkettenis 	    sizeof(keywords[0]), kw_cmp);
40797d8cafcSkettenis 
40897d8cafcSkettenis 	if (p)
40997d8cafcSkettenis 		return (p->k_val);
41097d8cafcSkettenis 	else
41197d8cafcSkettenis 		return (STRING);
41297d8cafcSkettenis }
41397d8cafcSkettenis 
41497d8cafcSkettenis #define MAXPUSHBACK	128
41597d8cafcSkettenis 
41608f6ba19Snaddy char	*parsebuf;
41797d8cafcSkettenis int	 parseindex;
41808f6ba19Snaddy char	 pushback_buffer[MAXPUSHBACK];
41997d8cafcSkettenis int	 pushback_index = 0;
42097d8cafcSkettenis 
42197d8cafcSkettenis int
lgetc(int quotec)42297d8cafcSkettenis lgetc(int quotec)
42397d8cafcSkettenis {
42497d8cafcSkettenis 	int		c, next;
42597d8cafcSkettenis 
42697d8cafcSkettenis 	if (parsebuf) {
42797d8cafcSkettenis 		/* Read character from the parsebuffer instead of input. */
42897d8cafcSkettenis 		if (parseindex >= 0) {
42908f6ba19Snaddy 			c = (unsigned char)parsebuf[parseindex++];
43097d8cafcSkettenis 			if (c != '\0')
43197d8cafcSkettenis 				return (c);
43297d8cafcSkettenis 			parsebuf = NULL;
43397d8cafcSkettenis 		} else
43497d8cafcSkettenis 			parseindex++;
43597d8cafcSkettenis 	}
43697d8cafcSkettenis 
43797d8cafcSkettenis 	if (pushback_index)
43808f6ba19Snaddy 		return ((unsigned char)pushback_buffer[--pushback_index]);
43997d8cafcSkettenis 
44097d8cafcSkettenis 	if (quotec) {
44197d8cafcSkettenis 		if ((c = getc(file->stream)) == EOF) {
44297d8cafcSkettenis 			yyerror("reached end of file while parsing "
44397d8cafcSkettenis 			    "quoted string");
44497d8cafcSkettenis 			if (file == topfile || popfile() == EOF)
44597d8cafcSkettenis 				return (EOF);
44697d8cafcSkettenis 			return (quotec);
44797d8cafcSkettenis 		}
44897d8cafcSkettenis 		return (c);
44997d8cafcSkettenis 	}
45097d8cafcSkettenis 
45197d8cafcSkettenis 	while ((c = getc(file->stream)) == '\\') {
45297d8cafcSkettenis 		next = getc(file->stream);
45397d8cafcSkettenis 		if (next != '\n') {
45497d8cafcSkettenis 			c = next;
45597d8cafcSkettenis 			break;
45697d8cafcSkettenis 		}
45797d8cafcSkettenis 		yylval.lineno = file->lineno;
45897d8cafcSkettenis 		file->lineno++;
45997d8cafcSkettenis 	}
46097d8cafcSkettenis 
46197d8cafcSkettenis 	while (c == EOF) {
46297d8cafcSkettenis 		if (file == topfile || popfile() == EOF)
46397d8cafcSkettenis 			return (EOF);
46497d8cafcSkettenis 		c = getc(file->stream);
46597d8cafcSkettenis 	}
46697d8cafcSkettenis 	return (c);
46797d8cafcSkettenis }
46897d8cafcSkettenis 
46997d8cafcSkettenis int
lungetc(int c)47097d8cafcSkettenis lungetc(int c)
47197d8cafcSkettenis {
47297d8cafcSkettenis 	if (c == EOF)
47397d8cafcSkettenis 		return (EOF);
47497d8cafcSkettenis 	if (parsebuf) {
47597d8cafcSkettenis 		parseindex--;
47697d8cafcSkettenis 		if (parseindex >= 0)
47797d8cafcSkettenis 			return (c);
47897d8cafcSkettenis 	}
47908f6ba19Snaddy 	if (pushback_index + 1 >= MAXPUSHBACK)
48097d8cafcSkettenis 		return (EOF);
48108f6ba19Snaddy 	pushback_buffer[pushback_index++] = c;
48208f6ba19Snaddy 	return (c);
48397d8cafcSkettenis }
48497d8cafcSkettenis 
48597d8cafcSkettenis int
findeol(void)48697d8cafcSkettenis findeol(void)
48797d8cafcSkettenis {
48897d8cafcSkettenis 	int	c;
48997d8cafcSkettenis 
49097d8cafcSkettenis 	parsebuf = NULL;
49197d8cafcSkettenis 
49297d8cafcSkettenis 	/* skip to either EOF or the first real EOL */
49397d8cafcSkettenis 	while (1) {
49497d8cafcSkettenis 		if (pushback_index)
49508f6ba19Snaddy 			c = (unsigned char)pushback_buffer[--pushback_index];
49697d8cafcSkettenis 		else
49797d8cafcSkettenis 			c = lgetc(0);
49897d8cafcSkettenis 		if (c == '\n') {
49997d8cafcSkettenis 			file->lineno++;
50097d8cafcSkettenis 			break;
50197d8cafcSkettenis 		}
50297d8cafcSkettenis 		if (c == EOF)
50397d8cafcSkettenis 			break;
50497d8cafcSkettenis 	}
50597d8cafcSkettenis 	return (ERROR);
50697d8cafcSkettenis }
50797d8cafcSkettenis 
50897d8cafcSkettenis int
yylex(void)50997d8cafcSkettenis yylex(void)
51097d8cafcSkettenis {
51108f6ba19Snaddy 	char	 buf[8096];
51208f6ba19Snaddy 	char	*p;
51397d8cafcSkettenis 	int	 quotec, next, c;
51497d8cafcSkettenis 	int	 token;
51597d8cafcSkettenis 
51697d8cafcSkettenis 	p = buf;
51797d8cafcSkettenis 	while ((c = lgetc(0)) == ' ' || c == '\t')
51897d8cafcSkettenis 		; /* nothing */
51997d8cafcSkettenis 
52097d8cafcSkettenis 	yylval.lineno = file->lineno;
52197d8cafcSkettenis 	if (c == '#')
52297d8cafcSkettenis 		while ((c = lgetc(0)) != '\n' && c != EOF)
52397d8cafcSkettenis 			; /* nothing */
52497d8cafcSkettenis 
52597d8cafcSkettenis 	switch (c) {
52697d8cafcSkettenis 	case '\'':
52797d8cafcSkettenis 	case '"':
52897d8cafcSkettenis 		quotec = c;
52997d8cafcSkettenis 		while (1) {
53097d8cafcSkettenis 			if ((c = lgetc(quotec)) == EOF)
53197d8cafcSkettenis 				return (0);
53297d8cafcSkettenis 			if (c == '\n') {
53397d8cafcSkettenis 				file->lineno++;
53497d8cafcSkettenis 				continue;
53597d8cafcSkettenis 			} else if (c == '\\') {
53697d8cafcSkettenis 				if ((next = lgetc(quotec)) == EOF)
53797d8cafcSkettenis 					return (0);
538a1533359Ssashan 				if (next == quotec || next == ' ' ||
539a1533359Ssashan 				    next == '\t')
54097d8cafcSkettenis 					c = next;
54197d8cafcSkettenis 				else if (next == '\n') {
54297d8cafcSkettenis 					file->lineno++;
54397d8cafcSkettenis 					continue;
54497d8cafcSkettenis 				} else
54597d8cafcSkettenis 					lungetc(next);
54697d8cafcSkettenis 			} else if (c == quotec) {
54797d8cafcSkettenis 				*p = '\0';
54897d8cafcSkettenis 				break;
54941eef22fSjsg 			} else if (c == '\0') {
55041eef22fSjsg 				yyerror("syntax error");
55141eef22fSjsg 				return (findeol());
55297d8cafcSkettenis 			}
55397d8cafcSkettenis 			if (p + 1 >= buf + sizeof(buf) - 1) {
55497d8cafcSkettenis 				yyerror("string too long");
55597d8cafcSkettenis 				return (findeol());
55697d8cafcSkettenis 			}
557015d7b4dSbenno 			*p++ = c;
55897d8cafcSkettenis 		}
55997d8cafcSkettenis 		yylval.v.string = xstrdup(buf);
56097d8cafcSkettenis 		return (STRING);
56197d8cafcSkettenis 	}
56297d8cafcSkettenis 
56397d8cafcSkettenis #define allowed_to_end_number(x) \
56497d8cafcSkettenis 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
56597d8cafcSkettenis 
56697d8cafcSkettenis 	if (c == '-' || isdigit(c)) {
56797d8cafcSkettenis 		do {
56897d8cafcSkettenis 			*p++ = c;
569915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
57097d8cafcSkettenis 				yyerror("string too long");
57197d8cafcSkettenis 				return (findeol());
57297d8cafcSkettenis 			}
57397d8cafcSkettenis 		} while ((c = lgetc(0)) != EOF && isdigit(c));
57497d8cafcSkettenis 		lungetc(c);
57597d8cafcSkettenis 		if (p == buf + 1 && buf[0] == '-')
57697d8cafcSkettenis 			goto nodigits;
57797d8cafcSkettenis 		if (c == EOF || allowed_to_end_number(c)) {
57897d8cafcSkettenis 			const char *errstr = NULL;
57997d8cafcSkettenis 
58097d8cafcSkettenis 			*p = '\0';
58197d8cafcSkettenis 			yylval.v.number = strtonum(buf, LLONG_MIN,
58297d8cafcSkettenis 			    LLONG_MAX, &errstr);
58397d8cafcSkettenis 			if (errstr) {
58497d8cafcSkettenis 				yyerror("\"%s\" invalid number: %s",
58597d8cafcSkettenis 				    buf, errstr);
58697d8cafcSkettenis 				return (findeol());
58797d8cafcSkettenis 			}
58897d8cafcSkettenis 			return (NUMBER);
58997d8cafcSkettenis 		} else {
59097d8cafcSkettenis nodigits:
59197d8cafcSkettenis 			while (p > buf + 1)
59208f6ba19Snaddy 				lungetc((unsigned char)*--p);
59308f6ba19Snaddy 			c = (unsigned char)*--p;
59497d8cafcSkettenis 			if (c == '-')
59597d8cafcSkettenis 				return (c);
59697d8cafcSkettenis 		}
59797d8cafcSkettenis 	}
59897d8cafcSkettenis 
59997d8cafcSkettenis #define allowed_in_string(x) \
60097d8cafcSkettenis 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
60197d8cafcSkettenis 	x != '{' && x != '}' && x != '<' && x != '>' && \
60297d8cafcSkettenis 	x != '!' && x != '=' && x != '/' && x != '#' && \
60397d8cafcSkettenis 	x != ','))
60497d8cafcSkettenis 
60597d8cafcSkettenis 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
60697d8cafcSkettenis 		do {
60797d8cafcSkettenis 			*p++ = c;
608915c3f33Sderaadt 			if ((size_t)(p-buf) >= sizeof(buf)) {
60997d8cafcSkettenis 				yyerror("string too long");
61097d8cafcSkettenis 				return (findeol());
61197d8cafcSkettenis 			}
61297d8cafcSkettenis 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
61397d8cafcSkettenis 		lungetc(c);
61497d8cafcSkettenis 		*p = '\0';
61597d8cafcSkettenis 		if ((token = lookup(buf)) == STRING)
61697d8cafcSkettenis 			yylval.v.string = xstrdup(buf);
61797d8cafcSkettenis 		return (token);
61897d8cafcSkettenis 	}
61997d8cafcSkettenis 	if (c == '\n') {
62097d8cafcSkettenis 		yylval.lineno = file->lineno;
62197d8cafcSkettenis 		file->lineno++;
62297d8cafcSkettenis 	}
62397d8cafcSkettenis 	if (c == EOF)
62497d8cafcSkettenis 		return (0);
62597d8cafcSkettenis 	return (c);
62697d8cafcSkettenis }
62797d8cafcSkettenis 
62897d8cafcSkettenis struct file *
pushfile(const char * name)62997d8cafcSkettenis pushfile(const char *name)
63097d8cafcSkettenis {
63197d8cafcSkettenis 	struct file	*nfile;
63297d8cafcSkettenis 
63397d8cafcSkettenis 	nfile = xzalloc(sizeof(struct file));
63497d8cafcSkettenis 	nfile->name = xstrdup(name);
63597d8cafcSkettenis 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
6366a3d55f9Skrw 		warn("%s: %s", __func__, nfile->name);
63797d8cafcSkettenis 		free(nfile->name);
63897d8cafcSkettenis 		free(nfile);
63997d8cafcSkettenis 		return (NULL);
64097d8cafcSkettenis 	}
64197d8cafcSkettenis 	nfile->lineno = 1;
64297d8cafcSkettenis 	TAILQ_INSERT_TAIL(&files, nfile, entry);
64397d8cafcSkettenis 	return (nfile);
64497d8cafcSkettenis }
64597d8cafcSkettenis 
64697d8cafcSkettenis int
popfile(void)64797d8cafcSkettenis popfile(void)
64897d8cafcSkettenis {
64997d8cafcSkettenis 	struct file	*prev;
65097d8cafcSkettenis 
65197d8cafcSkettenis 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
65297d8cafcSkettenis 		prev->errors += file->errors;
65397d8cafcSkettenis 
65497d8cafcSkettenis 	TAILQ_REMOVE(&files, file, entry);
65597d8cafcSkettenis 	fclose(file->stream);
65697d8cafcSkettenis 	free(file->name);
65797d8cafcSkettenis 	free(file);
65897d8cafcSkettenis 	file = prev;
65997d8cafcSkettenis 	return (file ? 0 : EOF);
66097d8cafcSkettenis }
66197d8cafcSkettenis 
66297d8cafcSkettenis int
parse_config(const char * filename,struct ldom_config * xconf)66397d8cafcSkettenis parse_config(const char *filename, struct ldom_config *xconf)
66497d8cafcSkettenis {
66597d8cafcSkettenis 	int		 errors = 0;
66697d8cafcSkettenis 
66797d8cafcSkettenis 	conf = xconf;
66897d8cafcSkettenis 
66997d8cafcSkettenis 	if ((file = pushfile(filename)) == NULL) {
67097d8cafcSkettenis 		return (-1);
67197d8cafcSkettenis 	}
67297d8cafcSkettenis 	topfile = file;
67397d8cafcSkettenis 
67497d8cafcSkettenis 	yyparse();
67597d8cafcSkettenis 	errors = file->errors;
67697d8cafcSkettenis 	popfile();
67797d8cafcSkettenis 
67897d8cafcSkettenis 	return (errors ? -1 : 0);
67997d8cafcSkettenis }
680