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
cleanup(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
setmachine(const char * mch,const char * mcharch)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
check_maxpart(void)472 check_maxpart(void)
473 {
474 if (maxpartitions <= 0) {
475 stop("cannot proceed without maxpartitions specifier");
476 }
477 }
478