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