1*ae0acb23Skn /* $OpenBSD: parse.y,v 1.21 2020/06/29 17:58:58 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 73693255e2Skn struct vdisk_opts { 74693255e2Skn const char *devalias; 75693255e2Skn } vdisk_opts; 76693255e2Skn 7759eb6c85Skettenis struct vnet_opts { 7897d8cafcSkettenis uint64_t mac_addr; 7997d8cafcSkettenis uint64_t mtu; 80a3b2112fSkn const char *devalias; 8159eb6c85Skettenis } vnet_opts; 8259eb6c85Skettenis 8359eb6c85Skettenis void vcput_opts_default(void); 84693255e2Skn void vdisk_opts_default(void); 8559eb6c85Skettenis void vnet_opts_default(void); 8697d8cafcSkettenis 8797d8cafcSkettenis typedef struct { 8897d8cafcSkettenis union { 8997d8cafcSkettenis int64_t number; 9097d8cafcSkettenis char *string; 9159eb6c85Skettenis struct vcpu_opts vcpu_opts; 92693255e2Skn struct vdisk_opts vdisk_opts; 9359eb6c85Skettenis struct vnet_opts vnet_opts; 9497d8cafcSkettenis } v; 9597d8cafcSkettenis int lineno; 9697d8cafcSkettenis } YYSTYPE; 9797d8cafcSkettenis 9897d8cafcSkettenis %} 9997d8cafcSkettenis 10097d8cafcSkettenis %token DOMAIN 101693255e2Skn %token VCPU MEMORY VDISK DEVALIAS VNET VARIABLE IODEVICE 10297d8cafcSkettenis %token MAC_ADDR MTU 10397d8cafcSkettenis %token ERROR 10497d8cafcSkettenis %token <v.string> STRING 10597d8cafcSkettenis %token <v.number> NUMBER 10697d8cafcSkettenis %type <v.number> memory 10759eb6c85Skettenis %type <v.vcpu_opts> vcpu 108693255e2Skn %type <v.vdisk_opts> vdisk_opts vdisk_opts_l vdisk_opt 109a3b2112fSkn %type <v.vdisk_opts> vdisk_devalias 11059eb6c85Skettenis %type <v.vnet_opts> vnet_opts vnet_opts_l vnet_opt 11159eb6c85Skettenis %type <v.vnet_opts> mac_addr 11259eb6c85Skettenis %type <v.vnet_opts> mtu 113a3b2112fSkn %type <v.vnet_opts> vnet_devalias 11497d8cafcSkettenis %% 11597d8cafcSkettenis 11697d8cafcSkettenis grammar : /* empty */ 11797d8cafcSkettenis | grammar '\n' 11897d8cafcSkettenis | grammar domain '\n' 11997d8cafcSkettenis | grammar error '\n' { file->errors++; } 12097d8cafcSkettenis ; 12197d8cafcSkettenis 12297d8cafcSkettenis domain : DOMAIN STRING optnl '{' optnl { 1234dacfa80Skn struct domain *odomain; 1244dacfa80Skn SIMPLEQ_FOREACH(odomain, &conf->domain_list, entry) 1254dacfa80Skn if (strcmp(odomain->name, $2) == 0) { 1264dacfa80Skn yyerror("duplicate domain name: %s", $2); 1274dacfa80Skn YYERROR; 1284dacfa80Skn } 12997d8cafcSkettenis domain = xzalloc(sizeof(struct domain)); 13097d8cafcSkettenis domain->name = $2; 13197d8cafcSkettenis SIMPLEQ_INIT(&domain->vdisk_list); 13297d8cafcSkettenis SIMPLEQ_INIT(&domain->vnet_list); 1338e765095Skettenis SIMPLEQ_INIT(&domain->var_list); 1348cfaec25Skettenis SIMPLEQ_INIT(&domain->iodev_list); 13597d8cafcSkettenis } 13697d8cafcSkettenis domainopts_l '}' { 137a4193c97Skn if (strcmp(domain->name, "primary") != 0) { 138a4193c97Skn if (domain->vcpu == 0) { 139a4193c97Skn yyerror("vcpu is required: %s", 140a4193c97Skn domain->name); 141a4193c97Skn YYERROR; 142a4193c97Skn } 143a4193c97Skn if ( domain->memory == 0) { 144a4193c97Skn yyerror("memory is required: %s", 145a4193c97Skn domain->name); 146a4193c97Skn YYERROR; 147a4193c97Skn } 148a4193c97Skn if (SIMPLEQ_EMPTY(&domain->vdisk_list) && 149a4193c97Skn SIMPLEQ_EMPTY(&domain->vnet_list) && 150a4193c97Skn SIMPLEQ_EMPTY(&domain->iodev_list)) { 151a4193c97Skn yyerror("at least one bootable device" 152a4193c97Skn " is required: %s", domain->name); 153a4193c97Skn YYERROR; 154a4193c97Skn } 155a4193c97Skn } 15697d8cafcSkettenis SIMPLEQ_INSERT_TAIL(&conf->domain_list, domain, entry); 15797d8cafcSkettenis domain = NULL; 15897d8cafcSkettenis } 15997d8cafcSkettenis ; 16097d8cafcSkettenis 16197d8cafcSkettenis domainopts_l : domainopts_l domainoptsl 16297d8cafcSkettenis | domainoptsl 16397d8cafcSkettenis ; 16497d8cafcSkettenis 16597d8cafcSkettenis domainoptsl : domainopts nl 16697d8cafcSkettenis ; 16797d8cafcSkettenis 16859eb6c85Skettenis domainopts : VCPU vcpu { 169da59641dSkn if (domain->vcpu) { 170da59641dSkn yyerror("duplicate vcpu option"); 171da59641dSkn YYERROR; 172da59641dSkn } 17359eb6c85Skettenis domain->vcpu = $2.count; 17459eb6c85Skettenis domain->vcpu_stride = $2.stride; 17597d8cafcSkettenis } 17697d8cafcSkettenis | MEMORY memory { 177da59641dSkn if (domain->memory) { 178da59641dSkn yyerror("duplicate memory option"); 179da59641dSkn YYERROR; 180da59641dSkn } 18197d8cafcSkettenis domain->memory = $2; 18297d8cafcSkettenis } 183693255e2Skn | VDISK STRING vdisk_opts { 184*ae0acb23Skn if (strcmp(domain->name, "primary") == 0) { 185*ae0acb23Skn yyerror("vdisk option invalid for primary" 186*ae0acb23Skn " domain"); 187*ae0acb23Skn YYERROR; 188*ae0acb23Skn } 18997d8cafcSkettenis struct vdisk *vdisk = xmalloc(sizeof(struct vdisk)); 19097d8cafcSkettenis vdisk->path = $2; 191b37e2bbcSkn vdisk->devalias = $3.devalias; 19297d8cafcSkettenis SIMPLEQ_INSERT_TAIL(&domain->vdisk_list, vdisk, entry); 19397d8cafcSkettenis } 19497d8cafcSkettenis | VNET vnet_opts { 195*ae0acb23Skn if (strcmp(domain->name, "primary") == 0) { 196*ae0acb23Skn yyerror("vnet option invalid for primary" 197*ae0acb23Skn " domain"); 198*ae0acb23Skn YYERROR; 199*ae0acb23Skn } 20097d8cafcSkettenis struct vnet *vnet = xmalloc(sizeof(struct vnet)); 20197d8cafcSkettenis vnet->mac_addr = $2.mac_addr; 20297d8cafcSkettenis vnet->mtu = $2.mtu; 203a3b2112fSkn vnet->devalias = $2.devalias; 20497d8cafcSkettenis SIMPLEQ_INSERT_TAIL(&domain->vnet_list, vnet, entry); 20597d8cafcSkettenis } 2068e765095Skettenis | VARIABLE STRING '=' STRING { 2078e765095Skettenis struct var *var = xmalloc(sizeof(struct var)); 2088e765095Skettenis var->name = $2; 2098e765095Skettenis var->str = $4; 2108e765095Skettenis SIMPLEQ_INSERT_TAIL(&domain->var_list, var, entry); 2118e765095Skettenis } 2128cfaec25Skettenis | IODEVICE STRING { 213*ae0acb23Skn if (strcmp(domain->name, "primary") == 0) { 214*ae0acb23Skn yyerror("iodevice option invalid for primary" 215*ae0acb23Skn " domain"); 216*ae0acb23Skn YYERROR; 217*ae0acb23Skn } 218da59641dSkn struct domain *odomain; 219da59641dSkn struct iodev *iodev; 220da59641dSkn SIMPLEQ_FOREACH(odomain, &conf->domain_list, entry) 221da59641dSkn SIMPLEQ_FOREACH(iodev, &odomain->iodev_list, entry) 222da59641dSkn if (strcmp(iodev->path, $2) == 0) { 223da59641dSkn yyerror("iodevice %s already" 2248efa5877Skn " assigned", $2); 225da59641dSkn YYERROR; 226da59641dSkn } 227da59641dSkn iodev = xmalloc(sizeof(struct iodev)); 2288cfaec25Skettenis iodev->path = $2; 2298cfaec25Skettenis SIMPLEQ_INSERT_TAIL(&domain->iodev_list, iodev, entry); 2308cfaec25Skettenis } 23197d8cafcSkettenis ; 23297d8cafcSkettenis 233693255e2Skn vdisk_opts : { vdisk_opts_default(); } 234693255e2Skn vdisk_opts_l 235693255e2Skn { $$ = vdisk_opts; } 236693255e2Skn | { vdisk_opts_default(); $$ = vdisk_opts; } 237693255e2Skn ; 238693255e2Skn vdisk_opts_l : vdisk_opts_l vdisk_opt 239693255e2Skn | vdisk_opt 240693255e2Skn ; 241a3b2112fSkn vdisk_opt : vdisk_devalias 242693255e2Skn ; 243693255e2Skn 244a3b2112fSkn vdisk_devalias : DEVALIAS '=' STRING { 245693255e2Skn vdisk_opts.devalias = $3; 246693255e2Skn } 247693255e2Skn ; 248693255e2Skn 24959eb6c85Skettenis vnet_opts : { vnet_opts_default(); } 25097d8cafcSkettenis vnet_opts_l 25159eb6c85Skettenis { $$ = vnet_opts; } 25259eb6c85Skettenis | { vnet_opts_default(); $$ = vnet_opts; } 25397d8cafcSkettenis ; 25497d8cafcSkettenis vnet_opts_l : vnet_opts_l vnet_opt 25597d8cafcSkettenis | vnet_opt 25697d8cafcSkettenis ; 25797d8cafcSkettenis vnet_opt : mac_addr 25897d8cafcSkettenis | mtu 259a3b2112fSkn | vnet_devalias 26097d8cafcSkettenis ; 26197d8cafcSkettenis 26297d8cafcSkettenis mac_addr : MAC_ADDR '=' STRING { 26397d8cafcSkettenis struct ether_addr *ea; 26497d8cafcSkettenis 26597d8cafcSkettenis if ((ea = ether_aton($3)) == NULL) { 26632cf627cSotto yyerror("invalid address: %s", $3); 26797d8cafcSkettenis YYERROR; 26897d8cafcSkettenis } 26997d8cafcSkettenis 27059eb6c85Skettenis vnet_opts.mac_addr = 27197d8cafcSkettenis (uint64_t)ea->ether_addr_octet[0] << 40 | 27297d8cafcSkettenis (uint64_t)ea->ether_addr_octet[1] << 32 | 27397d8cafcSkettenis ea->ether_addr_octet[2] << 24 | 27497d8cafcSkettenis ea->ether_addr_octet[3] << 16 | 27597d8cafcSkettenis ea->ether_addr_octet[4] << 8 | 27697d8cafcSkettenis ea->ether_addr_octet[5]; 27797d8cafcSkettenis } 27897d8cafcSkettenis ; 27997d8cafcSkettenis 28097d8cafcSkettenis mtu : MTU '=' NUMBER { 28159eb6c85Skettenis vnet_opts.mtu = $3; 28259eb6c85Skettenis } 28359eb6c85Skettenis ; 28459eb6c85Skettenis 285a3b2112fSkn vnet_devalias : DEVALIAS '=' STRING { 286a3b2112fSkn vnet_opts.devalias = $3; 287a3b2112fSkn } 288a3b2112fSkn ; 289a3b2112fSkn 29059eb6c85Skettenis vcpu : STRING { 29159eb6c85Skettenis const char *errstr; 29259eb6c85Skettenis char *colon; 29359eb6c85Skettenis 29459eb6c85Skettenis vcpu_opts_default(); 29559eb6c85Skettenis colon = strchr($1, ':'); 29659eb6c85Skettenis if (colon == NULL) { 29759eb6c85Skettenis yyerror("bogus stride in %s", $1); 29859eb6c85Skettenis YYERROR; 29959eb6c85Skettenis } 30059eb6c85Skettenis *colon++ = '\0'; 30159eb6c85Skettenis vcpu_opts.count = strtonum($1, 0, INT_MAX, &errstr); 30259eb6c85Skettenis if (errstr) { 30359eb6c85Skettenis yyerror("number %s is %s", $1, errstr); 30459eb6c85Skettenis YYERROR; 30559eb6c85Skettenis } 30659eb6c85Skettenis vcpu_opts.stride = strtonum(colon, 0, INT_MAX, &errstr); 30759eb6c85Skettenis if (errstr) { 30859eb6c85Skettenis yyerror("number %s is %s", colon, errstr); 30959eb6c85Skettenis YYERROR; 31059eb6c85Skettenis } 31159eb6c85Skettenis $$ = vcpu_opts; 31259eb6c85Skettenis } 31359eb6c85Skettenis | NUMBER { 31459eb6c85Skettenis vcpu_opts_default(); 31559eb6c85Skettenis vcpu_opts.count = $1; 31659eb6c85Skettenis $$ = vcpu_opts; 31797d8cafcSkettenis } 31897d8cafcSkettenis ; 31997d8cafcSkettenis 32097d8cafcSkettenis memory : NUMBER { 32197d8cafcSkettenis $$ = $1; 32297d8cafcSkettenis } 32397d8cafcSkettenis | STRING { 324d73a4c4fSkn if (scan_scaled($1, &$$) == -1) { 325d73a4c4fSkn yyerror("invalid size: %s", $1); 32697d8cafcSkettenis YYERROR; 32797d8cafcSkettenis } 32897d8cafcSkettenis } 32997d8cafcSkettenis ; 33097d8cafcSkettenis 33197d8cafcSkettenis optnl : '\n' optnl 33297d8cafcSkettenis | 33397d8cafcSkettenis ; 33497d8cafcSkettenis 33597d8cafcSkettenis nl : '\n' optnl /* one newline or more */ 33697d8cafcSkettenis ; 33797d8cafcSkettenis 33897d8cafcSkettenis %% 33997d8cafcSkettenis 34097d8cafcSkettenis void 34159eb6c85Skettenis vcpu_opts_default(void) 34297d8cafcSkettenis { 34359eb6c85Skettenis vcpu_opts.count = -1; 34459eb6c85Skettenis vcpu_opts.stride = 1; 34559eb6c85Skettenis } 34659eb6c85Skettenis 34759eb6c85Skettenis void 348693255e2Skn vdisk_opts_default(void) 349693255e2Skn { 350693255e2Skn vdisk_opts.devalias = NULL; 351693255e2Skn } 352693255e2Skn 353693255e2Skn void 35459eb6c85Skettenis vnet_opts_default(void) 35559eb6c85Skettenis { 35659eb6c85Skettenis vnet_opts.mac_addr = -1; 35759eb6c85Skettenis vnet_opts.mtu = 1500; 358a3b2112fSkn vnet_opts.devalias = NULL; 35997d8cafcSkettenis } 36097d8cafcSkettenis 36197d8cafcSkettenis struct keywords { 36297d8cafcSkettenis const char *k_name; 36397d8cafcSkettenis int k_val; 36497d8cafcSkettenis }; 36597d8cafcSkettenis 36697d8cafcSkettenis int 36797d8cafcSkettenis yyerror(const char *fmt, ...) 36897d8cafcSkettenis { 36997d8cafcSkettenis va_list ap; 37097d8cafcSkettenis 37197d8cafcSkettenis file->errors++; 37297d8cafcSkettenis va_start(ap, fmt); 37397d8cafcSkettenis fprintf(stderr, "%s:%d ", file->name, yylval.lineno); 37497d8cafcSkettenis vfprintf(stderr, fmt, ap); 37597d8cafcSkettenis fprintf(stderr, "\n"); 37697d8cafcSkettenis va_end(ap); 37797d8cafcSkettenis return (0); 37897d8cafcSkettenis } 37997d8cafcSkettenis 38097d8cafcSkettenis int 38197d8cafcSkettenis kw_cmp(const void *k, const void *e) 38297d8cafcSkettenis { 38397d8cafcSkettenis return (strcmp(k, ((const struct keywords *)e)->k_name)); 38497d8cafcSkettenis } 38597d8cafcSkettenis 38697d8cafcSkettenis int 38797d8cafcSkettenis lookup(char *s) 38897d8cafcSkettenis { 38997d8cafcSkettenis /* this has to be sorted always */ 39097d8cafcSkettenis static const struct keywords keywords[] = { 391693255e2Skn { "devalias", DEVALIAS}, 39297d8cafcSkettenis { "domain", DOMAIN}, 3938cfaec25Skettenis { "iodevice", IODEVICE}, 39497d8cafcSkettenis { "mac-addr", MAC_ADDR}, 39597d8cafcSkettenis { "memory", MEMORY}, 39697d8cafcSkettenis { "mtu", MTU}, 3978e765095Skettenis { "variable", VARIABLE}, 39897d8cafcSkettenis { "vcpu", VCPU}, 39997d8cafcSkettenis { "vdisk", VDISK}, 40097d8cafcSkettenis { "vnet", VNET} 40197d8cafcSkettenis }; 40297d8cafcSkettenis const struct keywords *p; 40397d8cafcSkettenis 40497d8cafcSkettenis p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 40597d8cafcSkettenis sizeof(keywords[0]), kw_cmp); 40697d8cafcSkettenis 40797d8cafcSkettenis if (p) 40897d8cafcSkettenis return (p->k_val); 40997d8cafcSkettenis else 41097d8cafcSkettenis return (STRING); 41197d8cafcSkettenis } 41297d8cafcSkettenis 41397d8cafcSkettenis #define MAXPUSHBACK 128 41497d8cafcSkettenis 415015d7b4dSbenno u_char *parsebuf; 41697d8cafcSkettenis int parseindex; 417015d7b4dSbenno u_char pushback_buffer[MAXPUSHBACK]; 41897d8cafcSkettenis int pushback_index = 0; 41997d8cafcSkettenis 42097d8cafcSkettenis int 42197d8cafcSkettenis lgetc(int quotec) 42297d8cafcSkettenis { 42397d8cafcSkettenis int c, next; 42497d8cafcSkettenis 42597d8cafcSkettenis if (parsebuf) { 42697d8cafcSkettenis /* Read character from the parsebuffer instead of input. */ 42797d8cafcSkettenis if (parseindex >= 0) { 42897d8cafcSkettenis c = parsebuf[parseindex++]; 42997d8cafcSkettenis if (c != '\0') 43097d8cafcSkettenis return (c); 43197d8cafcSkettenis parsebuf = NULL; 43297d8cafcSkettenis } else 43397d8cafcSkettenis parseindex++; 43497d8cafcSkettenis } 43597d8cafcSkettenis 43697d8cafcSkettenis if (pushback_index) 43797d8cafcSkettenis return (pushback_buffer[--pushback_index]); 43897d8cafcSkettenis 43997d8cafcSkettenis if (quotec) { 44097d8cafcSkettenis if ((c = getc(file->stream)) == EOF) { 44197d8cafcSkettenis yyerror("reached end of file while parsing " 44297d8cafcSkettenis "quoted string"); 44397d8cafcSkettenis if (file == topfile || popfile() == EOF) 44497d8cafcSkettenis return (EOF); 44597d8cafcSkettenis return (quotec); 44697d8cafcSkettenis } 44797d8cafcSkettenis return (c); 44897d8cafcSkettenis } 44997d8cafcSkettenis 45097d8cafcSkettenis while ((c = getc(file->stream)) == '\\') { 45197d8cafcSkettenis next = getc(file->stream); 45297d8cafcSkettenis if (next != '\n') { 45397d8cafcSkettenis c = next; 45497d8cafcSkettenis break; 45597d8cafcSkettenis } 45697d8cafcSkettenis yylval.lineno = file->lineno; 45797d8cafcSkettenis file->lineno++; 45897d8cafcSkettenis } 45997d8cafcSkettenis 46097d8cafcSkettenis while (c == EOF) { 46197d8cafcSkettenis if (file == topfile || popfile() == EOF) 46297d8cafcSkettenis return (EOF); 46397d8cafcSkettenis c = getc(file->stream); 46497d8cafcSkettenis } 46597d8cafcSkettenis return (c); 46697d8cafcSkettenis } 46797d8cafcSkettenis 46897d8cafcSkettenis int 46997d8cafcSkettenis lungetc(int c) 47097d8cafcSkettenis { 47197d8cafcSkettenis if (c == EOF) 47297d8cafcSkettenis return (EOF); 47397d8cafcSkettenis if (parsebuf) { 47497d8cafcSkettenis parseindex--; 47597d8cafcSkettenis if (parseindex >= 0) 47697d8cafcSkettenis return (c); 47797d8cafcSkettenis } 47897d8cafcSkettenis if (pushback_index < MAXPUSHBACK-1) 47997d8cafcSkettenis return (pushback_buffer[pushback_index++] = c); 48097d8cafcSkettenis else 48197d8cafcSkettenis return (EOF); 48297d8cafcSkettenis } 48397d8cafcSkettenis 48497d8cafcSkettenis int 48597d8cafcSkettenis findeol(void) 48697d8cafcSkettenis { 48797d8cafcSkettenis int c; 48897d8cafcSkettenis 48997d8cafcSkettenis parsebuf = NULL; 49097d8cafcSkettenis 49197d8cafcSkettenis /* skip to either EOF or the first real EOL */ 49297d8cafcSkettenis while (1) { 49397d8cafcSkettenis if (pushback_index) 49497d8cafcSkettenis c = pushback_buffer[--pushback_index]; 49597d8cafcSkettenis else 49697d8cafcSkettenis c = lgetc(0); 49797d8cafcSkettenis if (c == '\n') { 49897d8cafcSkettenis file->lineno++; 49997d8cafcSkettenis break; 50097d8cafcSkettenis } 50197d8cafcSkettenis if (c == EOF) 50297d8cafcSkettenis break; 50397d8cafcSkettenis } 50497d8cafcSkettenis return (ERROR); 50597d8cafcSkettenis } 50697d8cafcSkettenis 50797d8cafcSkettenis int 50897d8cafcSkettenis yylex(void) 50997d8cafcSkettenis { 510015d7b4dSbenno u_char buf[8096]; 511015d7b4dSbenno u_char *p; 51297d8cafcSkettenis int quotec, next, c; 51397d8cafcSkettenis int token; 51497d8cafcSkettenis 51597d8cafcSkettenis p = buf; 51697d8cafcSkettenis while ((c = lgetc(0)) == ' ' || c == '\t') 51797d8cafcSkettenis ; /* nothing */ 51897d8cafcSkettenis 51997d8cafcSkettenis yylval.lineno = file->lineno; 52097d8cafcSkettenis if (c == '#') 52197d8cafcSkettenis while ((c = lgetc(0)) != '\n' && c != EOF) 52297d8cafcSkettenis ; /* nothing */ 52397d8cafcSkettenis 52497d8cafcSkettenis switch (c) { 52597d8cafcSkettenis case '\'': 52697d8cafcSkettenis case '"': 52797d8cafcSkettenis quotec = c; 52897d8cafcSkettenis while (1) { 52997d8cafcSkettenis if ((c = lgetc(quotec)) == EOF) 53097d8cafcSkettenis return (0); 53197d8cafcSkettenis if (c == '\n') { 53297d8cafcSkettenis file->lineno++; 53397d8cafcSkettenis continue; 53497d8cafcSkettenis } else if (c == '\\') { 53597d8cafcSkettenis if ((next = lgetc(quotec)) == EOF) 53697d8cafcSkettenis return (0); 537a1533359Ssashan if (next == quotec || next == ' ' || 538a1533359Ssashan next == '\t') 53997d8cafcSkettenis c = next; 54097d8cafcSkettenis else if (next == '\n') { 54197d8cafcSkettenis file->lineno++; 54297d8cafcSkettenis continue; 54397d8cafcSkettenis } else 54497d8cafcSkettenis lungetc(next); 54597d8cafcSkettenis } else if (c == quotec) { 54697d8cafcSkettenis *p = '\0'; 54797d8cafcSkettenis break; 54841eef22fSjsg } else if (c == '\0') { 54941eef22fSjsg yyerror("syntax error"); 55041eef22fSjsg return (findeol()); 55197d8cafcSkettenis } 55297d8cafcSkettenis if (p + 1 >= buf + sizeof(buf) - 1) { 55397d8cafcSkettenis yyerror("string too long"); 55497d8cafcSkettenis return (findeol()); 55597d8cafcSkettenis } 556015d7b4dSbenno *p++ = c; 55797d8cafcSkettenis } 55897d8cafcSkettenis yylval.v.string = xstrdup(buf); 55997d8cafcSkettenis return (STRING); 56097d8cafcSkettenis } 56197d8cafcSkettenis 56297d8cafcSkettenis #define allowed_to_end_number(x) \ 56397d8cafcSkettenis (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 56497d8cafcSkettenis 56597d8cafcSkettenis if (c == '-' || isdigit(c)) { 56697d8cafcSkettenis do { 56797d8cafcSkettenis *p++ = c; 568915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) { 56997d8cafcSkettenis yyerror("string too long"); 57097d8cafcSkettenis return (findeol()); 57197d8cafcSkettenis } 57297d8cafcSkettenis } while ((c = lgetc(0)) != EOF && isdigit(c)); 57397d8cafcSkettenis lungetc(c); 57497d8cafcSkettenis if (p == buf + 1 && buf[0] == '-') 57597d8cafcSkettenis goto nodigits; 57697d8cafcSkettenis if (c == EOF || allowed_to_end_number(c)) { 57797d8cafcSkettenis const char *errstr = NULL; 57897d8cafcSkettenis 57997d8cafcSkettenis *p = '\0'; 58097d8cafcSkettenis yylval.v.number = strtonum(buf, LLONG_MIN, 58197d8cafcSkettenis LLONG_MAX, &errstr); 58297d8cafcSkettenis if (errstr) { 58397d8cafcSkettenis yyerror("\"%s\" invalid number: %s", 58497d8cafcSkettenis buf, errstr); 58597d8cafcSkettenis return (findeol()); 58697d8cafcSkettenis } 58797d8cafcSkettenis return (NUMBER); 58897d8cafcSkettenis } else { 58997d8cafcSkettenis nodigits: 59097d8cafcSkettenis while (p > buf + 1) 59197d8cafcSkettenis lungetc(*--p); 59297d8cafcSkettenis c = *--p; 59397d8cafcSkettenis if (c == '-') 59497d8cafcSkettenis return (c); 59597d8cafcSkettenis } 59697d8cafcSkettenis } 59797d8cafcSkettenis 59897d8cafcSkettenis #define allowed_in_string(x) \ 59997d8cafcSkettenis (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 60097d8cafcSkettenis x != '{' && x != '}' && x != '<' && x != '>' && \ 60197d8cafcSkettenis x != '!' && x != '=' && x != '/' && x != '#' && \ 60297d8cafcSkettenis x != ',')) 60397d8cafcSkettenis 60497d8cafcSkettenis if (isalnum(c) || c == ':' || c == '_' || c == '*') { 60597d8cafcSkettenis do { 60697d8cafcSkettenis *p++ = c; 607915c3f33Sderaadt if ((size_t)(p-buf) >= sizeof(buf)) { 60897d8cafcSkettenis yyerror("string too long"); 60997d8cafcSkettenis return (findeol()); 61097d8cafcSkettenis } 61197d8cafcSkettenis } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 61297d8cafcSkettenis lungetc(c); 61397d8cafcSkettenis *p = '\0'; 61497d8cafcSkettenis if ((token = lookup(buf)) == STRING) 61597d8cafcSkettenis yylval.v.string = xstrdup(buf); 61697d8cafcSkettenis return (token); 61797d8cafcSkettenis } 61897d8cafcSkettenis if (c == '\n') { 61997d8cafcSkettenis yylval.lineno = file->lineno; 62097d8cafcSkettenis file->lineno++; 62197d8cafcSkettenis } 62297d8cafcSkettenis if (c == EOF) 62397d8cafcSkettenis return (0); 62497d8cafcSkettenis return (c); 62597d8cafcSkettenis } 62697d8cafcSkettenis 62797d8cafcSkettenis struct file * 62897d8cafcSkettenis pushfile(const char *name) 62997d8cafcSkettenis { 63097d8cafcSkettenis struct file *nfile; 63197d8cafcSkettenis 63297d8cafcSkettenis nfile = xzalloc(sizeof(struct file)); 63397d8cafcSkettenis nfile->name = xstrdup(name); 63497d8cafcSkettenis if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 6356a3d55f9Skrw warn("%s: %s", __func__, nfile->name); 63697d8cafcSkettenis free(nfile->name); 63797d8cafcSkettenis free(nfile); 63897d8cafcSkettenis return (NULL); 63997d8cafcSkettenis } 64097d8cafcSkettenis nfile->lineno = 1; 64197d8cafcSkettenis TAILQ_INSERT_TAIL(&files, nfile, entry); 64297d8cafcSkettenis return (nfile); 64397d8cafcSkettenis } 64497d8cafcSkettenis 64597d8cafcSkettenis int 64697d8cafcSkettenis popfile(void) 64797d8cafcSkettenis { 64897d8cafcSkettenis struct file *prev; 64997d8cafcSkettenis 65097d8cafcSkettenis if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 65197d8cafcSkettenis prev->errors += file->errors; 65297d8cafcSkettenis 65397d8cafcSkettenis TAILQ_REMOVE(&files, file, entry); 65497d8cafcSkettenis fclose(file->stream); 65597d8cafcSkettenis free(file->name); 65697d8cafcSkettenis free(file); 65797d8cafcSkettenis file = prev; 65897d8cafcSkettenis return (file ? 0 : EOF); 65997d8cafcSkettenis } 66097d8cafcSkettenis 66197d8cafcSkettenis int 66297d8cafcSkettenis parse_config(const char *filename, struct ldom_config *xconf) 66397d8cafcSkettenis { 66497d8cafcSkettenis int errors = 0; 66597d8cafcSkettenis 66697d8cafcSkettenis conf = xconf; 66797d8cafcSkettenis 66897d8cafcSkettenis if ((file = pushfile(filename)) == NULL) { 66997d8cafcSkettenis return (-1); 67097d8cafcSkettenis } 67197d8cafcSkettenis topfile = file; 67297d8cafcSkettenis 67397d8cafcSkettenis yyparse(); 67497d8cafcSkettenis errors = file->errors; 67597d8cafcSkettenis popfile(); 67697d8cafcSkettenis 67797d8cafcSkettenis return (errors ? -1 : 0); 67897d8cafcSkettenis } 679