1 %union {
2 char *str;
3 int val;
4 struct file_list *file;
5 }
6
7 %token ARCH
8 %token COMMA
9 %token CONFIG
10 %token CPU
11 %token NOCPU
12 %token DEVICE
13 %token NODEVICE
14 %token ENV
15 %token ENVVAR
16 %token EQUALS
17 %token PLUSEQUALS
18 %token HINTS
19 %token IDENT
20 %token MAXUSERS
21 %token OPTIONS
22 %token NOOPTION
23 %token MAKEOPTIONS
24 %token NOMAKEOPTION
25 %token SEMICOLON
26 %token INCLUDE
27 %token INCLUDEOPTIONS
28 %token FILES
29
30 %token <str> ENVLINE
31 %token <str> ID
32 %token <val> NUMBER
33
34 %type <str> Save_id
35 %type <str> Opt_value
36 %type <str> Dev
37 %token <str> PATH
38
39 %{
40
41 /*-
42 * SPDX-License-Identifier: BSD-3-Clause
43 *
44 * Copyright (c) 1988, 1993
45 * The Regents of the University of California. All rights reserved.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 */
71
72 #include <assert.h>
73 #include <ctype.h>
74 #include <err.h>
75 #include <stdio.h>
76 #include <string.h>
77
78 #include "config.h"
79
80 struct device_head dtab;
81 char *ident;
82 char *env;
83 int yyline;
84 const char *yyfile;
85 struct file_list_head ftab;
86 struct files_name_head fntab;
87 struct options_files_name_head optfntab;
88 char errbuf[80];
89 int maxusers;
90
91 #define ns(s) strdup(s)
92 int include(const char *, int);
93 int yyerror(const char *s);
94 int yywrap(void);
95
96 static void newdev(char *name);
97 static void newfile(char *name);
98 static void newoptionsfile(char *name);
99 static void newenvvar(char *name, bool is_file);
100 static void rmdev_schedule(struct device_head *dh, char *name);
101 static void newopt(struct opt_head *list, char *name, char *value, int append, int dupe);
102 static void rmopt_schedule(struct opt_head *list, char *name);
103
104 static char *
devopt(char * dev)105 devopt(char *dev)
106 {
107 char *ret = malloc(strlen(dev) + 5);
108
109 sprintf(ret, "DEV_%s", dev);
110 raisestr(ret);
111 return ret;
112 }
113
114 %}
115 %%
116 Configuration:
117 Many_specs
118 ;
119
120 Many_specs:
121 Many_specs Spec
122 |
123 /* lambda */
124 ;
125
126 Spec:
127 Device_spec SEMICOLON
128 |
129 Config_spec SEMICOLON
130 |
131 INCLUDE PATH SEMICOLON {
132 if (incignore == 0)
133 include($2, 0);
134 };
135 |
136 INCLUDE ID SEMICOLON {
137 if (incignore == 0)
138 include($2, 0);
139 };
140 |
141 INCLUDEOPTIONS PATH SEMICOLON { newoptionsfile($2); };
142 |
143 INCLUDEOPTIONS ID SEMICOLON { newoptionsfile($2); };
144 |
145 FILES ID SEMICOLON { newfile($2); };
146 |
147 SEMICOLON
148 |
149 error SEMICOLON
150 ;
151
152 Config_spec:
153 ARCH Save_id {
154 if (machinename != NULL && !eq($2, machinename))
155 errx(1, "%s:%d: only one machine directive is allowed",
156 yyfile, yyline);
157 machinename = $2;
158 machinearch = $2;
159 } |
160 ARCH Save_id Save_id {
161 /*
162 * Allow the machinearch to change with a second machine directive,
163 * but still enforce no changes to the machinename.
164 */
165 if (machinename != NULL && !eq($2, machinename))
166 errx(1, "%s:%d: only one machine directive is allowed",
167 yyfile, yyline);
168 machinename = $2;
169 machinearch = $3;
170 } |
171 CPU Save_id {
172 struct cputype *cp =
173 (struct cputype *)calloc(1, sizeof (struct cputype));
174 if (cp == NULL)
175 err(EXIT_FAILURE, "calloc");
176 cp->cpu_name = $2;
177 SLIST_INSERT_HEAD(&cputype, cp, cpu_next);
178 } |
179 NOCPU Save_id {
180 struct cputype *cp, *cp2;
181 SLIST_FOREACH_SAFE(cp, &cputype, cpu_next, cp2) {
182 if (eq(cp->cpu_name, $2)) {
183 SLIST_REMOVE(&cputype, cp, cputype, cpu_next);
184 free(cp);
185 }
186 }
187 } |
188 OPTIONS Opt_list
189 |
190 NOOPTION NoOpt_list |
191 MAKEOPTIONS Mkopt_list
192 |
193 NOMAKEOPTION Save_id { rmopt_schedule(&mkopt, $2); } |
194 IDENT ID { ident = $2; } |
195 MAXUSERS NUMBER { maxusers = $2; } |
196 ENV ID { newenvvar($2, true); } |
197 ENVVAR ENVLINE { newenvvar($2, false); } |
198 HINTS ID {
199 struct hint *hint;
200
201 hint = (struct hint *)calloc(1, sizeof (struct hint));
202 if (hint == NULL)
203 err(EXIT_FAILURE, "calloc");
204 hint->hint_name = $2;
205 STAILQ_INSERT_HEAD(&hints, hint, hint_next);
206 }
207
208 System_id:
209 Save_id { newopt(&mkopt, ns("KERNEL"), $1, 0, 0); };
210
211 System_parameter_list:
212 System_parameter_list ID
213 | ID
214 ;
215
216 Opt_list:
217 Opt_list COMMA Option
218 |
219 Option
220 ;
221
222 NoOpt_list:
223 NoOpt_list COMMA NoOption
224 |
225 NoOption
226 ;
227 Option:
228 Save_id {
229 newopt(&opt, $1, NULL, 0, 1);
230 if (strchr($1, '=') != NULL)
231 errx(1, "%s:%d: The `=' in options should not be "
232 "quoted", yyfile, yyline);
233 } |
234 Save_id EQUALS Opt_value {
235 newopt(&opt, $1, $3, 0, 1);
236 } ;
237
238 NoOption:
239 Save_id {
240 rmopt_schedule(&opt, $1);
241 };
242
243 Opt_value:
244 ID { $$ = $1; } |
245 NUMBER {
246 char buf[80];
247
248 (void) snprintf(buf, sizeof(buf), "%d", $1);
249 $$ = ns(buf);
250 } ;
251
252 Save_id:
253 ID { $$ = $1; }
254 ;
255
256 Mkopt_list:
257 Mkopt_list COMMA Mkoption
258 |
259 Mkoption
260 ;
261
262 Mkoption:
263 Save_id { newopt(&mkopt, $1, ns(""), 0, 0); } |
264 Save_id EQUALS { newopt(&mkopt, $1, ns(""), 0, 0); } |
265 Save_id EQUALS Opt_value { newopt(&mkopt, $1, $3, 0, 0); } |
266 Save_id PLUSEQUALS Opt_value { newopt(&mkopt, $1, $3, 1, 0); } ;
267
268 Dev:
269 ID { $$ = $1; }
270 ;
271
272 Device_spec:
273 DEVICE Dev_list
274 |
275 NODEVICE NoDev_list
276 ;
277
278 Dev_list:
279 Dev_list COMMA Device
280 |
281 Device
282 ;
283
284 NoDev_list:
285 NoDev_list COMMA NoDevice
286 |
287 NoDevice
288 ;
289
290 Device:
291 Dev {
292 newopt(&opt, devopt($1), ns("1"), 0, 0);
293 /* and the device part */
294 newdev($1);
295 }
296
297 NoDevice:
298 Dev {
299 char *s = devopt($1);
300
301 rmopt_schedule(&opt, s);
302 free(s);
303 /* and the device part */
304 rmdev_schedule(&dtab, $1);
305 } ;
306
307 %%
308
309 int
310 yyerror(const char *s)
311 {
312
313 errx(1, "%s:%d: %s", yyfile, yyline + 1, s);
314 }
315
316 int
yywrap(void)317 yywrap(void)
318 {
319 if (found_defaults) {
320 if (freopen(PREFIX, "r", stdin) == NULL)
321 err(2, "%s", PREFIX);
322 yyfile = PREFIX;
323 yyline = 0;
324 found_defaults = 0;
325 return 0;
326 }
327 return 1;
328 }
329
330 /*
331 * Add a new file to the list of files.
332 */
333 static void
newfile(char * name)334 newfile(char *name)
335 {
336 struct files_name *nl;
337
338 nl = (struct files_name *) calloc(1, sizeof *nl);
339 if (nl == NULL)
340 err(EXIT_FAILURE, "calloc");
341 nl->f_name = name;
342 STAILQ_INSERT_TAIL(&fntab, nl, f_next);
343 }
344
345 /*
346 * Add a new options file to the list of options files.
347 */
348 static void
newoptionsfile(char * name)349 newoptionsfile(char *name)
350 {
351 struct files_name *nl;
352
353 nl = (struct files_name *) calloc(1, sizeof *nl);
354 if (nl == NULL)
355 err(EXIT_FAILURE, "calloc");
356 nl->f_name = name;
357 STAILQ_INSERT_TAIL(&optfntab, nl, f_next);
358 }
359
360 static void
newenvvar(char * name,bool is_file)361 newenvvar(char *name, bool is_file)
362 {
363 struct envvar *envvar;
364
365 envvar = (struct envvar *)calloc(1, sizeof (struct envvar));
366 if (envvar == NULL)
367 err(EXIT_FAILURE, "calloc");
368 envvar->env_str = name;
369 envvar->env_is_file = is_file;
370 STAILQ_INSERT_HEAD(&envvars, envvar, envvar_next);
371 }
372
373 /*
374 * Find a device in the list of devices.
375 */
376 static struct device *
finddev(struct device_head * dlist,char * name)377 finddev(struct device_head *dlist, char *name)
378 {
379 struct device *dp;
380
381 STAILQ_FOREACH(dp, dlist, d_next)
382 if (eq(dp->d_name, name))
383 return (dp);
384
385 return (NULL);
386 }
387
388 /*
389 * Add a device to the list of devices.
390 */
391 static void
newdev(char * name)392 newdev(char *name)
393 {
394 struct device *np, *dp;
395
396 if ((dp = finddev(&dtab, name)) != NULL) {
397 if (strcmp(dp->yyfile, yyfile) == 0)
398 fprintf(stderr,
399 "WARNING: duplicate device `%s' encountered in %s\n",
400 name, yyfile);
401 return;
402 }
403
404 np = (struct device *) calloc(1, sizeof *np);
405 if (np == NULL)
406 err(EXIT_FAILURE, "calloc");
407 np->d_name = name;
408 np->yyfile = strdup(yyfile);
409 STAILQ_INSERT_TAIL(&dtab, np, d_next);
410 }
411
412 /*
413 * Schedule a device to removal.
414 */
415 static void
rmdev_schedule(struct device_head * dh,char * name)416 rmdev_schedule(struct device_head *dh, char *name)
417 {
418 struct device *dp;
419
420 dp = finddev(dh, name);
421 if (dp != NULL) {
422 STAILQ_REMOVE(dh, dp, device, d_next);
423 free(dp->yyfile);
424 free(dp->d_name);
425 free(dp);
426 }
427 }
428
429 /*
430 * Find an option in the list of options.
431 */
432 static struct opt *
findopt(struct opt_head * list,char * name)433 findopt(struct opt_head *list, char *name)
434 {
435 struct opt *op;
436
437 SLIST_FOREACH(op, list, op_next)
438 if (eq(op->op_name, name))
439 return (op);
440
441 return (NULL);
442 }
443
444 /*
445 * Add an option to the list of options.
446 */
447 static void
newopt(struct opt_head * list,char * name,char * value,int append,int dupe)448 newopt(struct opt_head *list, char *name, char *value, int append, int dupe)
449 {
450 struct opt *op, *op2;
451
452 /*
453 * Ignore inclusions listed explicitly for configuration files.
454 */
455 if (eq(name, OPT_AUTOGEN)) {
456 incignore = 1;
457 return;
458 }
459
460 op2 = findopt(list, name);
461 if (op2 != NULL && !append && !dupe) {
462 if (strcmp(op2->yyfile, yyfile) == 0)
463 fprintf(stderr,
464 "WARNING: duplicate option `%s' encountered.\n", name);
465 return;
466 }
467
468 op = (struct opt *)calloc(1, sizeof (struct opt));
469 if (op == NULL)
470 err(EXIT_FAILURE, "calloc");
471 op->op_name = name;
472 op->op_ownfile = 0;
473 op->op_value = value;
474 op->yyfile = strdup(yyfile);
475 if (op2 != NULL) {
476 if (append) {
477 while (SLIST_NEXT(op2, op_append) != NULL)
478 op2 = SLIST_NEXT(op2, op_append);
479 SLIST_NEXT(op2, op_append) = op;
480 } else {
481 while (SLIST_NEXT(op2, op_next) != NULL)
482 op2 = SLIST_NEXT(op2, op_next);
483 SLIST_NEXT(op2, op_next) = op;
484 }
485 } else
486 SLIST_INSERT_HEAD(list, op, op_next);
487 }
488
489 /*
490 * Remove an option from the list of options.
491 */
492 static void
rmopt_schedule(struct opt_head * list,char * name)493 rmopt_schedule(struct opt_head *list, char *name)
494 {
495 struct opt *op;
496
497 while ((op = findopt(list, name)) != NULL) {
498 SLIST_REMOVE(list, op, opt, op_next);
499 free(op->yyfile);
500 free(op->op_name);
501 free(op);
502 }
503 }
504