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