gram.y revision 1.31 1 %{
2 /* $NetBSD: gram.y,v 1.31 2012/03/11 07:27:02 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
62 /*
63 * Allocation wrapper functions
64 */
65 static void wrap_alloc(void *ptr, unsigned code);
66 static void wrap_continue(void);
67 static void wrap_cleanup(void);
68
69 /*
70 * Allocation wrapper type codes
71 */
72 #define WRAP_CODE_nvlist 1
73
74 /*
75 * The allocation wrappers themselves
76 */
77 #define DECL_ALLOCWRAP(t) static struct t *wrap_mk_##t(struct t *arg)
78
79 DECL_ALLOCWRAP(nvlist);
80
81 /*
82 * Macros for allocating new objects
83 */
84
85 #define new0(n,s,p,i,x) wrap_mk_nvlist(newnv(n, s, p, i, x))
86 #define new_n(n) new0(n, NULL, NULL, 0, NULL)
87 #define new_nx(n, x) new0(n, NULL, NULL, 0, x)
88 #define new_ns(n, s) new0(n, s, NULL, 0, NULL)
89 #define new_si(s, i) new0(NULL, s, NULL, i, NULL)
90 #define new_nsi(n,s,i) new0(n, s, NULL, i, NULL)
91 #define new_np(n, p) new0(n, NULL, p, 0, NULL)
92 #define new_s(s) new0(NULL, s, NULL, 0, NULL)
93 #define new_p(p) new0(NULL, NULL, p, 0, NULL)
94 #define new_px(p, x) new0(NULL, NULL, p, 0, x)
95 #define new_sx(s, x) new0(NULL, s, NULL, 0, x)
96 #define new_nsx(n,s,x) new0(n, s, NULL, 0, x)
97 #define new_i(i) new0(NULL, NULL, NULL, i, NULL)
98
99 #define fx_atom(s) new0(s, NULL, NULL, FX_ATOM, NULL)
100 #define fx_not(e) new0(NULL, NULL, NULL, FX_NOT, e)
101 #define fx_and(e1, e2) new0(NULL, NULL, e1, FX_AND, e2)
102 #define fx_or(e1, e2) new0(NULL, NULL, e1, FX_OR, e2)
103
104 /*
105 * Other private functions
106 */
107
108 static void setmachine(const char *, const char *, struct nvlist *, int);
109 static void check_maxpart(void);
110
111 static void app(struct nvlist *, struct nvlist *);
112
113 static struct nvlist *mk_nsis(const char *, int, struct nvlist *, int);
114 static struct nvlist *mk_ns(const char *, struct nvlist *);
115
116 %}
117
118 %union {
119 struct attr *attr;
120 struct devbase *devb;
121 struct deva *deva;
122 struct nvlist *list;
123 const char *str;
124 struct numconst num;
125 int64_t val;
126 }
127
128 %token AND AT ATTACH
129 %token BLOCK BUILD
130 %token CHAR COLONEQ COMPILE_WITH CONFIG
131 %token DEFFS DEFINE DEFOPT DEFPARAM DEFFLAG DEFPSEUDO DEFPSEUDODEV
132 %token DEVICE DEVCLASS DUMPS DEVICE_MAJOR
133 %token ENDFILE
134 %token XFILE FILE_SYSTEM FLAGS
135 %token IDENT IOCONF
136 %token LINKZERO
137 %token XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR
138 %token NEEDS_COUNT NEEDS_FLAG NO
139 %token XOBJECT OBSOLETE ON OPTIONS
140 %token PACKAGE PLUSEQ PREFIX PSEUDO_DEVICE PSEUDO_ROOT
141 %token ROOT
142 %token SINGLE SOURCE
143 %token TYPE
144 %token VECTOR VERSION
145 %token WITH
146 %token <num> NUMBER
147 %token <str> PATHNAME QSTRING WORD EMPTYSTRING
148 %token ENDDEFS
149
150 %type <list> fopts fexpr fatom
151 %type <list> f_or_expr f_and_expr f_prefix_expr f_base_expr
152 %type <str> fs_spec
153 %type <val> fflgs fflag oflgs oflag
154 %type <str> rule
155 %type <attr> attr
156 %type <devb> devbase
157 %type <deva> devattach_opt
158 %type <list> atlist interface_opt
159 %type <str> atname
160 %type <list> loclist locdef
161 %type <str> locdefault
162 %type <list> values locdefaults
163 %type <list> attrs_opt attrs
164 %type <list> locators locator
165 %type <list> dev_spec
166 %type <str> device_instance
167 %type <str> attachment
168 %type <str> value
169 %type <val> major_minor npseudo
170 %type <num> signed_number
171 %type <val> device_flags
172 %type <str> deffs
173 %type <list> deffses
174 %type <list> defopt
175 %type <list> defopts
176 %type <str> optdep
177 %type <list> optdeps
178 %type <list> defoptdeps
179 %type <str> optfile_opt
180 %type <list> subarches
181 %type <str> filename stringvalue locname mkvarname
182 %type <val> device_major_block device_major_char
183 %type <list> devnodes devnodetype devnodeflags devnode_dims
184
185 %%
186
187 /*
188 * A complete configuration consists of both the configuration part (a
189 * kernel config such as GENERIC or SKYNET, plus also the various
190 * std.* files), which selects the material to be in the kernel, and
191 * also the definition part (files, files.*, etc.) that declares what
192 * material is available to be placed in kernels.
193 *
194 * The two parts have almost entirely separate syntaxes. This grammar
195 * covers both of them. When config is run on a kernel configuration
196 * file, the std.* file for the port is included explicitly. The
197 * files.* files are included implicitly when the std.* file declares
198 * the machine type.
199 *
200 * The machine spec, which brings in the definition part, must appear
201 * before all configuration material except for the "topthings"; these
202 * are the "source" and "build" declarations that tell config where
203 * things are. These are not used by default.
204 *
205 * A previous version of this comment contained the following text:
206 *
207 * Note that we do not have sufficient keywords to enforce any
208 * order between elements of "topthings" without introducing
209 * shift/reduce conflicts. Instead, check order requirements in
210 * the C code.
211 *
212 * As of March 2012 this comment makes no sense, as there are only two
213 * topthings and no reason for them to be forcibly ordered.
214 * Furthermore, the statement about conflicts is false.
215 */
216
217 /* Complete configuration. */
218 configuration:
219 topthings machine_spec definition_part configuration_part
220 ;
221
222 /* Sequence of zero or more topthings. */
223 topthings:
224 /* empty */
225 | topthings topthing
226 ;
227
228 /* Directory specification. */
229 topthing:
230 '\n'
231 | SOURCE filename '\n' { if (!srcdir) srcdir = $2; }
232 | BUILD filename '\n' { if (!builddir) builddir = $2; }
233 ;
234
235 /* "machine foo" from std.whatever */
236 machine_spec:
237 XMACHINE WORD '\n' { setmachine($2,NULL,NULL,0); }
238 | XMACHINE WORD WORD '\n' { setmachine($2,$3,NULL,0); }
239 | XMACHINE WORD WORD subarches '\n' { setmachine($2,$3,$4,0); }
240 | IOCONF WORD '\n' { setmachine($2,NULL,NULL,1); }
241 | error { stop("cannot proceed without machine or ioconf specifier"); }
242 ;
243
244 /* One or more sub-arches. */
245 subarches:
246 WORD { $$ = new_n($1); }
247 | subarches WORD { $$ = new_nx($2, $1); }
248 ;
249
250 /************************************************************/
251
252 /*
253 * The machine definitions grammar.
254 */
255
256 /* Complete definition part: the contents of all files.* files. */
257 definition_part:
258 definitions ENDDEFS { check_maxpart(); check_version(); }
259 ;
260
261 /* Zero or more definitions. Trap errors. */
262 definitions:
263 /* empty */
264 | definitions '\n'
265 | definitions definition '\n' { wrap_continue(); }
266 | definitions error '\n' { wrap_cleanup(); }
267 | definitions ENDFILE { enddefs(); checkfiles(); }
268 ;
269
270 /* A single definition. */
271 definition:
272 file
273 | object
274 | device_major { do_devsw = 1; }
275 | prefix
276 | DEVCLASS WORD { (void)defattr($2, NULL, NULL, 1); }
277 | DEFFS deffses defoptdeps { deffilesystem($2, $3); }
278 | DEFINE WORD interface_opt attrs_opt
279 { (void)defattr($2, $3, $4, 0); }
280 | DEFOPT optfile_opt defopts defoptdeps
281 { defoption($2, $3, $4); }
282 | DEFFLAG optfile_opt defopts defoptdeps
283 { defflag($2, $3, $4, 0); }
284 | OBSOLETE DEFFLAG optfile_opt defopts
285 { defflag($3, $4, NULL, 1); }
286 | DEFPARAM optfile_opt defopts defoptdeps
287 { defparam($2, $3, $4, 0); }
288 | OBSOLETE DEFPARAM optfile_opt defopts
289 { defparam($3, $4, NULL, 1); }
290 | DEVICE devbase interface_opt attrs_opt
291 { defdev($2, $3, $4, 0); }
292 | ATTACH devbase AT atlist devattach_opt attrs_opt
293 { defdevattach($5, $2, $4, $6); }
294 | MAXPARTITIONS NUMBER { maxpartitions = $2.val; }
295 | MAXUSERS NUMBER NUMBER NUMBER
296 { setdefmaxusers($2.val, $3.val, $4.val); }
297 | MAKEOPTIONS condmkopt_list
298 /* interface_opt in DEFPSEUDO is for backwards compatibility */
299 | DEFPSEUDO devbase interface_opt attrs_opt
300 { defdev($2, $3, $4, 1); }
301 | DEFPSEUDODEV devbase interface_opt attrs_opt
302 { defdev($2, $3, $4, 2); }
303 | MAJOR '{' majorlist '}'
304 | VERSION NUMBER { setversion($2.val); }
305 ;
306
307 /* source file: file foo/bar.c bar|baz needs-flag compile-with blah */
308 file:
309 XFILE filename fopts fflgs rule { addfile($2, $3, $4, $5); }
310 ;
311
312 /* file options: optional expression of config elements */
313 fopts:
314 /* empty */ { $$ = NULL; }
315 | fexpr { $$ = $1; }
316 ;
317
318 /* zero or more flags for a file */
319 fflgs:
320 /* empty */ { $$ = 0; }
321 | fflgs fflag { $$ = $1 | $2; }
322 ;
323
324 /* one flag for a file */
325 fflag:
326 NEEDS_COUNT { $$ = FI_NEEDSCOUNT; }
327 | NEEDS_FLAG { $$ = FI_NEEDSFLAG; }
328 ;
329
330 /* extra compile directive for a source file */
331 rule:
332 /* empty */ { $$ = NULL; }
333 | COMPILE_WITH stringvalue { $$ = $2; }
334 ;
335
336 /* object file: object zot.o foo|zot needs-flag */
337 object:
338 XOBJECT filename fopts oflgs { addobject($2, $3, $4); }
339 ;
340
341 /* zero or more flags for an object file */
342 oflgs:
343 /* empty */ { $$ = 0; }
344 | oflgs oflag { $$ = $1 | $2; }
345 ;
346
347 /* a single flag for an object file */
348 oflag:
349 NEEDS_FLAG { $$ = OI_NEEDSFLAG; }
350 ;
351
352 /* device major declaration */
353 device_major:
354 DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes
355 { adddevm($2, $3, $4, $5, $6); }
356 ;
357
358 /* char 55 */
359 device_major_char:
360 /* empty */ { $$ = -1; }
361 | CHAR NUMBER { $$ = $2.val; }
362 ;
363
364 /* block 33 */
365 device_major_block:
366 /* empty */ { $$ = -1; }
367 | BLOCK NUMBER { $$ = $2.val; }
368 ;
369
370 /* device node specification */
371 devnodes:
372 /* empty */ { $$ = new_s("DEVNODE_DONTBOTHER"); }
373 | devnodetype ',' devnodeflags { $$ = nvcat($1, $3); }
374 | devnodetype { $$ = $1; }
375 ;
376
377 /* device nodes without flags */
378 devnodetype:
379 SINGLE { $$ = new_s("DEVNODE_SINGLE"); }
380 | VECTOR '=' devnode_dims { $$ = nvcat(new_s("DEVNODE_VECTOR"), $3); }
381 ;
382
383 /* dimensions (?) */
384 devnode_dims:
385 NUMBER { $$ = new_i($1.val); }
386 | NUMBER ':' NUMBER {
387 struct nvlist *__nv1, *__nv2;
388
389 __nv1 = new_i($1.val);
390 __nv2 = new_i($3.val);
391 $$ = nvcat(__nv1, __nv2);
392 }
393 ;
394
395 /* flags for device nodes */
396 devnodeflags:
397 LINKZERO { $$ = new_s("DEVNODE_FLAG_LINKZERO");}
398 ;
399
400 /* prefix delimiter */
401 prefix:
402 PREFIX filename { prefix_push($2); }
403 | PREFIX { prefix_pop(); }
404 ;
405
406 /* one or more file system names */
407 deffses:
408 deffs { $$ = new_n($1); }
409 | deffses deffs { $$ = new_nx($2, $1); }
410 ;
411
412 /* a single file system name */
413 deffs:
414 WORD { $$ = $1; }
415 ;
416
417 /* optional locator specification */
418 interface_opt:
419 /* empty */ { $$ = NULL; }
420 | '{' '}' { $$ = new_nx("", NULL); }
421 | '{' loclist '}' { $$ = new_nx("", $2); }
422 ;
423
424 /*
425 * loclist order matters, must use right recursion
426 * XXX wot?
427 */
428
429 /* list of locator definitions */
430 loclist:
431 locdef { $$ = $1; }
432 | locdef ',' loclist { $$ = $1; app($1, $3); }
433 ;
434
435 /*
436 * "[ WORD locdefault ]" syntax may be unnecessary...
437 */
438
439 /* one locator definition */
440 locdef:
441 locname locdefault { $$ = new_nsi($1, $2, 0); }
442 | locname { $$ = new_nsi($1, NULL, 0); }
443 | '[' locname locdefault ']' { $$ = new_nsi($2, $3, 1); }
444 | locname '[' NUMBER ']' { $$ = mk_nsis($1, $3.val, NULL, 0); }
445 | locname '[' NUMBER ']' locdefaults
446 { $$ = mk_nsis($1, $3.val, $5, 0); }
447 | '[' locname '[' NUMBER ']' locdefaults ']'
448 { $$ = mk_nsis($2, $4.val, $6, 1); }
449 ;
450
451 /* locator name */
452 locname:
453 WORD { $$ = $1; }
454 | QSTRING { $$ = $1; }
455 ;
456
457 /* locator default value */
458 locdefault:
459 '=' value { $$ = $2; }
460 ;
461
462 /* multiple locator default values */
463 locdefaults:
464 '=' '{' values '}' { $$ = $3; }
465 ;
466
467 /* optional attributes */
468 attrs_opt:
469 /* empty */ { $$ = NULL; }
470 | ':' attrs { $$ = $2; }
471 ;
472
473 /* one or more attributes */
474 attrs:
475 attr { $$ = new_p($1); }
476 | attrs ',' attr { $$ = new_px($3, $1); }
477 ;
478
479 /* one attribute */
480 attr:
481 WORD { $$ = getattr($1); }
482 ;
483
484 /* list of places to attach: attach blah at ... */
485 atlist:
486 atname { $$ = new_n($1); }
487 | atlist ',' atname { $$ = new_nx($3, $1); }
488 ;
489
490 /* a place to attach a device */
491 atname:
492 WORD { $$ = $1; }
493 | ROOT { $$ = NULL; }
494 ;
495
496 /* one or more defined options */
497 defopts:
498 defopt { $$ = $1; }
499 | defopts defopt { $$ = nvcat($2, $1); }
500 ;
501
502 /* one defined option */
503 defopt:
504 WORD { $$ = new_n($1); }
505 | WORD '=' value { $$ = new_ns($1, $3); }
506 | WORD COLONEQ value {
507 struct nvlist *__nv = new_n($1);
508
509 $$ = new_nsx("", $3, __nv);
510 }
511 | WORD '=' value COLONEQ value {
512 struct nvlist *__nv = new_n($1);
513
514 $$ = new_nsx("", $5, __nv);
515 }
516 ;
517
518 /* option dependencies (read as "defopt deps") which are optional */
519 defoptdeps:
520 /* empty */ { $$ = NULL; }
521 | ':' optdeps { $$ = $2; }
522 ;
523
524 /* a list of option dependencies */
525 optdeps:
526 optdep { $$ = new_n($1); }
527 | optdeps ',' optdep { $$ = new_nx($3, $1); }
528 ;
529
530 /* one option dependence */
531 optdep:
532 WORD { $$ = $1; }
533 ;
534
535 /* list of conditional makeoptions */
536 condmkopt_list:
537 condmkoption
538 | condmkopt_list ',' condmkoption
539 ;
540
541 /* one conditional make option */
542 condmkoption:
543 fexpr mkvarname PLUSEQ value { appendcondmkoption($1, $2, $4); }
544 ;
545
546 /* device name */
547 devbase:
548 WORD { $$ = getdevbase($1); }
549 ;
550
551 /* optional attachment: with foo */
552 devattach_opt:
553 /* empty */ { $$ = NULL; }
554 | WITH WORD { $$ = getdevattach($2); }
555 ;
556
557 /* list of major numbers */
558 /* XXX why is this right-recursive? */
559 majorlist:
560 majordef
561 | majorlist ',' majordef
562 ;
563
564 /* one major number */
565 majordef:
566 devbase '=' NUMBER { setmajor($1, $3.val); }
567 ;
568
569 /************************************************************/
570
571 /*
572 * The configuration grammar.
573 */
574
575 /* Complete configuration part: all std.* files plus selected config. */
576 configuration_part:
577 config_items
578 ;
579
580 /* Zero or more config items. Trap errors. */
581 config_items:
582 /* empty */
583 | config_items '\n'
584 | config_items config_item '\n' { wrap_continue(); }
585 | config_items error '\n' { wrap_cleanup(); }
586 ;
587
588 /* One config item. */
589 config_item:
590 definition
591 | NO FILE_SYSTEM no_fs_list
592 | FILE_SYSTEM fs_list
593 | NO MAKEOPTIONS no_mkopt_list
594 | MAKEOPTIONS mkopt_list
595 | NO OPTIONS no_opt_list
596 | OPTIONS opt_list
597 | MAXUSERS NUMBER { setmaxusers($2.val); }
598 | IDENT stringvalue { setident($2); }
599 | CONFIG conf root_spec sysparam_list
600 { addconf(&conf); }
601 | NO CONFIG WORD { delconf($3); }
602 | NO PSEUDO_DEVICE WORD { delpseudo($3); }
603 | PSEUDO_DEVICE WORD npseudo { addpseudo($2, $3); }
604 | PSEUDO_ROOT device_instance { addpseudoroot($2); }
605 | NO device_instance AT attachment
606 { deldevi($2, $4); }
607 | NO DEVICE AT attachment { deldeva($4); }
608 | NO device_instance { deldev($2); }
609 | device_instance AT attachment locators device_flags
610 { adddev($1, $3, $4, $5); }
611 ;
612
613 /* list of filesystems */
614 fs_list:
615 fsoption
616 | fs_list ',' fsoption
617 ;
618
619 /* one filesystem */
620 fsoption:
621 WORD { addfsoption($1); }
622 ;
623
624 /* list of filesystems that had NO in front */
625 no_fs_list:
626 no_fsoption
627 | no_fs_list ',' no_fsoption
628 ;
629
630 /* one filesystem that had NO in front */
631 no_fsoption:
632 WORD { delfsoption($1); }
633 ;
634
635 /* list of make options */
636 /* XXX why is this right-recursive? */
637 mkopt_list:
638 mkoption
639 | mkopt_list ',' mkoption
640 ;
641
642 /* one make option */
643 mkoption:
644 mkvarname '=' value { addmkoption($1, $3); }
645 | mkvarname PLUSEQ value { appendmkoption($1, $3); }
646 ;
647
648 /* list of make options that had NO in front */
649 no_mkopt_list:
650 no_mkoption
651 | no_mkopt_list ',' no_mkoption
652 ;
653
654 /* one make option that had NO in front */
655 /* XXX shouldn't this be mkvarname rather than WORD? */
656 no_mkoption:
657 WORD { delmkoption($1); }
658 ;
659
660 /* list of options */
661 opt_list:
662 option
663 | opt_list ',' option
664 ;
665
666 /* one option */
667 option:
668 WORD { addoption($1, NULL); }
669 | WORD '=' value { addoption($1, $3); }
670 ;
671
672 /* list of options that had NO in front */
673 no_opt_list:
674 no_option
675 | no_opt_list ',' no_option
676 ;
677
678 /* one option that had NO in front */
679 no_option:
680 WORD { deloption($1); }
681 ;
682
683 /* the name in "config name root on ..." */
684 conf:
685 WORD {
686 conf.cf_name = $1;
687 conf.cf_lineno = currentline();
688 conf.cf_fstype = NULL;
689 conf.cf_root = NULL;
690 conf.cf_dump = NULL;
691 }
692 ;
693
694 /* root fs specification */
695 root_spec:
696 ROOT on_opt dev_spec { setconf(&conf.cf_root, "root", $3); }
697 | ROOT on_opt dev_spec fs_spec { setconf(&conf.cf_root, "root", $3); }
698 ;
699
700 /* device for root fs or dump */
701 dev_spec:
702 '?' { $$ = new_si(intern("?"), NODEV); }
703 | WORD { $$ = new_si($1, NODEV); }
704 | major_minor { $$ = new_si(NULL, $1); }
705 ;
706
707 /* major and minor device number */
708 major_minor:
709 MAJOR NUMBER MINOR NUMBER { $$ = makedev($2.val, $4.val); }
710 ;
711
712 /* filesystem type for root fs specification */
713 fs_spec:
714 TYPE '?' { setfstype(&conf.cf_fstype, intern("?")); }
715 | TYPE WORD { setfstype(&conf.cf_fstype, $2); }
716 ;
717
718 /* zero or more additional system parameters */
719 sysparam_list:
720 /* empty */
721 | sysparam_list sysparam
722 ;
723
724 /* one additional system parameter (there's only one: dumps) */
725 sysparam:
726 DUMPS on_opt dev_spec { setconf(&conf.cf_dump, "dumps", $3); }
727 ;
728
729 /* number of pseudo devices to configure (which is optional) */
730 npseudo:
731 /* empty */ { $$ = 1; }
732 | NUMBER { $$ = $1.val; }
733 ;
734
735 /* name of a device to configure */
736 device_instance:
737 WORD { $$ = $1; }
738 | WORD '*' { $$ = starref($1); }
739 ;
740
741 /* name of a device to configure an attachment to */
742 attachment:
743 ROOT { $$ = NULL; }
744 | WORD { $$ = $1; }
745 | WORD '?' { $$ = wildref($1); }
746 ;
747
748 /* zero or more locators */
749 locators:
750 /* empty */ { $$ = NULL; }
751 | locators locator { $$ = $2; app($2, $1); }
752 ;
753
754 /* one locator */
755 locator:
756 WORD '?' { $$ = new_ns($1, NULL); }
757 | WORD values { $$ = mk_ns($1, $2); }
758 ;
759
760 /* optional device flags */
761 device_flags:
762 /* empty */ { $$ = 0; }
763 | FLAGS NUMBER { $$ = $2.val; }
764 ;
765
766 /************************************************************/
767
768 /*
769 * dependency logic
770 */
771
772
773 /*
774 * order of options is important, must use right recursion
775 *
776 * dholland 20120310: wut?
777 */
778
779 /* expression of config elements */
780 fexpr:
781 f_or_expr
782 ;
783
784 f_or_expr:
785 f_and_expr
786 | f_or_expr '|' f_and_expr { $$ = fx_or($1, $3); }
787 ;
788
789 f_and_expr:
790 f_prefix_expr
791 | f_and_expr '&' f_prefix_expr { $$ = fx_and($1, $3); }
792 ;
793
794 f_prefix_expr:
795 f_base_expr
796 /* XXX notyet - need to strengthen downstream first */
797 /* | '!' f_prefix_expr { $$ = fx_not($2); } */
798 ;
799
800 f_base_expr:
801 fatom { $$ = $1; }
802 | '!' fatom { $$ = fx_not($2); }
803 | '(' fexpr ')' { $$ = $2; }
804 ;
805
806 /* basic element of config element expression: a config element */
807 fatom:
808 WORD { $$ = fx_atom($1); }
809 ;
810
811 /************************************************************/
812
813 /*
814 * Various nonterminals shared between the grammars.
815 */
816
817 /* variable name for make option */
818 mkvarname:
819 QSTRING { $$ = $1; }
820 | WORD { $$ = $1; }
821 ;
822
823 /* optional file for an option */
824 optfile_opt:
825 /* empty */ { $$ = NULL; }
826 | filename { $$ = $1; }
827 ;
828
829 /* filename. */
830 filename:
831 QSTRING { $$ = $1; }
832 | PATHNAME { $$ = $1; }
833 ;
834
835 /* constant value */
836 value:
837 QSTRING { $$ = $1; }
838 | WORD { $$ = $1; }
839 | EMPTYSTRING { $$ = $1; }
840 | signed_number {
841 char bf[40];
842
843 (void)snprintf(bf, sizeof(bf), FORMAT($1), (long long)$1.val);
844 $$ = intern(bf);
845 }
846 ;
847
848 /* constant value that is a string */
849 stringvalue:
850 QSTRING { $$ = $1; }
851 | WORD { $$ = $1; }
852 ;
853
854 /* comma-separated list of values */
855 /* XXX why right-recursive? */
856 values:
857 value { $$ = new_s($1); }
858 | value ',' values { $$ = new_sx($1, $3); }
859 ;
860
861 /* possibly negative number */
862 signed_number:
863 NUMBER { $$ = $1; }
864 | '-' NUMBER { $$.fmt = $2.fmt; $$.val = -$2.val; }
865 ;
866
867 /* optional ON keyword */
868 on_opt:
869 /* empty */
870 | ON
871 ;
872
873 %%
874
875 void
876 yyerror(const char *s)
877 {
878
879 cfgerror("%s", s);
880 }
881
882 /************************************************************/
883
884 /*
885 * Wrap allocations that live on the parser stack so that we can free
886 * them again on error instead of leaking.
887 */
888
889 #define MAX_WRAP 1000
890
891 struct wrap_entry {
892 void *ptr;
893 unsigned typecode;
894 };
895
896 static struct wrap_entry wrapstack[MAX_WRAP];
897 static unsigned wrap_depth;
898
899 /*
900 * Remember pointer PTR with type-code CODE.
901 */
902 static void
903 wrap_alloc(void *ptr, unsigned code)
904 {
905 unsigned pos;
906
907 if (wrap_depth >= MAX_WRAP) {
908 panic("allocation wrapper stack overflow");
909 }
910 pos = wrap_depth++;
911 wrapstack[pos].ptr = ptr;
912 wrapstack[pos].typecode = code;
913 }
914
915 /*
916 * We succeeded; commit to keeping everything that's been allocated so
917 * far and clear the stack.
918 */
919 static void
920 wrap_continue(void)
921 {
922 wrap_depth = 0;
923 }
924
925 /*
926 * We failed; destroy all the objects allocated.
927 */
928 static void
929 wrap_cleanup(void)
930 {
931 unsigned i;
932
933 for (i=0; i<wrap_depth; i++) {
934 switch (wrapstack[i].typecode) {
935 case WRAP_CODE_nvlist:
936 nvfree(wrapstack[i].ptr);
937 break;
938 default:
939 panic("invalid code %u on allocation wrapper stack",
940 wrapstack[i].typecode);
941 }
942 }
943 wrap_depth = 0;
944 }
945
946 /*
947 * Instantiate the wrapper functions.
948 *
949 * Each one calls wrap_alloc to save the pointer and then returns the
950 * pointer again; these need to be generated with the preprocessor in
951 * order to be typesafe.
952 */
953 #define DEF_ALLOCWRAP(t) \
954 static struct t * \
955 wrap_mk_##t(struct t *arg) \
956 { \
957 wrap_alloc(arg, WRAP_CODE_##t); \
958 return arg; \
959 }
960
961 DEF_ALLOCWRAP(nvlist);
962
963 /************************************************************/
964
965 static void
966 setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches,
967 int isioconf)
968 {
969 char buf[MAXPATHLEN];
970 struct nvlist *nv;
971
972 if (isioconf) {
973 fprintf(stderr, "WARNING: ioconf is an experimental feature\n");
974 if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
975 exit(1);
976 ioconfname = mch;
977 return;
978 }
979
980 machine = mch;
981 machinearch = mcharch;
982 machinesubarches = mchsubarches;
983
984 /*
985 * Define attributes for all the given names
986 */
987 if (defattr(machine, NULL, NULL, 0) != 0 ||
988 (machinearch != NULL &&
989 defattr(machinearch, NULL, NULL, 0) != 0))
990 exit(1);
991 for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
992 if (defattr(nv->nv_name, NULL, NULL, 0) != 0)
993 exit(1);
994 }
995
996 /*
997 * Set up the file inclusion stack. This empty include tells
998 * the parser there are no more device definitions coming.
999 */
1000 if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
1001 exit(1);
1002
1003 /* Include arch/${MACHINE}/conf/files.${MACHINE} */
1004 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
1005 machine, machine);
1006 if (include(buf, ENDFILE, 0, 0) != 0)
1007 exit(1);
1008
1009 /* Include any arch/${MACHINE_SUBARCH}/conf/files.${MACHINE_SUBARCH} */
1010 for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
1011 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
1012 nv->nv_name, nv->nv_name);
1013 if (include(buf, ENDFILE, 0, 0) != 0)
1014 exit(1);
1015 }
1016
1017 /* Include any arch/${MACHINE_ARCH}/conf/files.${MACHINE_ARCH} */
1018 if (machinearch != NULL)
1019 (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
1020 machinearch, machinearch);
1021 else
1022 strlcpy(buf, _PATH_DEVNULL, sizeof(buf));
1023 if (include(buf, ENDFILE, 0, 0) != 0)
1024 exit(1);
1025
1026 /*
1027 * Include the global conf/files. As the last thing
1028 * pushed on the stack, it will be processed first.
1029 */
1030 if (include("conf/files", ENDFILE, 0, 0) != 0)
1031 exit(1);
1032
1033 oktopackage = 1;
1034 }
1035
1036 static void
1037 check_maxpart(void)
1038 {
1039
1040 if (maxpartitions <= 0 && ioconfname == NULL) {
1041 stop("cannot proceed without maxpartitions specifier");
1042 }
1043 }
1044
1045 static void
1046 check_version(void)
1047 {
1048 /*
1049 * In essence, version is 0 and is not supported anymore
1050 */
1051 if (version < CONFIG_MINVERSION)
1052 stop("your sources are out of date -- please update.");
1053 }
1054
1055 static void
1056 app(struct nvlist *p, struct nvlist *q)
1057 {
1058 while (p->nv_next)
1059 p = p->nv_next;
1060 p->nv_next = q;
1061 }
1062
1063 static struct nvlist *
1064 mk_nsis(const char *name, int count, struct nvlist *adefs, int opt)
1065 {
1066 struct nvlist *defs = adefs;
1067 struct nvlist **p;
1068 char buf[200];
1069 int i;
1070
1071 if (count <= 0) {
1072 fprintf(stderr, "config: array with <= 0 size: %s\n", name);
1073 exit(1);
1074 }
1075 p = &defs;
1076 for(i = 0; i < count; i++) {
1077 if (*p == NULL)
1078 *p = new_s("0");
1079 snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
1080 (*p)->nv_name = i == 0 ? name : intern(buf);
1081 (*p)->nv_num = i > 0 || opt;
1082 p = &(*p)->nv_next;
1083 }
1084 *p = 0;
1085 return defs;
1086 }
1087
1088
1089 static struct nvlist *
1090 mk_ns(const char *name, struct nvlist *vals)
1091 {
1092 struct nvlist *p;
1093 char buf[200];
1094 int i;
1095
1096 for(i = 0, p = vals; p; i++, p = p->nv_next) {
1097 snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
1098 p->nv_name = i == 0 ? name : intern(buf);
1099 }
1100 return vals;
1101 }
1102
1103