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