xref: /openbsd/usr.sbin/config/gram.y (revision d89ec533)
1 %{
2 /*	$OpenBSD: gram.y,v 1.25 2021/11/28 19:26:03 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 <ctype.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <limits.h>
50 #include <string.h>
51 #include <errno.h>
52 #include "config.h"
53 #include "sem.h"
54 
55 #define	FORMAT(n) ((n) > -10 && (n) < 10 ? "%d" : "0x%x")
56 
57 #define	stop(s)	error(s), exit(1)
58 
59 int	include(const char *, int);
60 void	yyerror(const char *);
61 int	yylex(void);
62 
63 static	struct	config conf;	/* at most one active at a time */
64 
65 /* the following is used to recover nvlist space after errors */
66 static	struct	nvlist *alloc[1000];
67 static	int	adepth;
68 #define	new0(n,s,p,i,x)	(alloc[adepth++] = newnv(n, s, p, i, x))
69 #define	new_n(n)	new0(n, NULL, NULL, 0, NULL)
70 #define	new_nx(n, x)	new0(n, NULL, NULL, 0, x)
71 #define	new_ns(n, s)	new0(n, s, NULL, 0, NULL)
72 #define	new_si(s, i)	new0(NULL, s, NULL, i, NULL)
73 #define	new_nsi(n,s,i)	new0(n, s, NULL, i, NULL)
74 #define	new_np(n, p)	new0(n, NULL, p, 0, NULL)
75 #define	new_s(s)	new0(NULL, s, NULL, 0, NULL)
76 #define	new_p(p)	new0(NULL, NULL, p, 0, NULL)
77 #define	new_px(p, x)	new0(NULL, NULL, p, 0, x)
78 
79 #define	fx_atom(s)	new0(s, NULL, NULL, FX_ATOM, NULL)
80 #define	fx_not(e)	new0(NULL, NULL, NULL, FX_NOT, e)
81 #define	fx_and(e1, e2)	new0(NULL, NULL, e1, FX_AND, e2)
82 #define	fx_or(e1, e2)	new0(NULL, NULL, e1, FX_OR, e2)
83 
84 static	void	cleanup(void);
85 static	void	setmachine(const char *, const char *);
86 static	void	check_maxpart(void);
87 
88 %}
89 
90 %union {
91 	struct	attr *attr;
92 	struct	devbase *devb;
93 	struct	deva *deva;
94 	struct	nvlist *list;
95 	const char *str;
96 	int	val;
97 }
98 
99 %token	AND AT ATTACH BUILD COMPILE_WITH CONFIG DEFINE DEFOPT
100 %token	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>	pathnames
111 %type	<list>	fopts fexpr fatom
112 %type	<val>	fflgs fflag oflgs oflag
113 %type	<str>	rule
114 %type	<attr>	attr
115 %type	<devb>	devbase
116 %type	<deva>	devattach_opt
117 %type	<val>	disable
118 %type	<list>	atlist interface_opt
119 %type	<str>	atname
120 %type	<list>	loclist_opt loclist locdef
121 %type	<str>	locdefault
122 %type	<list>	attrs_opt attrs
123 %type	<list>	locators locator
124 %type	<list>	swapdev_list dev_spec
125 %type	<str>	device_instance
126 %type	<str>	attachment
127 %type	<str>	value
128 %type	<val>	major_minor signed_number npseudo
129 %type	<val>	flags_opt
130 
131 %%
132 
133 /*
134  * A configuration consists of a machine type, followed by the machine
135  * definition files (via the include() mechanism), followed by the
136  * configuration specification(s) proper.  In effect, this is two
137  * separate grammars, with some shared terminals and nonterminals.
138  * Note that we do not have sufficient keywords to enforce any order
139  * between elements of "topthings" without introducing shift/reduce
140  * conflicts.  Instead, check order requirements in the C code.
141  */
142 Configuration:
143 	topthings			/* dirspecs, include "std.arch" */
144 	machine_spec			/* "machine foo" from machine descr. */
145 	dev_defs dev_eof		/* sys/conf/files */
146 	dev_defs dev_eof		/* sys/arch/${MACHINE_ARCH}/... */
147 	dev_defs dev_eof		/* sys/arch/${MACHINE}/... */
148 					{ check_maxpart(); }
149 	specs;				/* rest of machine description */
150 
151 topthings:
152 	topthings topthing |
153 	/* empty */;
154 
155 topthing:
156 	SOURCE PATHNAME '\n'		{ if (!srcdir) srcdir = $2; } |
157 	BUILD  PATHNAME '\n'		{ if (!builddir) builddir = $2; } |
158 	include '\n' |
159 	'\n';
160 
161 machine_spec:
162 	XMACHINE WORD '\n'		{ setmachine($2,NULL); } |
163 	XMACHINE WORD WORD '\n'		{ setmachine($2,$3); } |
164 	error { stop("cannot proceed without machine specifier"); };
165 
166 dev_eof:
167 	ENDFILE				{ enddefs(); checkfiles(); };
168 
169 pathnames:
170 	PATHNAME			{ $$ = new_nsi($1, NULL, 0); } |
171 	pathnames '|' PATHNAME		{ ($$ = $1)->nv_next = new_nsi($3, NULL, 0); };
172 
173 /*
174  * Various nonterminals shared between the grammars.
175  */
176 file:
177 	XFILE pathnames fopts fflgs rule { addfile($2, $3, $4, $5); };
178 
179 object:
180 	XOBJECT PATHNAME fopts oflgs	{ addobject($2, $3, $4); };
181 
182 /* order of options is important, must use right recursion */
183 fopts:
184 	fexpr				{ $$ = $1; } |
185 	/* empty */			{ $$ = NULL; };
186 
187 fexpr:
188 	fatom				{ $$ = $1; } |
189 	'!' fatom			{ $$ = fx_not($2); } |
190 	fexpr '&' fexpr			{ $$ = fx_and($1, $3); } |
191 	fexpr '|' fexpr			{ $$ = fx_or($1, $3); } |
192 	'(' fexpr ')'			{ $$ = $2; };
193 
194 fatom:
195 	WORD				{ $$ = fx_atom($1); };
196 
197 fflgs:
198 	fflgs fflag			{ $$ = $1 | $2; } |
199 	/* empty */			{ $$ = 0; };
200 
201 fflag:
202 	NEEDS_COUNT			{ $$ = FI_NEEDSCOUNT; } |
203 	NEEDS_FLAG			{ $$ = FI_NEEDSFLAG; };
204 
205 oflgs:
206 	oflgs oflag			{ $$ = $1 | $2; } |
207 	/* empty */			{ $$ = 0; };
208 
209 oflag:
210 	NEEDS_FLAG			{ $$ = OI_NEEDSFLAG; };
211 
212 rule:
213 	COMPILE_WITH WORD		{ $$ = $2; } |
214 	/* empty */			{ $$ = NULL; };
215 
216 include:
217 	INCLUDE WORD			{ include($2, 0); };
218 
219 
220 /*
221  * The machine definitions grammar.
222  */
223 dev_defs:
224 	dev_defs dev_def |
225 	/* empty */;
226 
227 dev_def:
228 	one_def '\n'			{ adepth = 0; } |
229 	'\n' |
230 	error '\n'			{ cleanup(); };
231 
232 one_def:
233 	file |
234 	object |
235 	include |
236 	DEFINE WORD interface_opt	{ (void)defattr($2, $3); } |
237 	DEFOPT WORD			{ defoption($2); } |
238 	DEVICE devbase interface_opt attrs_opt
239 					{ defdev($2, 0, $3, $4); } |
240 	ATTACH devbase AT atlist devattach_opt attrs_opt
241 					{ defdevattach($5, $2, $4, $6); } |
242 	MAXUSERS NUMBER NUMBER NUMBER	{ setdefmaxusers($2, $3, $4); } |
243 	MAXPARTITIONS NUMBER		{ maxpartitions = $2; } |
244 	PSEUDO_DEVICE devbase attrs_opt { defdev($2,1,NULL,$3); } |
245 	MAJOR '{' majorlist '}';
246 
247 disable:
248 	DISABLE				{ $$ = 1; } |
249 	/* empty */			{ $$ = 0; };
250 
251 atlist:
252 	atlist ',' atname		{ $$ = new_nx($3, $1); } |
253 	atname				{ $$ = new_n($1); };
254 
255 atname:
256 	WORD				{ $$ = $1; } |
257 	ROOT				{ $$ = NULL; };
258 
259 devbase:
260 	WORD				{ $$ = getdevbase((char *)$1); };
261 
262 devattach_opt:
263 	WITH WORD			{ $$ = getdevattach($2); } |
264 	/* empty */			{ $$ = NULL; };
265 
266 interface_opt:
267 	'{' loclist_opt '}'		{ $$ = new_nx("", $2); } |
268 	/* empty */			{ $$ = NULL; };
269 
270 loclist_opt:
271 	loclist				{ $$ = $1; } |
272 	/* empty */			{ $$ = NULL; };
273 
274 /* loclist order matters, must use right recursion */
275 loclist:
276 	locdef ',' loclist		{ ($$ = $1)->nv_next = $3; } |
277 	locdef				{ $$ = $1; };
278 
279 /* "[ WORD locdefault ]" syntax may be unnecessary... */
280 locdef:
281 	WORD locdefault			{ $$ = new_nsi($1, $2, 0); } |
282 	WORD				{ $$ = new_nsi($1, NULL, 0); } |
283 	'[' WORD locdefault ']'		{ $$ = new_nsi($2, $3, 1); };
284 
285 locdefault:
286 	'=' value			{ $$ = $2; };
287 
288 value:
289 	WORD				{ $$ = $1; } |
290 	EMPTY				{ $$ = $1; } |
291 	signed_number			{
292 						char bf[40];
293 
294 						(void)snprintf(bf, sizeof bf,
295 						    FORMAT($1), $1);
296 						$$ = intern(bf);
297 					};
298 
299 signed_number:
300 	NUMBER				{ $$ = $1; } |
301 	'-' NUMBER			{ $$ = -$2; };
302 
303 attrs_opt:
304 	':' attrs			{ $$ = $2; } |
305 	/* empty */			{ $$ = NULL; };
306 
307 attrs:
308 	attrs ',' attr			{ $$ = new_px($3, $1); } |
309 	attr				{ $$ = new_p($1); };
310 
311 attr:
312 	WORD				{ $$ = getattr($1); };
313 
314 majorlist:
315 	majorlist ',' majordef |
316 	majordef;
317 
318 majordef:
319 	devbase '=' NUMBER		{ setmajor($1, $3); };
320 
321 
322 
323 /*
324  * The configuration grammar.
325  */
326 specs:
327 	specs spec |
328 	/* empty */;
329 
330 spec:
331 	config_spec '\n'		{ adepth = 0; } |
332 	'\n' |
333 	error '\n'			{ cleanup(); };
334 
335 config_spec:
336 	file |
337 	object |
338 	include |
339 	OPTIONS opt_list |
340 	RMOPTIONS ropt_list |
341 	MAKEOPTIONS mkopt_list |
342 	MAXUSERS NUMBER			{ setmaxusers($2); } |
343 	CONFIG conf sysparam_list	{ addconf(&conf); } |
344 	PSEUDO_DEVICE WORD npseudo disable { addpseudo($2, $3, $4); } |
345 	device_instance AT attachment ENABLE { enabledev($1, $3); } |
346 	device_instance AT attachment disable locators flags_opt
347 					{ adddev($1, $3, $5, $6, $4); };
348 
349 mkopt_list:
350 	mkopt_list ',' mkoption |
351 	mkoption;
352 
353 mkoption:
354 	WORD '=' value			{ addmkoption($1, $3); }
355 
356 opt_list:
357 	opt_list ',' option |
358 	option;
359 
360 ropt_list:
361 	ropt_list ',' WORD { removeoption($3); } |
362 	WORD { removeoption($1); };
363 
364 option:
365 	WORD				{ addoption($1, NULL); } |
366 	WORD '=' value			{ addoption($1, $3); };
367 
368 conf:
369 	WORD				{ conf.cf_name = $1;
370 					    conf.cf_lineno = currentline();
371 					    conf.cf_root = NULL;
372 					    conf.cf_swap = NULL;
373 					    conf.cf_dump = NULL; };
374 
375 sysparam_list:
376 	sysparam_list sysparam |
377 	sysparam;
378 
379 sysparam:
380 	ROOT on_opt dev_spec	 { setconf(&conf.cf_root, "root", $3); } |
381 	SWAP on_opt swapdev_list { setconf(&conf.cf_swap, "swap", $3); } |
382 	DUMPS on_opt dev_spec	 { setconf(&conf.cf_dump, "dumps", $3); };
383 
384 swapdev_list:
385 	dev_spec AND swapdev_list	{ ($$ = $1)->nv_next = $3; } |
386 	dev_spec			{ $$ = $1; };
387 
388 dev_spec:
389 	WORD				{ $$ = new_si($1, nodev); } |
390 	major_minor			{ $$ = new_si(NULL, $1); };
391 
392 major_minor:
393 	MAJOR NUMBER MINOR NUMBER	{ $$ = makedev($2, $4); };
394 
395 on_opt:
396 	ON | /* empty */;
397 
398 npseudo:
399 	NUMBER				{ $$ = $1; } |
400 	/* empty */			{ $$ = 1; };
401 
402 device_instance:
403 	WORD '*'			{ $$ = starref($1); } |
404 	WORD				{ $$ = $1; };
405 
406 attachment:
407 	ROOT				{ $$ = NULL; } |
408 	WORD '?'			{ $$ = wildref($1); } |
409 	WORD				{ $$ = $1; };
410 
411 locators:
412 	locators locator		{ ($$ = $2)->nv_next = $1; } |
413 	/* empty */			{ $$ = NULL; };
414 
415 locator:
416 	WORD value			{ $$ = new_ns($1, $2); } |
417 	WORD '?'			{ $$ = new_ns($1, NULL); };
418 
419 flags_opt:
420 	FLAGS NUMBER			{ $$ = $2; } |
421 	/* empty */			{ $$ = 0; };
422 
423 %%
424 
425 void
426 yyerror(const char *s)
427 {
428 
429 	error("%s", s);
430 }
431 
432 /*
433  * Cleanup procedure after syntax error: release any nvlists
434  * allocated during parsing the current line.
435  */
436 static void
437 cleanup(void)
438 {
439 	struct nvlist **np;
440 	int i;
441 
442 	for (np = alloc, i = adepth; --i >= 0; np++)
443 		nvfree(*np);
444 	adepth = 0;
445 }
446 
447 static void
448 setmachine(const char *mch, const char *mcharch)
449 {
450 	char buf[PATH_MAX];
451 
452 	machine = mch;
453 	machinearch = mcharch;
454 
455 	(void)snprintf(buf, sizeof buf, "arch/%s/conf/files.%s", machine, machine);
456 	if (include(buf, ENDFILE) != 0)
457 		exit(1);
458 
459 	if (machinearch != NULL)
460 		(void)snprintf(buf, sizeof buf, "arch/%s/conf/files.%s",
461 		    machinearch, machinearch);
462 	else
463 		strlcpy(buf, _PATH_DEVNULL, sizeof buf);
464 	if (include(buf, ENDFILE) != 0)
465 		exit(1);
466 
467 	if (include("conf/files", ENDFILE) != 0)
468 		exit(1);
469 }
470 
471 static void
472 check_maxpart(void)
473 {
474 	if (maxpartitions <= 0) {
475 		stop("cannot proceed without maxpartitions specifier");
476 	}
477 }
478