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