Home | History | Annotate | Line # | Download | only in config
gram.y revision 1.26
      1 %{
      2 /*	$NetBSD: gram.y,v 1.26 2012/03/11 00:57:44 dholland Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 1992, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * This software was developed by the Computer Systems Engineering group
      9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     10  * contributed to Berkeley.
     11  *
     12  * All advertising materials mentioning features or use of this software
     13  * must display the following acknowledgement:
     14  *	This product includes software developed by the University of
     15  *	California, Lawrence Berkeley Laboratories.
     16  *
     17  * Redistribution and use in source and binary forms, with or without
     18  * modification, are permitted provided that the following conditions
     19  * are met:
     20  * 1. Redistributions of source code must retain the above copyright
     21  *    notice, this list of conditions and the following disclaimer.
     22  * 2. Redistributions in binary form must reproduce the above copyright
     23  *    notice, this list of conditions and the following disclaimer in the
     24  *    documentation and/or other materials provided with the distribution.
     25  * 3. Neither the name of the University nor the names of its contributors
     26  *    may be used to endorse or promote products derived from this software
     27  *    without specific prior written permission.
     28  *
     29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  *
     41  *	from: @(#)gram.y	8.1 (Berkeley) 6/6/93
     42  */
     43 
     44 #include <sys/types.h>
     45 #include <sys/param.h>
     46 #include <ctype.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <string.h>
     50 #include <errno.h>
     51 #include "defs.h"
     52 #include "sem.h"
     53 
     54 #define	FORMAT(n) (((n).fmt == 8 && (n).val != 0) ? "0%llo" : \
     55     ((n).fmt == 16) ? "0x%llx" : "%lld")
     56 
     57 #define	stop(s)	cfgerror(s), exit(1)
     58 
     59 static	struct	config conf;	/* at most one active at a time */
     60 
     61 /* the following is used to recover nvlist space after errors */
     62 static	struct	nvlist *alloc[1000];
     63 static	int	adepth;
     64 #define	new0(n,s,p,i,x)	(alloc[adepth++] = newnv(n, s, p, i, x))
     65 #define	new_n(n)	new0(n, NULL, NULL, 0, NULL)
     66 #define	new_nx(n, x)	new0(n, NULL, NULL, 0, x)
     67 #define	new_ns(n, s)	new0(n, s, NULL, 0, NULL)
     68 #define	new_si(s, i)	new0(NULL, s, NULL, i, NULL)
     69 #define	new_nsi(n,s,i)	new0(n, s, NULL, i, NULL)
     70 #define	new_np(n, p)	new0(n, NULL, p, 0, NULL)
     71 #define	new_s(s)	new0(NULL, s, NULL, 0, NULL)
     72 #define	new_p(p)	new0(NULL, NULL, p, 0, NULL)
     73 #define	new_px(p, x)	new0(NULL, NULL, p, 0, x)
     74 #define	new_sx(s, x)	new0(NULL, s, NULL, 0, x)
     75 #define	new_nsx(n,s,x)	new0(n, s, NULL, 0, x)
     76 #define	new_i(i)	new0(NULL, NULL, NULL, i, NULL)
     77 
     78 #define	fx_atom(s)	new0(s, NULL, NULL, FX_ATOM, NULL)
     79 #define	fx_not(e)	new0(NULL, NULL, NULL, FX_NOT, e)
     80 #define	fx_and(e1, e2)	new0(NULL, NULL, e1, FX_AND, e2)
     81 #define	fx_or(e1, e2)	new0(NULL, NULL, e1, FX_OR, e2)
     82 
     83 static	void	cleanup(void);
     84 static	void	setmachine(const char *, const char *, struct nvlist *, int);
     85 static	void	check_maxpart(void);
     86 
     87 static	void	app(struct nvlist *, struct nvlist *);
     88 
     89 static	struct nvlist *mk_nsis(const char *, int, struct nvlist *, int);
     90 static	struct nvlist *mk_ns(const char *, struct nvlist *);
     91 
     92 %}
     93 
     94 %union {
     95 	struct	attr *attr;
     96 	struct	devbase *devb;
     97 	struct	deva *deva;
     98 	struct	nvlist *list;
     99 	const char *str;
    100 	struct	numconst num;
    101 	int64_t	val;
    102 }
    103 
    104 %token	AND AT ATTACH
    105 %token	BLOCK BUILD
    106 %token	CHAR COLONEQ COMPILE_WITH CONFIG
    107 %token	DEFFS DEFINE DEFOPT DEFPARAM DEFFLAG DEFPSEUDO DEFPSEUDODEV
    108 %token	DEVICE DEVCLASS DUMPS DEVICE_MAJOR
    109 %token	ENDFILE
    110 %token	XFILE FILE_SYSTEM FLAGS
    111 %token	IDENT IOCONF
    112 %token	LINKZERO
    113 %token	XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR
    114 %token	NEEDS_COUNT NEEDS_FLAG NO
    115 %token	XOBJECT OBSOLETE ON OPTIONS
    116 %token	PACKAGE PLUSEQ PREFIX PSEUDO_DEVICE PSEUDO_ROOT
    117 %token	ROOT
    118 %token	SINGLE SOURCE
    119 %token	TYPE
    120 %token	VECTOR VERSION
    121 %token	WITH
    122 %token	<num> NUMBER
    123 %token	<str> PATHNAME QSTRING WORD EMPTYSTRING
    124 %token	ENDDEFS
    125 
    126 %left '|'
    127 %left '&'
    128 
    129 %type	<list>	fopts fexpr fatom
    130 %type	<str>	fs_spec
    131 %type	<val>	fflgs fflag oflgs oflag
    132 %type	<str>	rule
    133 %type	<attr>	attr
    134 %type	<devb>	devbase
    135 %type	<deva>	devattach_opt
    136 %type	<list>	atlist interface_opt
    137 %type	<str>	atname
    138 %type	<list>	loclist_opt loclist locdef
    139 %type	<str>	locdefault
    140 %type	<list>	values locdefaults
    141 %type	<list>	attrs_opt attrs
    142 %type	<list>	locators locator
    143 %type	<list>	dev_spec
    144 %type	<str>	device_instance
    145 %type	<str>	attachment
    146 %type	<str>	value
    147 %type	<val>	major_minor npseudo
    148 %type	<num>	signed_number
    149 %type	<val>	flags_opt
    150 %type	<str>	deffs
    151 %type	<list>	deffses
    152 %type	<list>	defopt
    153 %type	<list>	defopts
    154 %type	<str>	optdep
    155 %type	<list>	optdeps
    156 %type	<list>	defoptdeps
    157 %type	<str>	optfile_opt
    158 %type	<list>	subarches_opt subarches
    159 %type	<str>	filename stringvalue locname mkvarname
    160 %type	<val>	device_major_block device_major_char
    161 %type	<list>	devnodes devnodetype devnodeflags devnode_dims
    162 
    163 %%
    164 
    165 /*
    166  * A complete configuration consists of both the configuration part (a
    167  * kernel config such as GENERIC or SKYNET, plus also the various
    168  * std.* files), which selects the material to be in the kernel, and
    169  * also the definition part (files, files.*, etc.) that declares what
    170  * material is available to be placed in kernels.
    171  *
    172  * The two parts have almost entirely separate syntaxes. This grammar
    173  * covers both of them. When config is run on a kernel configuration
    174  * file, the std.* file for the port is included explicitly. The
    175  * files.* files are included implicitly when the std.* file declares
    176  * the machine type.
    177  *
    178  * The machine spec, which brings in the definition part, must appear
    179  * before all configuration material except for the "topthings"; these
    180  * are the "source" and "build" declarations that tell config where
    181  * things are. These are not used by default.
    182  *
    183  * A previous version of this comment contained the following text:
    184  *
    185  *       Note that we do not have sufficient keywords to enforce any
    186  *       order between elements of "topthings" without introducing
    187  *       shift/reduce conflicts.  Instead, check order requirements in
    188  *       the C code.
    189  *
    190  * As of March 2012 this comment makes no sense, as there are only two
    191  * topthings and no reason for them to be forcibly ordered.
    192  * Furthermore, the statement about conflicts is false.
    193  */
    194 
    195 /* Complete configuration. */
    196 Configuration:
    197 	topthings
    198 		machine_spec dev_defs ENDDEFS
    199 		{ check_maxpart(); check_version(); }
    200 		specs
    201 ;
    202 
    203 /* Sequence of zero or more topthings. */
    204 topthings:
    205 	  /* empty */
    206 	| topthings topthing
    207 ;
    208 
    209 /* Directory specification. */
    210 topthing:
    211 	  SOURCE filename '\n'		{ if (!srcdir) srcdir = $2; }
    212 	| BUILD  filename '\n'		{ if (!builddir) builddir = $2; }
    213 	|                 '\n'
    214 ;
    215 
    216 /* "machine foo" from std.whatever */
    217 machine_spec:
    218 	  XMACHINE WORD '\n'			{ setmachine($2,NULL,NULL,0); }
    219 	| XMACHINE WORD WORD subarches_opt '\n'	{ setmachine($2,$3,$4,0); }
    220 	| IOCONF WORD '\n'			{ setmachine($2,NULL,NULL,1); }
    221 	| error { stop("cannot proceed without machine or ioconf specifier"); }
    222 ;
    223 
    224 /* Optional subarches. */
    225 subarches_opt:
    226 	  /* empty */			{ $$ = NULL; }
    227 	| subarches
    228 ;
    229 
    230 /* Subarches declaration. */
    231 subarches:
    232 	  subarches WORD		{ $$ = new_nx($2, $1); }
    233 	| WORD				{ $$ = new_n($1); }
    234 ;
    235 
    236 /************************************************************/
    237 
    238 /*
    239  * Various nonterminals shared between the grammars.
    240  * (Note: that's a lie, pending some reorg)
    241  */
    242 
    243 /* source file: file foo/bar.c bar|baz needs-flag compile-with blah */
    244 file:
    245 	XFILE filename fopts fflgs rule	{ addfile($2, $3, $4, $5); }
    246 ;
    247 
    248 /* object file: object zot.o foo|zot needs-flag */
    249 object:
    250 	XOBJECT filename fopts oflgs	{ addobject($2, $3, $4); }
    251 ;
    252 
    253 /* device major declaration */
    254 device_major:
    255 	DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes
    256 					{ adddevm($2, $3, $4, $5, $6); }
    257 ;
    258 
    259 /* block 33 */
    260 device_major_block:
    261 	  /* empty */			{ $$ = -1; }
    262 	| BLOCK NUMBER			{ $$ = $2.val; }
    263 ;
    264 
    265 /* char 55 */
    266 device_major_char:
    267 	  /* empty */			{ $$ = -1; }
    268 	| CHAR NUMBER			{ $$ = $2.val; }
    269 ;
    270 
    271 /*
    272  * order of options is important, must use right recursion
    273  *
    274  * dholland 20120310: wut?
    275  */
    276 
    277 /* file options: optional expression of config elements */
    278 fopts:
    279 	  /* empty */			{ $$ = NULL; }
    280 	| fexpr				{ $$ = $1; }
    281 ;
    282 
    283 /* expression of config elements */
    284 /* XXX this should use a real expression grammar */
    285 fexpr:
    286 	  fatom				{ $$ = $1; }
    287 	| '!' fatom			{ $$ = fx_not($2); }
    288 	| fexpr '&' fexpr		{ $$ = fx_and($1, $3); }
    289 	| fexpr '|' fexpr		{ $$ = fx_or($1, $3); }
    290 	| '(' fexpr ')'			{ $$ = $2; }
    291 ;
    292 
    293 /* basic element of config element expression: a config element */
    294 fatom:
    295 	WORD				{ $$ = fx_atom($1); }
    296 ;
    297 
    298 /* zero or more flags for a file */
    299 fflgs:
    300 	  /* empty */			{ $$ = 0; }
    301 	| fflgs fflag			{ $$ = $1 | $2; }
    302 ;
    303 
    304 /* one flag for a file */
    305 fflag:
    306 	  NEEDS_COUNT			{ $$ = FI_NEEDSCOUNT; }
    307 	| NEEDS_FLAG			{ $$ = FI_NEEDSFLAG; }
    308 ;
    309 
    310 /* device node specification */
    311 devnodes:
    312 	  /* empty */			{ $$ = new_s("DEVNODE_DONTBOTHER"); }
    313 	| devnodetype ',' devnodeflags	{ $$ = nvcat($1, $3); }
    314 	| devnodetype			{ $$ = $1; }
    315 ;
    316 
    317 /* device nodes without flags */
    318 devnodetype:
    319 	  SINGLE			{ $$ = new_s("DEVNODE_SINGLE"); }
    320 	| VECTOR '=' devnode_dims  { $$ = nvcat(new_s("DEVNODE_VECTOR"), $3); }
    321 ;
    322 
    323 /* dimensions (?) */
    324 devnode_dims:
    325 	  NUMBER			{ $$ = new_i($1.val); }
    326 	| NUMBER ':' NUMBER		{
    327 		struct nvlist *__nv1, *__nv2;
    328 
    329 		__nv1 = new_i($1.val);
    330 		__nv2 = new_i($3.val);
    331 		$$ = nvcat(__nv1, __nv2);
    332 	  }
    333 ;
    334 
    335 /* flags for device nodes */
    336 devnodeflags:
    337 	LINKZERO			{ $$ = new_s("DEVNODE_FLAG_LINKZERO");}
    338 ;
    339 
    340 /* zero or more flags for an object file */
    341 oflgs:
    342 	  /* empty */			{ $$ = 0; }
    343 	| oflgs oflag			{ $$ = $1 | $2; }
    344 ;
    345 
    346 /* a single flag for an object file */
    347 oflag:
    348 	NEEDS_FLAG			{ $$ = OI_NEEDSFLAG; }
    349 ;
    350 
    351 /* extra compile directive for a source file */
    352 rule:
    353 	  /* empty */			{ $$ = NULL; }
    354 	| COMPILE_WITH stringvalue	{ $$ = $2; }
    355 ;
    356 
    357 /* prefix delimiter */
    358 prefix:
    359 	  PREFIX filename		{ prefix_push($2); }
    360 	| PREFIX			{ prefix_pop(); }
    361 ;
    362 
    363 /************************************************************/
    364 
    365 /*
    366  * The machine definitions grammar.
    367  */
    368 
    369 /* Complete definition part: the contents of all files.* files. */
    370 dev_defs:
    371 	  /* empty */
    372 	| dev_defs dev_def
    373 	| dev_defs ENDFILE		{ enddefs(); checkfiles(); }
    374 ;
    375 
    376 /* A single definition, or a blank line. Trap errors. */
    377 dev_def:
    378 	  '\n'
    379 	| one_def '\n'			{ adepth = 0; }
    380 	| error '\n'			{ cleanup(); }
    381 ;
    382 
    383 /* A single definition. */
    384 one_def:
    385 	  file
    386 	| object
    387 	| device_major			{ do_devsw = 1; }
    388 	| prefix
    389 	| DEVCLASS WORD			{ (void)defattr($2, NULL, NULL, 1); }
    390 	| DEFFS deffses defoptdeps	{ deffilesystem($2, $3); }
    391 	| DEFINE WORD interface_opt attrs_opt
    392 					{ (void)defattr($2, $3, $4, 0); }
    393 	| DEFOPT optfile_opt defopts defoptdeps
    394 					{ defoption($2, $3, $4); }
    395 	| DEFFLAG optfile_opt defopts defoptdeps
    396 					{ defflag($2, $3, $4, 0); }
    397 	| OBSOLETE DEFFLAG optfile_opt defopts
    398 					{ defflag($3, $4, NULL, 1); }
    399 	| DEFPARAM optfile_opt defopts defoptdeps
    400 					{ defparam($2, $3, $4, 0); }
    401 	| OBSOLETE DEFPARAM optfile_opt defopts
    402 					{ defparam($3, $4, NULL, 1); }
    403 	| DEVICE devbase interface_opt attrs_opt
    404 					{ defdev($2, $3, $4, 0); }
    405 	| ATTACH devbase AT atlist devattach_opt attrs_opt
    406 					{ defdevattach($5, $2, $4, $6); }
    407 	| MAXPARTITIONS NUMBER		{ maxpartitions = $2.val; }
    408 	| MAXUSERS NUMBER NUMBER NUMBER
    409 				    { setdefmaxusers($2.val, $3.val, $4.val); }
    410 	| MAKEOPTIONS condmkopt_list
    411 	/* interface_opt in DEFPSEUDO is for backwards compatibility */
    412 	| DEFPSEUDO devbase interface_opt attrs_opt
    413 					{ defdev($2, $3, $4, 1); }
    414 	| DEFPSEUDODEV devbase interface_opt attrs_opt
    415 					{ defdev($2, $3, $4, 2); }
    416 	| MAJOR '{' majorlist '}'
    417 	| VERSION NUMBER		{ setversion($2.val); }
    418 ;
    419 
    420 /* list of places to attach: attach blah at ... */
    421 atlist:
    422 	  atname			{ $$ = new_n($1); }
    423 	| atlist ',' atname		{ $$ = new_nx($3, $1); }
    424 ;
    425 
    426 /* a place to attach a device */
    427 atname:
    428 	  WORD				{ $$ = $1; }
    429 	| ROOT				{ $$ = NULL; }
    430 ;
    431 
    432 /* one or more file system names */
    433 deffses:
    434 	  deffs				{ $$ = new_n($1); }
    435 	| deffses deffs			{ $$ = new_nx($2, $1); }
    436 ;
    437 
    438 /* a single file system name */
    439 deffs:
    440 	WORD				{ $$ = $1; }
    441 ;
    442 
    443 /* option dependencies (read as "defopt deps") which are optional */
    444 defoptdeps:
    445 	  /* empty */			{ $$ = NULL; }
    446 	| ':' optdeps			{ $$ = $2; }
    447 ;
    448 
    449 /* a list of option dependencies */
    450 optdeps:
    451 	  optdep			{ $$ = new_n($1); }
    452 	| optdeps ',' optdep		{ $$ = new_nx($3, $1); }
    453 ;
    454 
    455 /* one option dependence */
    456 optdep:
    457 	WORD				{ $$ = $1; }
    458 ;
    459 
    460 /* one or more defined options */
    461 defopts:
    462 	  defopt			{ $$ = $1; }
    463 	| defopts defopt		{ $$ = nvcat($2, $1); }
    464 ;
    465 
    466 /* one defined option */
    467 defopt:
    468 	  WORD				{ $$ = new_n($1); }
    469 	| WORD '=' value		{ $$ = new_ns($1, $3); }
    470 	| WORD COLONEQ value		{
    471 		struct nvlist *__nv = new_n($1);
    472 
    473 		$$ = new_nsx("", $3, __nv);
    474 	  }
    475 	| WORD '=' value COLONEQ value	{
    476 		struct nvlist *__nv = new_n($1);
    477 
    478 		$$ = new_nsx("", $5, __nv);
    479 	  }
    480 ;
    481 
    482 /* device name */
    483 devbase:
    484 	WORD				{ $$ = getdevbase($1); }
    485 ;
    486 
    487 /* optional attachment: with foo */
    488 devattach_opt:
    489 	  /* empty */			{ $$ = NULL; }
    490 	| WITH WORD			{ $$ = getdevattach($2); }
    491 ;
    492 
    493 /* optional locator specification in braces */
    494 interface_opt:
    495 	  /* empty */			{ $$ = NULL; }
    496 	| '{' loclist_opt '}'		{ $$ = new_nx("", $2); }
    497 ;
    498 
    499 /* optional locator specification without braces */
    500 loclist_opt:
    501 	  /* empty */			{ $$ = NULL; }
    502 	| loclist			{ $$ = $1; }
    503 ;
    504 
    505 /*
    506  * loclist order matters, must use right recursion
    507  * XXX wot?
    508  */
    509 
    510 /* list of locator definitions */
    511 loclist:
    512 	  locdef			{ $$ = $1; }
    513 	| locdef ',' loclist		{ $$ = $1; app($1, $3); }
    514 ;
    515 
    516 /*
    517  * "[ WORD locdefault ]" syntax may be unnecessary...
    518  */
    519 
    520 /* one locator definition */
    521 locdef:
    522 	  locname locdefault 		{ $$ = new_nsi($1, $2, 0); }
    523 	| locname			{ $$ = new_nsi($1, NULL, 0); }
    524 	| '[' locname locdefault ']'	{ $$ = new_nsi($2, $3, 1); }
    525 	| locname '[' NUMBER ']'	{ $$ = mk_nsis($1, $3.val, NULL, 0); }
    526 	| locname '[' NUMBER ']' locdefaults
    527 					{ $$ = mk_nsis($1, $3.val, $5, 0); }
    528 	| '[' locname '[' NUMBER ']' locdefaults ']'
    529 					{ $$ = mk_nsis($2, $4.val, $6, 1); }
    530 ;
    531 
    532 /* locator name */
    533 locname:
    534 	  WORD				{ $$ = $1; }
    535 	| QSTRING			{ $$ = $1; }
    536 ;
    537 
    538 /* locator default value */
    539 locdefault:
    540 	'=' value			{ $$ = $2; }
    541 ;
    542 
    543 /* multiple locator default values */
    544 locdefaults:
    545 	'=' '{' values '}'		{ $$ = $3; }
    546 ;
    547 
    548 /* optional file for an option */
    549 optfile_opt:
    550 	  /* empty */			{ $$ = NULL; }
    551 	| filename			{ $$ = $1; }
    552 ;
    553 
    554 /* filename. */
    555 filename:
    556 	  QSTRING			{ $$ = $1; }
    557 	| PATHNAME			{ $$ = $1; }
    558 ;
    559 
    560 /* constant value */
    561 value:
    562 	  QSTRING			{ $$ = $1; }
    563 	| WORD				{ $$ = $1; }
    564 	| EMPTYSTRING			{ $$ = $1; }
    565 	| signed_number			{
    566 		char bf[40];
    567 
    568 		(void)snprintf(bf, sizeof(bf), FORMAT($1), (long long)$1.val);
    569 		$$ = intern(bf);
    570 	  }
    571 ;
    572 
    573 /* constant value that is a string */
    574 stringvalue:
    575 	  QSTRING			{ $$ = $1; }
    576 	| WORD				{ $$ = $1; }
    577 ;
    578 
    579 /* comma-separated list of values */
    580 /* XXX why right-recursive? */
    581 values:
    582 	  value				{ $$ = new_s($1); }
    583 	| value ',' values		{ $$ = new_sx($1, $3); }
    584 ;
    585 
    586 /* possibly negative number */
    587 signed_number:
    588 	  NUMBER			{ $$ = $1; }
    589 	| '-' NUMBER			{ $$.fmt = $2.fmt; $$.val = -$2.val; }
    590 ;
    591 
    592 /* optional attributes */
    593 attrs_opt:
    594 	  /* empty */			{ $$ = NULL; }
    595 	| ':' attrs			{ $$ = $2; }
    596 ;
    597 
    598 /* one or more attributes */
    599 attrs:
    600 	  attr				{ $$ = new_p($1); }
    601 	| attrs ',' attr		{ $$ = new_px($3, $1); }
    602 ;
    603 
    604 /* one attribute */
    605 attr:
    606 	WORD				{ $$ = getattr($1); }
    607 ;
    608 
    609 /* list of major numbers */
    610 /* XXX why is this right-recursive? */
    611 majorlist:
    612 	  majordef
    613 	| majorlist ',' majordef
    614 ;
    615 
    616 /* one major number */
    617 majordef:
    618 	devbase '=' NUMBER		{ setmajor($1, $3.val); }
    619 ;
    620 
    621 /************************************************************/
    622 
    623 /*
    624  * The configuration grammar.
    625  */
    626 
    627 /* Complete configuration part: all std.* files plus selected config. */
    628 specs:
    629 	  /* empty */
    630 	| specs spec
    631 ;
    632 
    633 /* One config item, or a blank line. Trap errors. */
    634 spec:
    635 	  '\n'
    636 	| config_spec '\n'		{ adepth = 0; }
    637 	| error '\n'			{ cleanup(); }
    638 ;
    639 
    640 /* One config item. */
    641 config_spec:
    642 	  one_def
    643 	| NO FILE_SYSTEM no_fs_list
    644 	| FILE_SYSTEM fs_list
    645 	| NO MAKEOPTIONS no_mkopt_list
    646 	| MAKEOPTIONS mkopt_list
    647 	| NO OPTIONS no_opt_list
    648 	| OPTIONS opt_list
    649 	| MAXUSERS NUMBER		{ setmaxusers($2.val); }
    650 	| IDENT stringvalue		{ setident($2); }
    651 	| CONFIG conf root_spec sysparam_list
    652 					{ addconf(&conf); }
    653 	| NO CONFIG WORD		{ delconf($3); }
    654 	| NO PSEUDO_DEVICE WORD		{ delpseudo($3); }
    655 	| PSEUDO_DEVICE WORD npseudo	{ addpseudo($2, $3); }
    656 	| PSEUDO_ROOT device_instance	{ addpseudoroot($2); }
    657 	| NO device_instance AT attachment
    658 					{ deldevi($2, $4); }
    659 	| NO DEVICE AT attachment	{ deldeva($4); }
    660 	| NO device_instance		{ deldev($2); }
    661 	| device_instance AT attachment locators flags_opt
    662 					{ adddev($1, $3, $4, $5); }
    663 ;
    664 
    665 /* list of filesystems */
    666 fs_list:
    667 	  fsoption
    668 	| fs_list ',' fsoption
    669 ;
    670 
    671 /* one filesystem */
    672 fsoption:
    673 	WORD				{ addfsoption($1); }
    674 ;
    675 
    676 /* list of filesystems that had NO in front */
    677 no_fs_list:
    678 	  no_fsoption
    679 	| no_fs_list ',' no_fsoption
    680 ;
    681 
    682 /* one filesystem that had NO in front */
    683 no_fsoption:
    684 	WORD				{ delfsoption($1); }
    685 ;
    686 
    687 /* list of make options */
    688 /* XXX why is this right-recursive? */
    689 mkopt_list:
    690 	  mkoption
    691 	| mkopt_list ',' mkoption
    692 ;
    693 
    694 /* variable name for make option */
    695 mkvarname:
    696 	  QSTRING			{ $$ = $1; }
    697 	| WORD				{ $$ = $1; }
    698 ;
    699 
    700 /* one make option */
    701 mkoption:
    702 	  mkvarname '=' value		{ addmkoption($1, $3); }
    703 	| mkvarname PLUSEQ value	{ appendmkoption($1, $3); }
    704 ;
    705 
    706 /* list of conditional makeoptions */
    707 condmkopt_list:
    708 	  condmkoption
    709 	| condmkopt_list ',' condmkoption
    710 ;
    711 
    712 /* one conditional make option */
    713 condmkoption:
    714 	fexpr mkvarname PLUSEQ value	{ appendcondmkoption($1, $2, $4); }
    715 ;
    716 
    717 /* list of make options that had NO in front */
    718 no_mkopt_list:
    719 	  no_mkoption
    720 	| no_mkopt_list ',' no_mkoption
    721 ;
    722 
    723 /* one make option that had NO in front */
    724 no_mkoption:
    725 	WORD				{ delmkoption($1); }
    726 ;
    727 
    728 /* list of options */
    729 opt_list:
    730 	  option
    731 	| opt_list ',' option
    732 ;
    733 
    734 /* one option */
    735 option:
    736 	  WORD				{ addoption($1, NULL); }
    737 	| WORD '=' value		{ addoption($1, $3); }
    738 ;
    739 
    740 /* list of options that had NO in front */
    741 no_opt_list:
    742 	  no_option
    743 	| no_opt_list ',' no_option
    744 ;
    745 
    746 /* one option that had NO in front */
    747 no_option:
    748 	WORD				{ deloption($1); }
    749 ;
    750 
    751 /* the name in "config name root on ..." */
    752 conf:
    753 	WORD				{
    754 		conf.cf_name = $1;
    755 		conf.cf_lineno = currentline();
    756 		conf.cf_fstype = NULL;
    757 		conf.cf_root = NULL;
    758 		conf.cf_dump = NULL;
    759 	}
    760 ;
    761 
    762 /* root fs specification */
    763 root_spec:
    764 	ROOT on_opt dev_spec fs_spec_opt
    765 					{ setconf(&conf.cf_root, "root", $3); }
    766 ;
    767 
    768 /* filesystem type for root fs specification */
    769 fs_spec_opt:
    770 	  /* empty */
    771 	| TYPE fs_spec			{ setfstype(&conf.cf_fstype, $2); }
    772 ;
    773 
    774 /* filesystem name for root fs specification */
    775 fs_spec:
    776 	  '?'				{ $$ = intern("?"); }
    777 	| WORD				{ $$ = $1; }
    778 ;
    779 
    780 /* zero or more additional system parameters */
    781 sysparam_list:
    782 	  /* empty */
    783 	| sysparam_list sysparam
    784 ;
    785 
    786 /* one additional system parameter (there's only one: dumps) */
    787 sysparam:
    788 	DUMPS on_opt dev_spec	       { setconf(&conf.cf_dump, "dumps", $3); }
    789 ;
    790 
    791 /* device for root fs or dump */
    792 dev_spec:
    793 	  '?'				{ $$ = new_si(intern("?"), NODEV); }
    794 	| WORD				{ $$ = new_si($1, NODEV); }
    795 	| major_minor			{ $$ = new_si(NULL, $1); }
    796 ;
    797 
    798 /* major and minor device number */
    799 major_minor:
    800 	MAJOR NUMBER MINOR NUMBER	{ $$ = makedev($2.val, $4.val); }
    801 ;
    802 
    803 /* optional ON keyword */
    804 on_opt:
    805 	  /* empty */
    806 	| ON
    807 ;
    808 
    809 /* number of pseudo devices to configure (which is optional) */
    810 npseudo:
    811 	  /* empty */			{ $$ = 1; }
    812 	| NUMBER			{ $$ = $1.val; }
    813 ;
    814 
    815 /* name of a device to configure */
    816 device_instance:
    817 	  WORD				{ $$ = $1; }
    818 	| WORD '*'			{ $$ = starref($1); }
    819 ;
    820 
    821 /* name of a device to configure an attachment to */
    822 attachment:
    823 	  ROOT				{ $$ = NULL; }
    824 	| WORD				{ $$ = $1; }
    825 	| WORD '?'			{ $$ = wildref($1); }
    826 ;
    827 
    828 /* zero or more locators */
    829 locators:
    830 	  /* empty */			{ $$ = NULL; }
    831 	| locators locator		{ $$ = $2; app($2, $1); }
    832 ;
    833 
    834 /* one locator */
    835 locator:
    836 	  WORD '?'			{ $$ = new_ns($1, NULL); }
    837 	| WORD values			{ $$ = mk_ns($1, $2); }
    838 ;
    839 
    840 /* optional device flags */
    841 flags_opt:
    842 	  /* empty */			{ $$ = 0; }
    843 	| FLAGS NUMBER			{ $$ = $2.val; }
    844 ;
    845 
    846 %%
    847 
    848 void
    849 yyerror(const char *s)
    850 {
    851 
    852 	cfgerror("%s", s);
    853 }
    854 
    855 /*
    856  * Cleanup procedure after syntax error: release any nvlists
    857  * allocated during parsing the current line.
    858  */
    859 static void
    860 cleanup(void)
    861 {
    862 	struct nvlist **np;
    863 	int i;
    864 
    865 	for (np = alloc, i = adepth; --i >= 0; np++)
    866 		nvfree(*np);
    867 	adepth = 0;
    868 }
    869 
    870 static void
    871 setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches,
    872 	int isioconf)
    873 {
    874 	char buf[MAXPATHLEN];
    875 	struct nvlist *nv;
    876 
    877 	if (isioconf) {
    878 		fprintf(stderr, "WARNING: ioconf is an experimental feature\n");
    879 		if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
    880 			exit(1);
    881 		ioconfname = mch;
    882 		return;
    883 	}
    884 
    885 	machine = mch;
    886 	machinearch = mcharch;
    887 	machinesubarches = mchsubarches;
    888 
    889 	/*
    890 	 * Define attributes for all the given names
    891 	 */
    892 	if (defattr(machine, NULL, NULL, 0) != 0 ||
    893 	    (machinearch != NULL &&
    894 	     defattr(machinearch, NULL, NULL, 0) != 0))
    895 		exit(1);
    896 	for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
    897 		if (defattr(nv->nv_name, NULL, NULL, 0) != 0)
    898 			exit(1);
    899 	}
    900 
    901 	/*
    902 	 * Set up the file inclusion stack.  This empty include tells
    903 	 * the parser there are no more device definitions coming.
    904 	 */
    905 	if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
    906 		exit(1);
    907 
    908 	/* Include arch/${MACHINE}/conf/files.${MACHINE} */
    909 	(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    910 	    machine, machine);
    911 	if (include(buf, ENDFILE, 0, 0) != 0)
    912 		exit(1);
    913 
    914 	/* Include any arch/${MACHINE_SUBARCH}/conf/files.${MACHINE_SUBARCH} */
    915 	for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
    916 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    917 		    nv->nv_name, nv->nv_name);
    918 		if (include(buf, ENDFILE, 0, 0) != 0)
    919 			exit(1);
    920 	}
    921 
    922 	/* Include any arch/${MACHINE_ARCH}/conf/files.${MACHINE_ARCH} */
    923 	if (machinearch != NULL)
    924 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    925 		    machinearch, machinearch);
    926 	else
    927 		strlcpy(buf, _PATH_DEVNULL, sizeof(buf));
    928 	if (include(buf, ENDFILE, 0, 0) != 0)
    929 		exit(1);
    930 
    931 	/*
    932 	 * Include the global conf/files.  As the last thing
    933 	 * pushed on the stack, it will be processed first.
    934 	 */
    935 	if (include("conf/files", ENDFILE, 0, 0) != 0)
    936 		exit(1);
    937 
    938 	oktopackage = 1;
    939 }
    940 
    941 static void
    942 check_maxpart(void)
    943 {
    944 
    945 	if (maxpartitions <= 0 && ioconfname == NULL) {
    946 		stop("cannot proceed without maxpartitions specifier");
    947 	}
    948 }
    949 
    950 static void
    951 check_version(void)
    952 {
    953 	/*
    954 	 * In essence, version is 0 and is not supported anymore
    955 	 */
    956 	if (version < CONFIG_MINVERSION)
    957 		stop("your sources are out of date -- please update.");
    958 }
    959 
    960 static void
    961 app(struct nvlist *p, struct nvlist *q)
    962 {
    963 	while (p->nv_next)
    964 		p = p->nv_next;
    965 	p->nv_next = q;
    966 }
    967 
    968 static struct nvlist *
    969 mk_nsis(const char *name, int count, struct nvlist *adefs, int opt)
    970 {
    971 	struct nvlist *defs = adefs;
    972 	struct nvlist **p;
    973 	char buf[200];
    974 	int i;
    975 
    976 	if (count <= 0) {
    977 		fprintf(stderr, "config: array with <= 0 size: %s\n", name);
    978 		exit(1);
    979 	}
    980 	p = &defs;
    981 	for(i = 0; i < count; i++) {
    982 		if (*p == NULL)
    983 			*p = new_s("0");
    984 		snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
    985 		(*p)->nv_name = i == 0 ? name : intern(buf);
    986 		(*p)->nv_num = i > 0 || opt;
    987 		p = &(*p)->nv_next;
    988 	}
    989 	*p = 0;
    990 	return defs;
    991 }
    992 
    993 
    994 static struct nvlist *
    995 mk_ns(const char *name, struct nvlist *vals)
    996 {
    997 	struct nvlist *p;
    998 	char buf[200];
    999 	int i;
   1000 
   1001 	for(i = 0, p = vals; p; i++, p = p->nv_next) {
   1002 		snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
   1003 		p->nv_name = i == 0 ? name : intern(buf);
   1004 	}
   1005 	return vals;
   1006 }
   1007 
   1008