1 %{
2 /*	$OpenBSD: gram.y,v 1.18 2004/01/04 00:47:01 deraadt Exp $	*/
3 /*	$NetBSD: gram.y,v 1.14 1997/02/02 21:12:32 thorpej Exp $	*/
4 
5 /*
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Lawrence Berkeley Laboratories.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *	from: @(#)gram.y	8.1 (Berkeley) 6/6/93
43  */
44 
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <ctype.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <errno.h>
52 #include "config.h"
53 #include "sem.h"
54 
55 __RCSID("$MirOS: src/usr.sbin/config/gram.y,v 1.3 2007/02/19 03:24:55 tg Exp $");
56 
57 #define	FORMAT(n) ((n) > -10 && (n) < 10 ? "%d" : "0x%x")
58 
59 #define	stop(s)	error(s), exit(1)
60 
61 void	yyerror(const char *);
62 int	yylex(void);
63 
64 static	struct	config conf;	/* at most one active at a time */
65 
66 /* the following is used to recover nvlist space after errors */
67 static	struct	nvlist *alloc[1000];
68 static	int	adepth;
69 #define	new0(n,s,p,i,x)	(alloc[adepth++] = newnv(n, s, p, i, x))
70 #define	new_n(n)	new0(n, NULL, NULL, 0, NULL)
71 #define	new_nx(n, x)	new0(n, NULL, NULL, 0, x)
72 #define	new_ns(n, s)	new0(n, s, NULL, 0, NULL)
73 #define	new_si(s, i)	new0(NULL, s, NULL, i, NULL)
74 #define	new_nsi(n,s,i)	new0(n, s, NULL, i, NULL)
75 #define	new_np(n, p)	new0(n, NULL, p, 0, NULL)
76 #define	new_s(s)	new0(NULL, s, NULL, 0, NULL)
77 #define	new_p(p)	new0(NULL, NULL, p, 0, NULL)
78 #define	new_px(p, x)	new0(NULL, NULL, p, 0, x)
79 
80 #define	fx_atom(s)	new0(s, NULL, NULL, FX_ATOM, NULL)
81 #define	fx_not(e)	new0(NULL, NULL, NULL, FX_NOT, e)
82 #define	fx_and(e1, e2)	new0(NULL, NULL, e1, FX_AND, e2)
83 #define	fx_or(e1, e2)	new0(NULL, NULL, e1, FX_OR, e2)
84 
85 static	void	cleanup(void);
86 static	void	setmachine(const char *, const char *);
87 static	void	check_maxpart(void);
88 
89 %}
90 
91 %union {
92 	struct	attr *attr;
93 	struct	devbase *devb;
94 	struct	deva *deva;
95 	struct	nvlist *list;
96 	const char *str;
97 	int	val;
98 }
99 
100 %token	AND AT ATTACH BUILD COMPILE_WITH CONFIG DEFINE DEFOPT DEVICE DISABLE
101 %token	DUMPS ENDFILE XFILE XOBJECT FLAGS INCLUDE XMACHINE MAJOR MAKEOPTIONS
102 %token	MAXUSERS MAXPARTITIONS MINOR ON OPTIONS PSEUDO_DEVICE ROOT SOURCE SWAP
103 %token	WITH NEEDS_COUNT NEEDS_FLAG RMOPTIONS ENABLE
104 %token	<val> NUMBER
105 %token	<str> PATHNAME WORD EMPTY
106 
107 %left '|'
108 %left '&'
109 
110 %type	<list>	fopts fexpr fatom
111 %type	<val>	fflgs fflag oflgs oflag
112 %type	<str>	rule
113 %type	<attr>	attr
114 %type	<devb>	devbase
115 %type	<deva>	devattach_opt
116 %type	<val>	disable
117 %type	<list>	atlist interface_opt
118 %type	<str>	atname
119 %type	<list>	loclist_opt loclist locdef
120 %type	<str>	locdefault
121 %type	<list>	attrs_opt attrs
122 %type	<list>	locators locator
123 %type	<list>	swapdev_list dev_spec
124 %type	<str>	device_instance
125 %type	<str>	attachment
126 %type	<str>	value
127 %type	<val>	major_minor signed_number npseudo
128 %type	<val>	flags_opt
129 
130 %%
131 
132 /*
133  * A configuration consists of a machine type, followed by the machine
134  * definition files (via the include() mechanism), followed by the
135  * configuration specification(s) proper.  In effect, this is two
136  * separate grammars, with some shared terminals and nonterminals.
137  * Note that we do not have sufficient keywords to enforce any order
138  * between elements of "topthings" without introducing shift/reduce
139  * conflicts.  Instead, check order requirements in the C code.
140  */
141 Configuration:
142 	topthings			/* dirspecs, include "std.arch" */
143 	machine_spec			/* "machine foo" from machine descr. */
144 	dev_defs dev_eof		/* sys/conf/files */
145 	dev_defs dev_eof		/* sys/arch/${MACHINE_ARCH}/... */
146 	dev_defs dev_eof		/* sys/arch/${MACHINE}/... */
147 					{ check_maxpart(); }
148 	specs;				/* rest of machine description */
149 
150 topthings:
151 	topthings topthing |
152 	/* empty */;
153 
154 topthing:
155 	SOURCE PATHNAME '\n'		{ if (!srcdir) srcdir = $2; } |
156 	BUILD  PATHNAME '\n'		{ if (!builddir) builddir = $2; } |
157 	include '\n' |
158 	'\n';
159 
160 machine_spec:
161 	XMACHINE WORD '\n'		{ setmachine($2,NULL); } |
162 	XMACHINE WORD WORD '\n'		{ setmachine($2,$3); } |
163 	error { stop("cannot proceed without machine specifier"); };
164 
165 dev_eof:
166 	ENDFILE				{ enddefs(); checkfiles(); };
167 
168 /*
169  * Various nonterminals shared between the grammars.
170  */
171 file:
172 	XFILE PATHNAME fopts fflgs rule	{ addfile($2, $3, $4, $5); };
173 
174 object:
175 	XOBJECT PATHNAME fopts oflgs	{ addobject($2, $3, $4); };
176 
177 /* order of options is important, must use right recursion */
178 fopts:
179 	fexpr				{ $$ = $1; } |
180 	/* empty */			{ $$ = NULL; };
181 
182 fexpr:
183 	fatom				{ $$ = $1; } |
184 	'!' fatom			{ $$ = fx_not($2); } |
185 	fexpr '&' fexpr			{ $$ = fx_and($1, $3); } |
186 	fexpr '|' fexpr			{ $$ = fx_or($1, $3); } |
187 	'(' fexpr ')'			{ $$ = $2; };
188 
189 fatom:
190 	WORD				{ $$ = fx_atom($1); };
191 
192 fflgs:
193 	fflgs fflag			{ $$ = $1 | $2; } |
194 	/* empty */			{ $$ = 0; };
195 
196 fflag:
197 	NEEDS_COUNT			{ $$ = FI_NEEDSCOUNT; } |
198 	NEEDS_FLAG			{ $$ = FI_NEEDSFLAG; };
199 
200 oflgs:
201 	oflgs oflag			{ $$ = $1 | $2; } |
202 	/* empty */			{ $$ = 0; };
203 
204 oflag:
205 	NEEDS_FLAG			{ $$ = OI_NEEDSFLAG; };
206 
207 rule:
208 	COMPILE_WITH WORD		{ $$ = $2; } |
209 	/* empty */			{ $$ = NULL; };
210 
211 include:
212 	INCLUDE WORD			{ include($2, 0); };
213 
214 
215 /*
216  * The machine definitions grammar.
217  */
218 dev_defs:
219 	dev_defs dev_def |
220 	/* empty */;
221 
222 dev_def:
223 	one_def '\n'			{ adepth = 0; } |
224 	'\n' |
225 	error '\n'			{ cleanup(); };
226 
227 one_def:
228 	file |
229 	object |
230 	include |
231 	DEFINE WORD interface_opt	{ (void)defattr($2, $3); } |
232 	DEFOPT WORD			{ defoption($2); } |
233 	DEVICE devbase interface_opt attrs_opt
234 					{ defdev($2, 0, $3, $4); } |
235 	ATTACH devbase AT atlist devattach_opt attrs_opt
236 					{ defdevattach($5, $2, $4, $6); } |
237 	MAXUSERS NUMBER NUMBER NUMBER	{ setdefmaxusers($2, $3, $4); } |
238 	MAXPARTITIONS NUMBER		{ maxpartitions = $2; } |
239 	PSEUDO_DEVICE devbase attrs_opt { defdev($2,1,NULL,$3); } |
240 	MAJOR '{' majorlist '}';
241 
242 disable:
243 	DISABLE				{ $$ = 1; } |
244 	/* empty */			{ $$ = 0; };
245 
246 atlist:
247 	atlist ',' atname		{ $$ = new_nx($3, $1); } |
248 	atname				{ $$ = new_n($1); };
249 
250 atname:
251 	WORD				{ $$ = $1; } |
252 	ROOT				{ $$ = NULL; };
253 
254 devbase:
255 	WORD				{ $$ = getdevbase($1); };
256 
257 devattach_opt:
258 	WITH WORD			{ $$ = getdevattach($2); } |
259 	/* empty */			{ $$ = NULL; };
260 
261 interface_opt:
262 	'{' loclist_opt '}'		{ $$ = new_nx("", $2); } |
263 	/* empty */			{ $$ = NULL; };
264 
265 loclist_opt:
266 	loclist				{ $$ = $1; } |
267 	/* empty */			{ $$ = NULL; };
268 
269 /* loclist order matters, must use right recursion */
270 loclist:
271 	locdef ',' loclist		{ ($$ = $1)->nv_next = $3; } |
272 	locdef				{ $$ = $1; };
273 
274 /* "[ WORD locdefault ]" syntax may be unnecessary... */
275 locdef:
276 	WORD locdefault			{ $$ = new_nsi($1, $2, 0); } |
277 	WORD				{ $$ = new_nsi($1, NULL, 0); } |
278 	'[' WORD locdefault ']'		{ $$ = new_nsi($2, $3, 1); };
279 
280 locdefault:
281 	'=' value			{ $$ = $2; };
282 
283 value:
284 	WORD				{ $$ = $1; } |
285 	EMPTY				{ $$ = $1; } |
286 	signed_number			{
287 						char bf[40];
288 
289 						(void)snprintf(bf, sizeof bf,
290 						    FORMAT($1), $1);
291 						$$ = intern(bf);
292 					};
293 
294 signed_number:
295 	NUMBER				{ $$ = $1; } |
296 	'-' NUMBER			{ $$ = -$2; };
297 
298 attrs_opt:
299 	':' attrs			{ $$ = $2; } |
300 	/* empty */			{ $$ = NULL; };
301 
302 attrs:
303 	attrs ',' attr			{ $$ = new_px($3, $1); } |
304 	attr				{ $$ = new_p($1); };
305 
306 attr:
307 	WORD				{ $$ = getattr($1); };
308 
309 majorlist:
310 	majorlist ',' majordef |
311 	majordef;
312 
313 majordef:
314 	devbase '=' NUMBER		{ setmajor($1, $3); };
315 
316 
317 
318 /*
319  * The configuration grammar.
320  */
321 specs:
322 	specs spec |
323 	/* empty */;
324 
325 spec:
326 	config_spec '\n'		{ adepth = 0; } |
327 	'\n' |
328 	error '\n'			{ cleanup(); };
329 
330 config_spec:
331 	file |
332 	object |
333 	include |
334 	OPTIONS opt_list |
335 	RMOPTIONS ropt_list |
336 	MAKEOPTIONS mkopt_list |
337 	MAXUSERS NUMBER			{ setmaxusers($2); } |
338 	CONFIG conf sysparam_list	{ addconf(&conf); } |
339 	PSEUDO_DEVICE WORD npseudo	{ addpseudo($2, $3); } |
340 	device_instance AT attachment ENABLE { enabledev($1, $3); } |
341 	device_instance AT attachment disable locators flags_opt
342 					{ adddev($1, $3, $5, $6, $4); };
343 
344 mkopt_list:
345 	mkopt_list ',' mkoption |
346 	mkoption;
347 
348 mkoption:
349 	WORD '=' value			{ addmkoption($1, $3); }
350 
351 opt_list:
352 	opt_list ',' option |
353 	option;
354 
355 ropt_list:
356 	ropt_list ',' WORD { removeoption($3); } |
357 	WORD { removeoption($1); };
358 
359 option:
360 	WORD				{ addoption($1, NULL); } |
361 	WORD '=' value			{ addoption($1, $3); };
362 
363 conf:
364 	WORD				{ conf.cf_name = $1;
365 					    conf.cf_lineno = currentline();
366 					    conf.cf_root = NULL;
367 					    conf.cf_swap = NULL;
368 					    conf.cf_dump = NULL; };
369 
370 sysparam_list:
371 	sysparam_list sysparam |
372 	sysparam;
373 
374 sysparam:
375 	ROOT on_opt dev_spec	 { setconf(&conf.cf_root, "root", $3); } |
376 	SWAP on_opt swapdev_list { setconf(&conf.cf_swap, "swap", $3); } |
377 	DUMPS on_opt dev_spec	 { setconf(&conf.cf_dump, "dumps", $3); };
378 
379 swapdev_list:
380 	dev_spec AND swapdev_list	{ ($$ = $1)->nv_next = $3; } |
381 	dev_spec			{ $$ = $1; };
382 
383 dev_spec:
384 	WORD				{ $$ = new_si($1, NODEV); } |
385 	major_minor			{ $$ = new_si(NULL, $1); };
386 
387 major_minor:
388 	MAJOR NUMBER MINOR NUMBER	{ $$ = makedev($2, $4); };
389 
390 on_opt:
391 	ON | /* empty */;
392 
393 npseudo:
394 	NUMBER				{ $$ = $1; } |
395 	/* empty */			{ $$ = 1; };
396 
397 device_instance:
398 	WORD '*'			{ $$ = starref($1); } |
399 	WORD				{ $$ = $1; };
400 
401 attachment:
402 	ROOT				{ $$ = NULL; } |
403 	WORD '?'			{ $$ = wildref($1); } |
404 	WORD				{ $$ = $1; };
405 
406 locators:
407 	locators locator		{ ($$ = $2)->nv_next = $1; } |
408 	/* empty */			{ $$ = NULL; };
409 
410 locator:
411 	WORD value			{ $$ = new_ns($1, $2); } |
412 	WORD '?'			{ $$ = new_ns($1, NULL); };
413 
414 flags_opt:
415 	FLAGS NUMBER			{ $$ = $2; } |
416 	/* empty */			{ $$ = 0; };
417 
418 %%
419 
420 void
421 yyerror(const char *s)
422 {
423 
424 	error("%s", s);
425 }
426 
427 /*
428  * Cleanup procedure after syntax error: release any nvlists
429  * allocated during parsing the current line.
430  */
431 static void
cleanup(void)432 cleanup(void)
433 {
434 	struct nvlist **np;
435 	int i;
436 
437 	for (np = alloc, i = adepth; --i >= 0; np++)
438 		nvfree(*np);
439 	adepth = 0;
440 }
441 
442 static void
setmachine(const char * mch,const char * mcharch)443 setmachine(const char *mch, const char *mcharch)
444 {
445 	char buf[MAXPATHLEN];
446 
447 	machine = mch;
448 	machinearch = mcharch;
449 
450 	(void)snprintf(buf, sizeof buf, "arch/%s/conf/files.%s", machine, machine);
451 	if (include(buf, ENDFILE) != 0)
452 		exit(1);
453 
454 	if (machinearch != NULL)
455 		(void)snprintf(buf, sizeof buf, "arch/%s/conf/files.%s",
456 		    machinearch, machinearch);
457 	else
458 		strlcpy(buf, _PATH_DEVNULL, sizeof buf);
459 	if (include(buf, ENDFILE) != 0)
460 		exit(1);
461 
462 	if (include("conf/files", ENDFILE) != 0)
463 		exit(1);
464 }
465 
466 static void
check_maxpart(void)467 check_maxpart(void)
468 {
469 	if (maxpartitions <= 0) {
470 		stop("cannot proceed without maxpartitions specifier");
471 	}
472 }
473