xref: /freebsd/usr.sbin/config/config.y (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
1 %union {
2 	char	*str;
3 	int	val;
4 	struct	file_list *file;
5 }
6 
7 %token	AND
8 %token	ANY
9 %token	AT
10 %token	BIO
11 %token	BUS
12 %token	CAM
13 %token	COMMA
14 %token	CONFIG
15 %token	CONFLICTS
16 %token	CONTROLLER
17 %token	CPU
18 %token	DEVICE
19 %token	DISABLE
20 %token	DISK
21 %token	DRIVE
22 %token	DRQ
23 %token	EQUALS
24 %token	FLAGS
25 %token	IDENT
26 %token	IOMEM
27 %token	IOSIZ
28 %token	IRQ
29 %token	MACHINE
30 %token	MAJOR
31 %token	MASTER
32 %token	MAXUSERS
33 %token	MINOR
34 %token	MINUS
35 %token	NET
36 %token	NEXUS
37 %token	OPTIONS
38 %token	MAKEOPTIONS
39 %token	PORT
40 %token	PRIORITY
41 %token	PSEUDO_DEVICE
42 %token	SEMICOLON
43 %token	SEQUENTIAL
44 %token	SIZE
45 %token	SLAVE
46 %token	TARGET
47 %token	TTY
48 %token	TRACE
49 %token	UNIT
50 %token	VECTOR
51 
52 %token	<str>	ID
53 %token	<val>	NUMBER
54 %token	<val>	FPNUMBER
55 
56 %type	<str>	Save_id
57 %type	<str>	Opt_value
58 %type	<str>	Dev
59 %type	<str>	device_name
60 
61 %{
62 
63 /*
64  * Copyright (c) 1988, 1993
65  *	The Regents of the University of California.  All rights reserved.
66  *
67  * Redistribution and use in source and binary forms, with or without
68  * modification, are permitted provided that the following conditions
69  * are met:
70  * 1. Redistributions of source code must retain the above copyright
71  *    notice, this list of conditions and the following disclaimer.
72  * 2. Redistributions in binary form must reproduce the above copyright
73  *    notice, this list of conditions and the following disclaimer in the
74  *    documentation and/or other materials provided with the distribution.
75  * 3. All advertising materials mentioning features or use of this software
76  *    must display the following acknowledgement:
77  *	This product includes software developed by the University of
78  *	California, Berkeley and its contributors.
79  * 4. Neither the name of the University nor the names of its contributors
80  *    may be used to endorse or promote products derived from this software
81  *    without specific prior written permission.
82  *
83  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
84  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
85  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
86  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
87  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
88  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
89  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
90  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
91  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
92  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
93  * SUCH DAMAGE.
94  *
95  *	@(#)config.y	8.1 (Berkeley) 6/6/93
96  */
97 
98 #include <ctype.h>
99 #include <err.h>
100 #include <stdio.h>
101 #include <string.h>
102 
103 #include "config.h"
104 
105 static struct	device cur;
106 static struct	device *curp = 0;
107 
108 struct  device *dtab;
109 char	*ident;
110 int	yyline;
111 struct  file_list *ftab;
112 char	errbuf[80];
113 int	maxusers;
114 int	do_trace;
115 
116 int	seen_scbus;
117 
118 #define ns(s)	strdup(s)
119 
120 static struct device *connect __P((char *, int));
121 static struct device *huhcon __P((char *));
122 static void yyerror __P((char *s));
123 
124 
125 %}
126 %%
127 Configuration:
128 	Many_specs
129 		;
130 
131 Many_specs:
132 	Many_specs Spec
133 		|
134 	/* lambda */
135 		;
136 
137 Spec:
138 	Device_spec SEMICOLON
139 	      = { newdev(&cur); } |
140 	Config_spec SEMICOLON
141 		|
142 	TRACE SEMICOLON
143 	      = { do_trace = !do_trace; } |
144 	SEMICOLON
145 		|
146 	error SEMICOLON
147 		;
148 
149 Config_spec:
150 	MACHINE Save_id
151 	    = {
152 		if (!strcmp($2, "i386")) {
153 			machine = MACHINE_I386;
154 			machinename = "i386";
155 		} else if (!strcmp($2, "pc98")) {
156 			machine = MACHINE_PC98;
157 			machinename = "pc98";
158 		} else if (!strcmp($2, "alpha")) {
159 			machine = MACHINE_ALPHA;
160 			machinename = "alpha";
161 		} else
162 			yyerror("Unknown machine type");
163 	      } |
164 	CPU Save_id
165 	      = {
166 		struct cputype *cp =
167 		    (struct cputype *)malloc(sizeof (struct cputype));
168 		memset(cp, 0, sizeof(*cp));
169 		cp->cpu_name = $2;
170 		cp->cpu_next = cputype;
171 		cputype = cp;
172 	      } |
173 	OPTIONS Opt_list
174 		|
175 	MAKEOPTIONS Mkopt_list
176 		|
177 	IDENT ID
178 	      = { ident = $2; } |
179 	System_spec
180 		|
181 	MAXUSERS NUMBER
182 	      = { maxusers = $2; };
183 
184 System_spec:
185 	CONFIG System_id System_parameter_list
186 	  = { warnx("line %d: root/dump/swap specifications obsolete", yyline);}
187 	  |
188 	CONFIG System_id
189 	  ;
190 
191 System_id:
192 	Save_id
193 	      = {
194 		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
195 		memset(op, 0, sizeof(*op));
196 		op->op_name = ns("KERNEL");
197 		op->op_ownfile = 0;
198 		op->op_next = mkopt;
199 		op->op_value = $1;
200 		op->op_line = yyline + 1;
201 		mkopt = op;
202 	      };
203 
204 System_parameter_list:
205 	  System_parameter_list ID
206 	| ID
207 	;
208 
209 device_name:
210 	  Save_id
211 		= { $$ = $1; }
212 	| Save_id NUMBER
213 		= {
214 			char buf[80];
215 
216 			(void) snprintf(buf, sizeof(buf), "%s%d", $1, $2);
217 			$$ = ns(buf); free($1);
218 		}
219 	| Save_id NUMBER ID
220 		= {
221 			char buf[80];
222 
223 			(void) snprintf(buf, sizeof(buf), "%s%d%s", $1, $2, $3);
224 			$$ = ns(buf); free($1);
225 		}
226 	| Save_id NUMBER ID NUMBER
227 		= {
228 			char buf[80];
229 
230 			(void) snprintf(buf, sizeof(buf), "%s%d%s%d",
231 			     $1, $2, $3, $4);
232 			$$ = ns(buf); free($1);
233 		}
234 	| Save_id NUMBER ID NUMBER ID
235 		= {
236 			char buf[80];
237 
238 			(void) snprintf(buf, sizeof(buf), "%s%d%s%d%s",
239 			     $1, $2, $3, $4, $5);
240 			$$ = ns(buf); free($1);
241 		}
242 	;
243 
244 Opt_list:
245 	Opt_list COMMA Option
246 		|
247 	Option
248 		;
249 
250 Option:
251 	Save_id
252 	      = {
253 		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
254 		char *s;
255 		memset(op, 0, sizeof(*op));
256 		op->op_name = $1;
257 		op->op_next = opt;
258 		op->op_value = 0;
259 		/*
260 		 * op->op_line is 1-based; yyline is 0-based but is now 1
261 		 * larger than when `Save_id' was lexed.
262 		 */
263 		op->op_line = yyline;
264 		opt = op;
265 		if ((s = strchr(op->op_name, '='))) {
266 			warnx("line %d: The `=' in options should not be quoted", yyline);
267 			*s = '\0';
268 			op->op_value = ns(s + 1);
269 		}
270 	      } |
271 	Save_id EQUALS Opt_value
272 	      = {
273 		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
274 		memset(op, 0, sizeof(*op));
275 		op->op_name = $1;
276 		op->op_next = opt;
277 		op->op_value = $3;
278 		op->op_line = yyline + 1;
279 		opt = op;
280 	      } ;
281 
282 Opt_value:
283 	ID
284 		= { $$ = $1; } |
285 	NUMBER
286 		= {
287 			char buf[80];
288 
289 			(void) snprintf(buf, sizeof(buf), "%d", $1);
290 			$$ = ns(buf);
291 		} ;
292 
293 Save_id:
294 	ID
295 	      = { $$ = $1; }
296 	;
297 
298 Mkopt_list:
299 	Mkopt_list COMMA Mkoption
300 		|
301 	Mkoption
302 		;
303 
304 Mkoption:
305 	Save_id EQUALS Opt_value
306 	      = {
307 		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
308 		memset(op, 0, sizeof(*op));
309 		op->op_name = $1;
310 		op->op_ownfile = 0;	/* for now */
311 		op->op_next = mkopt;
312 		op->op_value = $3;
313 		op->op_line = yyline + 1;
314 		mkopt = op;
315 	      } ;
316 
317 Dev:
318 	ID
319 	      = { $$ = $1; }
320 	;
321 
322 Device_spec:
323 	DEVICE Dev_name Dev_info Int_spec
324 	      = { cur.d_type = DEVICE; } |
325 	MASTER Dev_name Dev_info Int_spec
326 	      = { cur.d_type = MASTER; } |
327 	DISK Dev_name Dev_info Int_spec
328 	      = { cur.d_dk = 1; cur.d_type = DEVICE; } |
329 	CONTROLLER Dev_name Dev_info Int_spec
330 	      = { cur.d_type = CONTROLLER; } |
331 	PSEUDO_DEVICE Init_dev Dev
332 	      = {
333 		cur.d_name = $3;
334 		cur.d_type = PSEUDO_DEVICE;
335 		} |
336 	PSEUDO_DEVICE Init_dev Dev NUMBER
337 	      = {
338 		cur.d_name = $3;
339 		cur.d_type = PSEUDO_DEVICE;
340 		cur.d_slave = $4;
341 		} ;
342 
343 Dev_name:
344 	Init_dev Dev NUMBER
345 	      = {
346 		cur.d_name = $2;
347 		if (eq($2, "scbus"))
348 			seen_scbus = 1;
349 		cur.d_unit = $3;
350 		};
351 
352 Init_dev:
353 	/* lambda */
354 	      = { init_dev(&cur); };
355 
356 Dev_info:
357 	Con_info Info_list
358 		|
359 	/* lambda */
360 		;
361 
362 Con_info:
363 	AT Dev NUMBER
364 	      = {
365 		if (eq(cur.d_name, "mba") || eq(cur.d_name, "uba")) {
366 			(void) snprintf(errbuf, sizeof(errbuf),
367 				"%s must be connected to a nexus", cur.d_name);
368 			yyerror(errbuf);
369 		}
370 		cur.d_conn = connect($2, $3);
371 		} |
372 	AT NEXUS NUMBER
373 	      = { check_nexus(&cur, $3); cur.d_conn = TO_NEXUS; };
374 
375 Info_list:
376 	Info_list Info
377 		|
378 	/* lambda */
379 		;
380 
381 Info:
382 	BUS NUMBER
383 	      = {
384 		if (cur.d_conn != 0 && cur.d_conn->d_type == CONTROLLER)
385 			cur.d_slave = $2;
386 		else
387 			yyerror("can't specify a bus to something "
388 				 "other than a controller");
389 		} |
390 	TARGET NUMBER
391 	      = { cur.d_target = $2; } |
392 	UNIT NUMBER
393 	      = { cur.d_lun = $2; } |
394 	DRIVE NUMBER
395 	      = { cur.d_drive = $2; } |
396 	SLAVE NUMBER
397 	      = {
398 		if (cur.d_conn != 0 && cur.d_conn != TO_NEXUS &&
399 		    cur.d_conn->d_type == MASTER)
400 			cur.d_slave = $2;
401 		else
402 			yyerror("can't specify slave--not to master");
403 		} |
404 	IRQ NUMBER
405 	      = { cur.d_irq = $2; } |
406 	DRQ NUMBER
407 	      = { cur.d_drq = $2; } |
408 	IOMEM NUMBER
409 	      = { cur.d_maddr = $2; } |
410 	IOSIZ NUMBER
411 	      = { cur.d_msize = $2; } |
412 	PORT device_name
413 	      = { cur.d_port = $2; } |
414 	PORT NUMBER
415 	      = { cur.d_portn = $2; } |
416 	TTY
417 	      = { yyerror("`tty' interrupt label obsolete"); } |
418 	BIO
419 	      = { yyerror("`bio' interrupt label obsolete"); } |
420 	CAM
421 	      = { yyerror("`cam' interrupt label obsolete"); } |
422 	NET
423 	      = { yyerror("`net' interrupt label obsolete"); } |
424 	FLAGS NUMBER
425 	      = { cur.d_flags = $2; } |
426 	DISABLE
427 	      = { cur.d_disabled = 1; } |
428 	CONFLICTS
429 	      = { cur.d_conflicts = 1; };
430 
431 Int_spec:
432 	VECTOR ID
433 	      = { yyerror("`vector xxxintr' interrupt vector obsolete"); } |
434 	PRIORITY NUMBER
435 	      = { yyerror("`priority nnn' interrupt priority obsolete"); } |
436 	/* lambda */
437 		;
438 
439 %%
440 
441 static void
442 yyerror(s)
443 	char *s;
444 {
445 
446 	warnx("line %d: %s", yyline + 1, s);
447 }
448 
449 /*
450  * add a device to the list of devices
451  */
452 static void
453 newdev(dp)
454 	register struct device *dp;
455 {
456 	register struct device *np, *xp;
457 
458 	if (dp->d_unit >= 0) {
459 		for (xp = dtab; xp != 0; xp = xp->d_next) {
460 			if ((xp->d_unit == dp->d_unit) &&
461 			    eq(xp->d_name, dp->d_name)) {
462 				warnx("line %d: already seen device %s%d",
463 				    yyline, xp->d_name, xp->d_unit);
464 			}
465 		}
466 	}
467 	np = (struct device *) malloc(sizeof *np);
468 	memset(np, 0, sizeof(*np));
469 	*np = *dp;
470 	np->d_next = 0;
471 	if (curp == 0)
472 		dtab = np;
473 	else
474 		curp->d_next = np;
475 	curp = np;
476 }
477 
478 
479 /*
480  * find the pointer to connect to the given device and number.
481  * returns 0 if no such device and prints an error message
482  */
483 static struct device *
484 connect(dev, num)
485 	register char *dev;
486 	register int num;
487 {
488 	register struct device *dp;
489 
490 	if (num == QUES)
491 		return (huhcon(dev));
492 	for (dp = dtab; dp != 0; dp = dp->d_next) {
493 		if ((num != dp->d_unit) || !eq(dev, dp->d_name))
494 			continue;
495 		if (dp->d_type != CONTROLLER && dp->d_type != MASTER) {
496 			(void) snprintf(errbuf, sizeof(errbuf),
497 			    "%s connected to non-controller", dev);
498 			yyerror(errbuf);
499 			return (0);
500 		}
501 		return (dp);
502 	}
503 	(void) snprintf(errbuf, sizeof(errbuf), "%s %d not defined", dev, num);
504 	yyerror(errbuf);
505 	return (0);
506 }
507 
508 /*
509  * connect to an unspecific thing
510  */
511 static struct device *
512 huhcon(dev)
513 	register char *dev;
514 {
515 	register struct device *dp, *dcp;
516 	struct device rdev;
517 	int oldtype;
518 
519 	/*
520 	 * First make certain that there are some of these to wildcard on
521 	 */
522 	for (dp = dtab; dp != 0; dp = dp->d_next)
523 		if (eq(dp->d_name, dev))
524 			break;
525 	if (dp == 0) {
526 		(void) snprintf(errbuf, sizeof(errbuf), "no %s's to wildcard",
527 		   dev);
528 		yyerror(errbuf);
529 		return (0);
530 	}
531 	oldtype = dp->d_type;
532 	dcp = dp->d_conn;
533 	/*
534 	 * Now see if there is already a wildcard entry for this device
535 	 * (e.g. Search for a "uba ?")
536 	 */
537 	for (; dp != 0; dp = dp->d_next)
538 		if (eq(dev, dp->d_name) && dp->d_unit == -1)
539 			break;
540 	/*
541 	 * If there isn't, make one because everything needs to be connected
542 	 * to something.
543 	 */
544 	if (dp == 0) {
545 		dp = &rdev;
546 		init_dev(dp);
547 		dp->d_unit = QUES;
548 		dp->d_name = ns(dev);
549 		dp->d_type = oldtype;
550 		newdev(dp);
551 		dp = curp;
552 		/*
553 		 * Connect it to the same thing that other similar things are
554 		 * connected to, but make sure it is a wildcard unit
555 		 * (e.g. up connected to sc ?, here we make connect sc? to a
556 		 * uba?).  If other things like this are on the NEXUS or
557 		 * if they aren't connected to anything, then make the same
558 		 * connection, else call ourself to connect to another
559 		 * unspecific device.
560 		 */
561 		if (dcp == TO_NEXUS || dcp == 0)
562 			dp->d_conn = dcp;
563 		else
564 			dp->d_conn = connect(dcp->d_name, QUES);
565 	}
566 	return (dp);
567 }
568 
569 void
570 init_dev(dp)
571 	register struct device *dp;
572 {
573 
574 	dp->d_name = "OHNO!!!";
575 	dp->d_type = DEVICE;
576 	dp->d_conn = 0;
577 	dp->d_conflicts = 0;
578 	dp->d_disabled = 0;
579 	dp->d_flags = dp->d_dk = 0;
580 	dp->d_slave = dp->d_lun = dp->d_target = dp->d_drive = dp->d_unit = UNKNOWN;
581 	dp->d_port = (char *)0;
582 	dp->d_portn = -1;
583 	dp->d_irq = -1;
584 	dp->d_drq = -1;
585 	dp->d_maddr = 0;
586 	dp->d_msize = 0;
587 }
588 
589 /*
590  * make certain that this is a reasonable type of thing to connect to a nexus
591  */
592 static void
593 check_nexus(dev, num)
594 	register struct device *dev;
595 	int num;
596 {
597 
598 	switch (machine) {
599 
600 	case MACHINE_I386:
601 	case MACHINE_PC98:
602 #if 0
603 		if (!eq(dev->d_name, "isa"))
604 			yyerror("only isa's should be connected to the nexus");
605 #endif
606 		break;
607 
608 	}
609 }
610