Home | History | Annotate | Line # | Download | only in config
gram.y revision 1.29
      1 %{
      2 /*	$NetBSD: gram.y,v 1.29 2012/03/11 02:43:33 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 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>	device_flags
    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
    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 machine_spec definition_part configuration_part
    198 ;
    199 
    200 /* Sequence of zero or more topthings. */
    201 topthings:
    202 	  /* empty */
    203 	| topthings topthing
    204 ;
    205 
    206 /* Directory specification. */
    207 topthing:
    208 	                  '\n'
    209 	| SOURCE filename '\n'		{ if (!srcdir) srcdir = $2; }
    210 	| BUILD  filename '\n'		{ if (!builddir) builddir = $2; }
    211 ;
    212 
    213 /* "machine foo" from std.whatever */
    214 machine_spec:
    215 	  XMACHINE WORD '\n'			{ setmachine($2,NULL,NULL,0); }
    216 	| XMACHINE WORD WORD '\n'		{ setmachine($2,$3,NULL,0); }
    217 	| XMACHINE WORD WORD subarches '\n'	{ setmachine($2,$3,$4,0); }
    218 	| IOCONF WORD '\n'			{ setmachine($2,NULL,NULL,1); }
    219 	| error { stop("cannot proceed without machine or ioconf specifier"); }
    220 ;
    221 
    222 /* One or more sub-arches. */
    223 subarches:
    224 	  WORD				{ $$ = new_n($1); }
    225 	| subarches WORD		{ $$ = new_nx($2, $1); }
    226 ;
    227 
    228 /************************************************************/
    229 
    230 /*
    231  * The machine definitions grammar.
    232  */
    233 
    234 /* Complete definition part: the contents of all files.* files. */
    235 definition_part:
    236 	definitions ENDDEFS		{ check_maxpart(); check_version(); }
    237 ;
    238 
    239 /* Zero or more definitions. Trap errors. */
    240 definitions:
    241 	  /* empty */
    242 	| definitions '\n'
    243 	| definitions definition '\n'	{ adepth = 0; }
    244 	| definitions error '\n'	{ cleanup(); }
    245 	| definitions ENDFILE		{ enddefs(); checkfiles(); }
    246 ;
    247 
    248 /* A single definition. */
    249 definition:
    250 	  file
    251 	| object
    252 	| device_major			{ do_devsw = 1; }
    253 	| prefix
    254 	| DEVCLASS WORD			{ (void)defattr($2, NULL, NULL, 1); }
    255 	| DEFFS deffses defoptdeps	{ deffilesystem($2, $3); }
    256 	| DEFINE WORD interface_opt attrs_opt
    257 					{ (void)defattr($2, $3, $4, 0); }
    258 	| DEFOPT optfile_opt defopts defoptdeps
    259 					{ defoption($2, $3, $4); }
    260 	| DEFFLAG optfile_opt defopts defoptdeps
    261 					{ defflag($2, $3, $4, 0); }
    262 	| OBSOLETE DEFFLAG optfile_opt defopts
    263 					{ defflag($3, $4, NULL, 1); }
    264 	| DEFPARAM optfile_opt defopts defoptdeps
    265 					{ defparam($2, $3, $4, 0); }
    266 	| OBSOLETE DEFPARAM optfile_opt defopts
    267 					{ defparam($3, $4, NULL, 1); }
    268 	| DEVICE devbase interface_opt attrs_opt
    269 					{ defdev($2, $3, $4, 0); }
    270 	| ATTACH devbase AT atlist devattach_opt attrs_opt
    271 					{ defdevattach($5, $2, $4, $6); }
    272 	| MAXPARTITIONS NUMBER		{ maxpartitions = $2.val; }
    273 	| MAXUSERS NUMBER NUMBER NUMBER
    274 				    { setdefmaxusers($2.val, $3.val, $4.val); }
    275 	| MAKEOPTIONS condmkopt_list
    276 	/* interface_opt in DEFPSEUDO is for backwards compatibility */
    277 	| DEFPSEUDO devbase interface_opt attrs_opt
    278 					{ defdev($2, $3, $4, 1); }
    279 	| DEFPSEUDODEV devbase interface_opt attrs_opt
    280 					{ defdev($2, $3, $4, 2); }
    281 	| MAJOR '{' majorlist '}'
    282 	| VERSION NUMBER		{ setversion($2.val); }
    283 ;
    284 
    285 /* source file: file foo/bar.c bar|baz needs-flag compile-with blah */
    286 file:
    287 	XFILE filename fopts fflgs rule	{ addfile($2, $3, $4, $5); }
    288 ;
    289 
    290 /* file options: optional expression of config elements */
    291 fopts:
    292 	  /* empty */			{ $$ = NULL; }
    293 	| fexpr				{ $$ = $1; }
    294 ;
    295 
    296 /* zero or more flags for a file */
    297 fflgs:
    298 	  /* empty */			{ $$ = 0; }
    299 	| fflgs fflag			{ $$ = $1 | $2; }
    300 ;
    301 
    302 /* one flag for a file */
    303 fflag:
    304 	  NEEDS_COUNT			{ $$ = FI_NEEDSCOUNT; }
    305 	| NEEDS_FLAG			{ $$ = FI_NEEDSFLAG; }
    306 ;
    307 
    308 /* extra compile directive for a source file */
    309 rule:
    310 	  /* empty */			{ $$ = NULL; }
    311 	| COMPILE_WITH stringvalue	{ $$ = $2; }
    312 ;
    313 
    314 /* object file: object zot.o foo|zot needs-flag */
    315 object:
    316 	XOBJECT filename fopts oflgs	{ addobject($2, $3, $4); }
    317 ;
    318 
    319 /* zero or more flags for an object file */
    320 oflgs:
    321 	  /* empty */			{ $$ = 0; }
    322 	| oflgs oflag			{ $$ = $1 | $2; }
    323 ;
    324 
    325 /* a single flag for an object file */
    326 oflag:
    327 	NEEDS_FLAG			{ $$ = OI_NEEDSFLAG; }
    328 ;
    329 
    330 /* device major declaration */
    331 device_major:
    332 	DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes
    333 					{ adddevm($2, $3, $4, $5, $6); }
    334 ;
    335 
    336 /* char 55 */
    337 device_major_char:
    338 	  /* empty */			{ $$ = -1; }
    339 	| CHAR NUMBER			{ $$ = $2.val; }
    340 ;
    341 
    342 /* block 33 */
    343 device_major_block:
    344 	  /* empty */			{ $$ = -1; }
    345 	| BLOCK NUMBER			{ $$ = $2.val; }
    346 ;
    347 
    348 /* device node specification */
    349 devnodes:
    350 	  /* empty */			{ $$ = new_s("DEVNODE_DONTBOTHER"); }
    351 	| devnodetype ',' devnodeflags	{ $$ = nvcat($1, $3); }
    352 	| devnodetype			{ $$ = $1; }
    353 ;
    354 
    355 /* device nodes without flags */
    356 devnodetype:
    357 	  SINGLE			{ $$ = new_s("DEVNODE_SINGLE"); }
    358 	| VECTOR '=' devnode_dims  { $$ = nvcat(new_s("DEVNODE_VECTOR"), $3); }
    359 ;
    360 
    361 /* dimensions (?) */
    362 devnode_dims:
    363 	  NUMBER			{ $$ = new_i($1.val); }
    364 	| NUMBER ':' NUMBER		{
    365 		struct nvlist *__nv1, *__nv2;
    366 
    367 		__nv1 = new_i($1.val);
    368 		__nv2 = new_i($3.val);
    369 		$$ = nvcat(__nv1, __nv2);
    370 	  }
    371 ;
    372 
    373 /* flags for device nodes */
    374 devnodeflags:
    375 	LINKZERO			{ $$ = new_s("DEVNODE_FLAG_LINKZERO");}
    376 ;
    377 
    378 /* prefix delimiter */
    379 prefix:
    380 	  PREFIX filename		{ prefix_push($2); }
    381 	| PREFIX			{ prefix_pop(); }
    382 ;
    383 
    384 /* one or more file system names */
    385 deffses:
    386 	  deffs				{ $$ = new_n($1); }
    387 	| deffses deffs			{ $$ = new_nx($2, $1); }
    388 ;
    389 
    390 /* a single file system name */
    391 deffs:
    392 	WORD				{ $$ = $1; }
    393 ;
    394 
    395 /* optional locator specification */
    396 interface_opt:
    397 	  /* empty */			{ $$ = NULL; }
    398 	| '{' '}'			{ $$ = new_nx("", NULL); }
    399 	| '{' loclist '}'		{ $$ = new_nx("", $2); }
    400 ;
    401 
    402 /*
    403  * loclist order matters, must use right recursion
    404  * XXX wot?
    405  */
    406 
    407 /* list of locator definitions */
    408 loclist:
    409 	  locdef			{ $$ = $1; }
    410 	| locdef ',' loclist		{ $$ = $1; app($1, $3); }
    411 ;
    412 
    413 /*
    414  * "[ WORD locdefault ]" syntax may be unnecessary...
    415  */
    416 
    417 /* one locator definition */
    418 locdef:
    419 	  locname locdefault 		{ $$ = new_nsi($1, $2, 0); }
    420 	| locname			{ $$ = new_nsi($1, NULL, 0); }
    421 	| '[' locname locdefault ']'	{ $$ = new_nsi($2, $3, 1); }
    422 	| locname '[' NUMBER ']'	{ $$ = mk_nsis($1, $3.val, NULL, 0); }
    423 	| locname '[' NUMBER ']' locdefaults
    424 					{ $$ = mk_nsis($1, $3.val, $5, 0); }
    425 	| '[' locname '[' NUMBER ']' locdefaults ']'
    426 					{ $$ = mk_nsis($2, $4.val, $6, 1); }
    427 ;
    428 
    429 /* locator name */
    430 locname:
    431 	  WORD				{ $$ = $1; }
    432 	| QSTRING			{ $$ = $1; }
    433 ;
    434 
    435 /* locator default value */
    436 locdefault:
    437 	'=' value			{ $$ = $2; }
    438 ;
    439 
    440 /* multiple locator default values */
    441 locdefaults:
    442 	'=' '{' values '}'		{ $$ = $3; }
    443 ;
    444 
    445 /* optional attributes */
    446 attrs_opt:
    447 	  /* empty */			{ $$ = NULL; }
    448 	| ':' attrs			{ $$ = $2; }
    449 ;
    450 
    451 /* one or more attributes */
    452 attrs:
    453 	  attr				{ $$ = new_p($1); }
    454 	| attrs ',' attr		{ $$ = new_px($3, $1); }
    455 ;
    456 
    457 /* one attribute */
    458 attr:
    459 	WORD				{ $$ = getattr($1); }
    460 ;
    461 
    462 /* list of places to attach: attach blah at ... */
    463 atlist:
    464 	  atname			{ $$ = new_n($1); }
    465 	| atlist ',' atname		{ $$ = new_nx($3, $1); }
    466 ;
    467 
    468 /* a place to attach a device */
    469 atname:
    470 	  WORD				{ $$ = $1; }
    471 	| ROOT				{ $$ = NULL; }
    472 ;
    473 
    474 /* one or more defined options */
    475 defopts:
    476 	  defopt			{ $$ = $1; }
    477 	| defopts defopt		{ $$ = nvcat($2, $1); }
    478 ;
    479 
    480 /* one defined option */
    481 defopt:
    482 	  WORD				{ $$ = new_n($1); }
    483 	| WORD '=' value		{ $$ = new_ns($1, $3); }
    484 	| WORD COLONEQ value		{
    485 		struct nvlist *__nv = new_n($1);
    486 
    487 		$$ = new_nsx("", $3, __nv);
    488 	  }
    489 	| WORD '=' value COLONEQ value	{
    490 		struct nvlist *__nv = new_n($1);
    491 
    492 		$$ = new_nsx("", $5, __nv);
    493 	  }
    494 ;
    495 
    496 /* option dependencies (read as "defopt deps") which are optional */
    497 defoptdeps:
    498 	  /* empty */			{ $$ = NULL; }
    499 	| ':' optdeps			{ $$ = $2; }
    500 ;
    501 
    502 /* a list of option dependencies */
    503 optdeps:
    504 	  optdep			{ $$ = new_n($1); }
    505 	| optdeps ',' optdep		{ $$ = new_nx($3, $1); }
    506 ;
    507 
    508 /* one option dependence */
    509 optdep:
    510 	WORD				{ $$ = $1; }
    511 ;
    512 
    513 /* list of conditional makeoptions */
    514 condmkopt_list:
    515 	  condmkoption
    516 	| condmkopt_list ',' condmkoption
    517 ;
    518 
    519 /* one conditional make option */
    520 condmkoption:
    521 	fexpr mkvarname PLUSEQ value	{ appendcondmkoption($1, $2, $4); }
    522 ;
    523 
    524 /* device name */
    525 devbase:
    526 	WORD				{ $$ = getdevbase($1); }
    527 ;
    528 
    529 /* optional attachment: with foo */
    530 devattach_opt:
    531 	  /* empty */			{ $$ = NULL; }
    532 	| WITH WORD			{ $$ = getdevattach($2); }
    533 ;
    534 
    535 /* list of major numbers */
    536 /* XXX why is this right-recursive? */
    537 majorlist:
    538 	  majordef
    539 	| majorlist ',' majordef
    540 ;
    541 
    542 /* one major number */
    543 majordef:
    544 	devbase '=' NUMBER		{ setmajor($1, $3.val); }
    545 ;
    546 
    547 /************************************************************/
    548 
    549 /*
    550  * The configuration grammar.
    551  */
    552 
    553 /* Complete configuration part: all std.* files plus selected config. */
    554 configuration_part:
    555 	config_items
    556 ;
    557 
    558 /* Zero or more config items. Trap errors. */
    559 config_items:
    560 	  /* empty */
    561 	| config_items '\n'
    562 	| config_items config_item '\n'	{ adepth = 0; }
    563 	| config_items error '\n'	{ cleanup(); }
    564 ;
    565 
    566 /* One config item. */
    567 config_item:
    568 	  definition
    569 	| NO FILE_SYSTEM no_fs_list
    570 	| FILE_SYSTEM fs_list
    571 	| NO MAKEOPTIONS no_mkopt_list
    572 	| MAKEOPTIONS mkopt_list
    573 	| NO OPTIONS no_opt_list
    574 	| OPTIONS opt_list
    575 	| MAXUSERS NUMBER		{ setmaxusers($2.val); }
    576 	| IDENT stringvalue		{ setident($2); }
    577 	| CONFIG conf root_spec sysparam_list
    578 					{ addconf(&conf); }
    579 	| NO CONFIG WORD		{ delconf($3); }
    580 	| NO PSEUDO_DEVICE WORD		{ delpseudo($3); }
    581 	| PSEUDO_DEVICE WORD npseudo	{ addpseudo($2, $3); }
    582 	| PSEUDO_ROOT device_instance	{ addpseudoroot($2); }
    583 	| NO device_instance AT attachment
    584 					{ deldevi($2, $4); }
    585 	| NO DEVICE AT attachment	{ deldeva($4); }
    586 	| NO device_instance		{ deldev($2); }
    587 	| device_instance AT attachment locators device_flags
    588 					{ adddev($1, $3, $4, $5); }
    589 ;
    590 
    591 /* list of filesystems */
    592 fs_list:
    593 	  fsoption
    594 	| fs_list ',' fsoption
    595 ;
    596 
    597 /* one filesystem */
    598 fsoption:
    599 	WORD				{ addfsoption($1); }
    600 ;
    601 
    602 /* list of filesystems that had NO in front */
    603 no_fs_list:
    604 	  no_fsoption
    605 	| no_fs_list ',' no_fsoption
    606 ;
    607 
    608 /* one filesystem that had NO in front */
    609 no_fsoption:
    610 	WORD				{ delfsoption($1); }
    611 ;
    612 
    613 /* list of make options */
    614 /* XXX why is this right-recursive? */
    615 mkopt_list:
    616 	  mkoption
    617 	| mkopt_list ',' mkoption
    618 ;
    619 
    620 /* one make option */
    621 mkoption:
    622 	  mkvarname '=' value		{ addmkoption($1, $3); }
    623 	| mkvarname PLUSEQ value	{ appendmkoption($1, $3); }
    624 ;
    625 
    626 /* list of make options that had NO in front */
    627 no_mkopt_list:
    628 	  no_mkoption
    629 	| no_mkopt_list ',' no_mkoption
    630 ;
    631 
    632 /* one make option that had NO in front */
    633 /* XXX shouldn't this be mkvarname rather than WORD? */
    634 no_mkoption:
    635 	WORD				{ delmkoption($1); }
    636 ;
    637 
    638 /* list of options */
    639 opt_list:
    640 	  option
    641 	| opt_list ',' option
    642 ;
    643 
    644 /* one option */
    645 option:
    646 	  WORD				{ addoption($1, NULL); }
    647 	| WORD '=' value		{ addoption($1, $3); }
    648 ;
    649 
    650 /* list of options that had NO in front */
    651 no_opt_list:
    652 	  no_option
    653 	| no_opt_list ',' no_option
    654 ;
    655 
    656 /* one option that had NO in front */
    657 no_option:
    658 	WORD				{ deloption($1); }
    659 ;
    660 
    661 /* the name in "config name root on ..." */
    662 conf:
    663 	WORD				{
    664 		conf.cf_name = $1;
    665 		conf.cf_lineno = currentline();
    666 		conf.cf_fstype = NULL;
    667 		conf.cf_root = NULL;
    668 		conf.cf_dump = NULL;
    669 	}
    670 ;
    671 
    672 /* root fs specification */
    673 root_spec:
    674 	  ROOT on_opt dev_spec		{ setconf(&conf.cf_root, "root", $3); }
    675 	| ROOT on_opt dev_spec fs_spec	{ setconf(&conf.cf_root, "root", $3); }
    676 ;
    677 
    678 /* device for root fs or dump */
    679 dev_spec:
    680 	  '?'				{ $$ = new_si(intern("?"), NODEV); }
    681 	| WORD				{ $$ = new_si($1, NODEV); }
    682 	| major_minor			{ $$ = new_si(NULL, $1); }
    683 ;
    684 
    685 /* major and minor device number */
    686 major_minor:
    687 	MAJOR NUMBER MINOR NUMBER	{ $$ = makedev($2.val, $4.val); }
    688 ;
    689 
    690 /* filesystem type for root fs specification */
    691 fs_spec:
    692 	  TYPE '?'		   { setfstype(&conf.cf_fstype, intern("?")); }
    693 	| TYPE WORD			{ setfstype(&conf.cf_fstype, $2); }
    694 ;
    695 
    696 /* zero or more additional system parameters */
    697 sysparam_list:
    698 	  /* empty */
    699 	| sysparam_list sysparam
    700 ;
    701 
    702 /* one additional system parameter (there's only one: dumps) */
    703 sysparam:
    704 	DUMPS on_opt dev_spec	       { setconf(&conf.cf_dump, "dumps", $3); }
    705 ;
    706 
    707 /* number of pseudo devices to configure (which is optional) */
    708 npseudo:
    709 	  /* empty */			{ $$ = 1; }
    710 	| NUMBER			{ $$ = $1.val; }
    711 ;
    712 
    713 /* name of a device to configure */
    714 device_instance:
    715 	  WORD				{ $$ = $1; }
    716 	| WORD '*'			{ $$ = starref($1); }
    717 ;
    718 
    719 /* name of a device to configure an attachment to */
    720 attachment:
    721 	  ROOT				{ $$ = NULL; }
    722 	| WORD				{ $$ = $1; }
    723 	| WORD '?'			{ $$ = wildref($1); }
    724 ;
    725 
    726 /* zero or more locators */
    727 locators:
    728 	  /* empty */			{ $$ = NULL; }
    729 	| locators locator		{ $$ = $2; app($2, $1); }
    730 ;
    731 
    732 /* one locator */
    733 locator:
    734 	  WORD '?'			{ $$ = new_ns($1, NULL); }
    735 	| WORD values			{ $$ = mk_ns($1, $2); }
    736 ;
    737 
    738 /* optional device flags */
    739 device_flags:
    740 	  /* empty */			{ $$ = 0; }
    741 	| FLAGS NUMBER			{ $$ = $2.val; }
    742 ;
    743 
    744 /************************************************************/
    745 
    746 /*
    747  * dependency logic
    748  */
    749 
    750 
    751 /*
    752  * order of options is important, must use right recursion
    753  *
    754  * dholland 20120310: wut?
    755  */
    756 
    757 /* expression of config elements */
    758 /* XXX this should use a real expression grammar */
    759 fexpr:
    760 	  fatom				{ $$ = $1; }
    761 	| '!' fatom			{ $$ = fx_not($2); }
    762 	| fexpr '&' fexpr		{ $$ = fx_and($1, $3); }
    763 	| fexpr '|' fexpr		{ $$ = fx_or($1, $3); }
    764 	| '(' fexpr ')'			{ $$ = $2; }
    765 ;
    766 
    767 /* basic element of config element expression: a config element */
    768 fatom:
    769 	WORD				{ $$ = fx_atom($1); }
    770 ;
    771 
    772 /************************************************************/
    773 
    774 /*
    775  * Various nonterminals shared between the grammars.
    776  */
    777 
    778 /* variable name for make option */
    779 mkvarname:
    780 	  QSTRING			{ $$ = $1; }
    781 	| WORD				{ $$ = $1; }
    782 ;
    783 
    784 /* optional file for an option */
    785 optfile_opt:
    786 	  /* empty */			{ $$ = NULL; }
    787 	| filename			{ $$ = $1; }
    788 ;
    789 
    790 /* filename. */
    791 filename:
    792 	  QSTRING			{ $$ = $1; }
    793 	| PATHNAME			{ $$ = $1; }
    794 ;
    795 
    796 /* constant value */
    797 value:
    798 	  QSTRING			{ $$ = $1; }
    799 	| WORD				{ $$ = $1; }
    800 	| EMPTYSTRING			{ $$ = $1; }
    801 	| signed_number			{
    802 		char bf[40];
    803 
    804 		(void)snprintf(bf, sizeof(bf), FORMAT($1), (long long)$1.val);
    805 		$$ = intern(bf);
    806 	  }
    807 ;
    808 
    809 /* constant value that is a string */
    810 stringvalue:
    811 	  QSTRING			{ $$ = $1; }
    812 	| WORD				{ $$ = $1; }
    813 ;
    814 
    815 /* comma-separated list of values */
    816 /* XXX why right-recursive? */
    817 values:
    818 	  value				{ $$ = new_s($1); }
    819 	| value ',' values		{ $$ = new_sx($1, $3); }
    820 ;
    821 
    822 /* possibly negative number */
    823 signed_number:
    824 	  NUMBER			{ $$ = $1; }
    825 	| '-' NUMBER			{ $$.fmt = $2.fmt; $$.val = -$2.val; }
    826 ;
    827 
    828 /* optional ON keyword */
    829 on_opt:
    830 	  /* empty */
    831 	| ON
    832 ;
    833 
    834 %%
    835 
    836 void
    837 yyerror(const char *s)
    838 {
    839 
    840 	cfgerror("%s", s);
    841 }
    842 
    843 /*
    844  * Cleanup procedure after syntax error: release any nvlists
    845  * allocated during parsing the current line.
    846  */
    847 static void
    848 cleanup(void)
    849 {
    850 	struct nvlist **np;
    851 	int i;
    852 
    853 	for (np = alloc, i = adepth; --i >= 0; np++)
    854 		nvfree(*np);
    855 	adepth = 0;
    856 }
    857 
    858 static void
    859 setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches,
    860 	int isioconf)
    861 {
    862 	char buf[MAXPATHLEN];
    863 	struct nvlist *nv;
    864 
    865 	if (isioconf) {
    866 		fprintf(stderr, "WARNING: ioconf is an experimental feature\n");
    867 		if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
    868 			exit(1);
    869 		ioconfname = mch;
    870 		return;
    871 	}
    872 
    873 	machine = mch;
    874 	machinearch = mcharch;
    875 	machinesubarches = mchsubarches;
    876 
    877 	/*
    878 	 * Define attributes for all the given names
    879 	 */
    880 	if (defattr(machine, NULL, NULL, 0) != 0 ||
    881 	    (machinearch != NULL &&
    882 	     defattr(machinearch, NULL, NULL, 0) != 0))
    883 		exit(1);
    884 	for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
    885 		if (defattr(nv->nv_name, NULL, NULL, 0) != 0)
    886 			exit(1);
    887 	}
    888 
    889 	/*
    890 	 * Set up the file inclusion stack.  This empty include tells
    891 	 * the parser there are no more device definitions coming.
    892 	 */
    893 	if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
    894 		exit(1);
    895 
    896 	/* Include arch/${MACHINE}/conf/files.${MACHINE} */
    897 	(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    898 	    machine, machine);
    899 	if (include(buf, ENDFILE, 0, 0) != 0)
    900 		exit(1);
    901 
    902 	/* Include any arch/${MACHINE_SUBARCH}/conf/files.${MACHINE_SUBARCH} */
    903 	for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
    904 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    905 		    nv->nv_name, nv->nv_name);
    906 		if (include(buf, ENDFILE, 0, 0) != 0)
    907 			exit(1);
    908 	}
    909 
    910 	/* Include any arch/${MACHINE_ARCH}/conf/files.${MACHINE_ARCH} */
    911 	if (machinearch != NULL)
    912 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    913 		    machinearch, machinearch);
    914 	else
    915 		strlcpy(buf, _PATH_DEVNULL, sizeof(buf));
    916 	if (include(buf, ENDFILE, 0, 0) != 0)
    917 		exit(1);
    918 
    919 	/*
    920 	 * Include the global conf/files.  As the last thing
    921 	 * pushed on the stack, it will be processed first.
    922 	 */
    923 	if (include("conf/files", ENDFILE, 0, 0) != 0)
    924 		exit(1);
    925 
    926 	oktopackage = 1;
    927 }
    928 
    929 static void
    930 check_maxpart(void)
    931 {
    932 
    933 	if (maxpartitions <= 0 && ioconfname == NULL) {
    934 		stop("cannot proceed without maxpartitions specifier");
    935 	}
    936 }
    937 
    938 static void
    939 check_version(void)
    940 {
    941 	/*
    942 	 * In essence, version is 0 and is not supported anymore
    943 	 */
    944 	if (version < CONFIG_MINVERSION)
    945 		stop("your sources are out of date -- please update.");
    946 }
    947 
    948 static void
    949 app(struct nvlist *p, struct nvlist *q)
    950 {
    951 	while (p->nv_next)
    952 		p = p->nv_next;
    953 	p->nv_next = q;
    954 }
    955 
    956 static struct nvlist *
    957 mk_nsis(const char *name, int count, struct nvlist *adefs, int opt)
    958 {
    959 	struct nvlist *defs = adefs;
    960 	struct nvlist **p;
    961 	char buf[200];
    962 	int i;
    963 
    964 	if (count <= 0) {
    965 		fprintf(stderr, "config: array with <= 0 size: %s\n", name);
    966 		exit(1);
    967 	}
    968 	p = &defs;
    969 	for(i = 0; i < count; i++) {
    970 		if (*p == NULL)
    971 			*p = new_s("0");
    972 		snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
    973 		(*p)->nv_name = i == 0 ? name : intern(buf);
    974 		(*p)->nv_num = i > 0 || opt;
    975 		p = &(*p)->nv_next;
    976 	}
    977 	*p = 0;
    978 	return defs;
    979 }
    980 
    981 
    982 static struct nvlist *
    983 mk_ns(const char *name, struct nvlist *vals)
    984 {
    985 	struct nvlist *p;
    986 	char buf[200];
    987 	int i;
    988 
    989 	for(i = 0, p = vals; p; i++, p = p->nv_next) {
    990 		snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
    991 		p->nv_name = i == 0 ? name : intern(buf);
    992 	}
    993 	return vals;
    994 }
    995 
    996