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