xref: /freebsd/usr.sbin/config/config.y (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
1 %union {
2 	char	*str;
3 	int	val;
4 	struct	file_list *file;
5 	struct	idlst *lst;
6 }
7 
8 %token	AND
9 %token	ANY
10 %token	ARGS
11 %token	AT
12 %token	BIO
13 %token	BUS
14 %token	CAM
15 %token	HA
16 %token	COMMA
17 %token	CONFIG
18 %token	CONFLICTS
19 %token	CONTROLLER
20 %token	CPU
21 %token	CSR
22 %token	DEVICE
23 %token	DISABLE
24 %token	DISK
25 %token	DRIVE
26 %token	DRQ
27 %token	DUMPS
28 %token	EQUALS
29 %token	FLAGS
30 %token	IDENT
31 %token	INTERLEAVE
32 %token	IOMEM
33 %token	IOSIZ
34 %token	IRQ
35 %token	MACHINE
36 %token	MAJOR
37 %token	MASTER
38 %token	MAXUSERS
39 %token	MINOR
40 %token	MINUS
41 %token	NET
42 %token	NEXUS
43 %token	ON
44 %token	OPTIONS
45 %token	MAKEOPTIONS
46 %token	PORT
47 %token	PRIORITY
48 %token	PSEUDO_DEVICE
49 %token	ROOT
50 %token	SEMICOLON
51 %token	SEQUENTIAL
52 %token	SIZE
53 %token	SLAVE
54 %token	SWAP
55 %token	TARGET
56 %token	TTY
57 %token	TRACE
58 %token	UNIT
59 %token	VECTOR
60 
61 %token	<str>	ID
62 %token	<val>	NUMBER
63 %token	<val>	FPNUMBER
64 
65 %type	<str>	Save_id
66 %type	<str>	Opt_value
67 %type	<str>	Dev
68 %type	<lst>	Id_list
69 %type	<val>	optional_size
70 %type	<val>	optional_sflag
71 %type	<str>	device_name
72 %type	<val>	major_minor
73 %type	<val>	arg_device_spec
74 %type	<val>	root_device_spec root_device_specs
75 %type	<val>	dump_device_spec
76 %type	<file>	swap_device_spec
77 %type	<file>	comp_device_spec
78 
79 %{
80 
81 /*
82  * Copyright (c) 1988, 1993
83  *	The Regents of the University of California.  All rights reserved.
84  *
85  * Redistribution and use in source and binary forms, with or without
86  * modification, are permitted provided that the following conditions
87  * are met:
88  * 1. Redistributions of source code must retain the above copyright
89  *    notice, this list of conditions and the following disclaimer.
90  * 2. Redistributions in binary form must reproduce the above copyright
91  *    notice, this list of conditions and the following disclaimer in the
92  *    documentation and/or other materials provided with the distribution.
93  * 3. All advertising materials mentioning features or use of this software
94  *    must display the following acknowledgement:
95  *	This product includes software developed by the University of
96  *	California, Berkeley and its contributors.
97  * 4. Neither the name of the University nor the names of its contributors
98  *    may be used to endorse or promote products derived from this software
99  *    without specific prior written permission.
100  *
101  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
102  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
103  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
104  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
105  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
106  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
107  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
108  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
109  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
110  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
111  * SUCH DAMAGE.
112  *
113  *	@(#)config.y	8.1 (Berkeley) 6/6/93
114  */
115 
116 #include "config.h"
117 
118 #include <sys/disklabel.h>
119 #include <sys/diskslice.h>
120 #ifdef linux
121 #include <sys/sysmacros.h>
122 #endif
123 
124 #include <ctype.h>
125 #include <err.h>
126 #include <stdio.h>
127 #include <string.h>
128 
129 struct	device cur;
130 struct	device *curp = 0;
131 
132 #define ns(s)	strdup(s)
133 
134 int alreadychecked __P((dev_t, dev_t[], dev_t *));
135 void deverror __P((char *, char *));
136 int finddev __P((dev_t));
137 void init_dev __P((struct device *));
138 void verifycomp __P((struct file_list *));
139 
140 %}
141 %%
142 Configuration:
143 	Many_specs
144 		= { verifysystemspecs(); }
145 		;
146 
147 Many_specs:
148 	Many_specs Spec
149 		|
150 	/* lambda */
151 		;
152 
153 Spec:
154 	Device_spec SEMICOLON
155 	      = { newdev(&cur); } |
156 	Config_spec SEMICOLON
157 		|
158 	TRACE SEMICOLON
159 	      = { do_trace = !do_trace; } |
160 	SEMICOLON
161 		|
162 	error SEMICOLON
163 		;
164 
165 Config_spec:
166 	MACHINE Save_id
167 	    = {
168 		if (!strcmp($2, "vax")) {
169 			machine = MACHINE_VAX;
170 			machinename = "vax";
171 		} else if (!strcmp($2, "tahoe")) {
172 			machine = MACHINE_TAHOE;
173 			machinename = "tahoe";
174 		} else if (!strcmp($2, "hp300")) {
175 			machine = MACHINE_HP300;
176 			machinename = "hp300";
177 		} else if (!strcmp($2, "i386")) {
178 			machine = MACHINE_I386;
179 			machinename = "i386";
180 		} else if (!strcmp($2, "pc98")) {
181 			machine = MACHINE_PC98;
182 			machinename = "pc98";
183 		} else if (!strcmp($2, "mips")) {
184 			machine = MACHINE_MIPS;
185 			machinename = "mips";
186 		} else if (!strcmp($2, "pmax")) {
187 			machine = MACHINE_PMAX;
188 			machinename = "pmax";
189 		} else if (!strcmp($2, "luna68k")) {
190 			machine = MACHINE_LUNA68K;
191 			machinename = "luna68k";
192 		} else if (!strcmp($2, "news3400")) {
193 			machine = MACHINE_NEWS3400;
194 			machinename = "news3400";
195 		} else if (!strcmp($2, "alpha")) {
196 			machine = MACHINE_ALPHA;
197 			machinename = "alpha";
198 		} else
199 			yyerror("Unknown machine type");
200 	      } |
201 	CPU Save_id
202 	      = {
203 		struct cputype *cp =
204 		    (struct cputype *)malloc(sizeof (struct cputype));
205 		memset(cp, 0, sizeof(*cp));
206 		cp->cpu_name = $2;
207 		cp->cpu_next = cputype;
208 		cputype = cp;
209 	      } |
210 	OPTIONS Opt_list
211 		|
212 	MAKEOPTIONS Mkopt_list
213 		|
214 	IDENT ID
215 	      = { ident = $2; } |
216 	System_spec
217 		|
218 	MAXUSERS NUMBER
219 	      = { maxusers = $2; };
220 
221 System_spec:
222 	  System_id System_parameter_list
223 		= { checksystemspec(*confp); }
224 	;
225 
226 System_id:
227 	  CONFIG Save_id
228 		= { mkconf($2); }
229 	;
230 
231 System_parameter_list:
232 	  System_parameter_list System_parameter
233 	| System_parameter
234 	;
235 
236 System_parameter:
237 	  addr_spec
238 	| swap_spec
239 	| root_spec
240 	| dump_spec
241 	| arg_spec
242 	;
243 
244 addr_spec:
245 	  AT NUMBER
246 		= { loadaddress = $2; }
247 	;
248 
249 swap_spec:
250 	  SWAP optional_on swap_device_list
251 	;
252 
253 swap_device_list:
254 	  swap_device_list AND swap_device
255 	| swap_device
256 	;
257 
258 swap_device:
259 	  swap_device_spec optional_size optional_sflag
260 	      = { mkswap(*confp, $1, $2, $3); }
261 	;
262 
263 swap_device_spec:
264 	  device_name
265 		= {
266 			struct file_list *fl = newflist(SWAPSPEC);
267 
268 			if (eq($1, "generic"))
269 				fl->f_fn = $1;
270 			else {
271 				fl->f_swapdev = nametodev($1, 0,
272 						    COMPATIBILITY_SLICE, 'b');
273 				fl->f_fn = devtoname(fl->f_swapdev);
274 			}
275 			$$ = fl;
276 		}
277 	| major_minor
278 		= {
279 			struct file_list *fl = newflist(SWAPSPEC);
280 
281 			fl->f_swapdev = $1;
282 			fl->f_fn = devtoname($1);
283 			$$ = fl;
284 		}
285 	;
286 
287 root_spec:
288 	  ROOT optional_on root_device_specs
289 		= {
290 			struct file_list *fl = *confp;
291 
292 			if (fl && fl->f_rootdev != NODEV)
293 				yyerror("extraneous root device specification");
294 			else
295 				fl->f_rootdev = $3;
296 		}
297 	;
298 
299 root_device_specs:
300 	  root_device_spec AND root_device_specs
301 		= {
302 			warnx("extraneous root devices ignored");
303 			$$ = $1;
304 		  }
305 	| root_device_spec
306 	;
307 
308 root_device_spec:
309 	  device_name
310 		= { $$ = nametodev($1, 0, COMPATIBILITY_SLICE, 'a'); }
311 	| major_minor
312 	;
313 
314 dump_spec:
315 	  DUMPS optional_on dump_device_spec
316 		= {
317 			struct file_list *fl = *confp;
318 
319 			if (fl && fl->f_dumpdev != NODEV)
320 				yyerror("extraneous dump device specification");
321 			else
322 				fl->f_dumpdev = $3;
323 		}
324 
325 	;
326 
327 dump_device_spec:
328 	  device_name
329 		= { $$ = nametodev($1, 0, COMPATIBILITY_SLICE, 'b'); }
330 	| major_minor
331 	;
332 
333 arg_spec:
334 	  ARGS optional_on arg_device_spec
335 		= { yyerror("arg device specification obsolete, ignored"); }
336 	;
337 
338 arg_device_spec:
339 	  device_name
340 		= { $$ = nametodev($1, 0, COMPATIBILITY_SLICE, 'b'); }
341 	| major_minor
342 	;
343 
344 major_minor:
345 	  MAJOR NUMBER MINOR NUMBER
346 		= { $$ = makedev($2, $4); }
347 	;
348 
349 optional_on:
350 	  ON
351 	| /* empty */
352 	;
353 
354 optional_size:
355 	  SIZE NUMBER
356 	      = { $$ = $2; }
357 	| /* empty */
358 	      = { $$ = 0; }
359 	;
360 
361 optional_sflag:
362 	  SEQUENTIAL
363 	      = { $$ = 2; }
364 	| /* empty */
365 	      = { $$ = 0; }
366 	;
367 
368 device_name:
369 	  Save_id
370 		= { $$ = $1; }
371 	| Save_id NUMBER
372 		= {
373 			char buf[80];
374 
375 			(void) snprintf(buf, 80, "%s%d", $1, $2);
376 			$$ = ns(buf); free($1);
377 		}
378 	| Save_id NUMBER ID
379 		= {
380 			char buf[80];
381 
382 			(void) snprintf(buf, 80, "%s%d%s", $1, $2, $3);
383 			$$ = ns(buf); free($1);
384 		}
385 	| Save_id NUMBER ID NUMBER
386 		= {
387 			char buf[80];
388 
389 			(void) snprintf(buf, 80, "%s%d%s%d", $1, $2, $3, $4);
390 			$$ = ns(buf); free($1);
391 		}
392 	| Save_id NUMBER ID NUMBER ID
393 		= {
394 			char buf[80];
395 
396 			(void) snprintf(buf, 80, "%s%d%s%d%s",
397 			     $1, $2, $3, $4, $5);
398 			$$ = ns(buf); free($1);
399 		}
400 	;
401 
402 Opt_list:
403 	Opt_list COMMA Option
404 		|
405 	Option
406 		;
407 
408 Option:
409 	Save_id
410 	      = {
411 		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
412 		char *s;
413 		memset(op, 0, sizeof(*op));
414 		op->op_name = $1;
415 		op->op_next = opt;
416 		op->op_value = 0;
417 		/*
418 		 * op->op_line is 1-based; yyline is 0-based but is now 1
419 		 * larger than when `Save_id' was lexed.
420 		 */
421 		op->op_line = yyline;
422 		opt = op;
423 		if ((s = strchr(op->op_name, '='))) {
424 			/* AARGH!!!! Old-style bogon */
425 			*s = '\0';
426 			op->op_value = ns(s + 1);
427 		}
428 	      } |
429 	Save_id EQUALS Opt_value
430 	      = {
431 		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
432 		memset(op, 0, sizeof(*op));
433 		op->op_name = $1;
434 		op->op_next = opt;
435 		op->op_value = $3;
436 		op->op_line = yyline + 1;
437 		opt = op;
438 	      } ;
439 
440 Opt_value:
441 	ID
442 	      = { $$ = $1; } |
443 	NUMBER
444 	      = {
445 		char nb[16];
446 	        (void) sprintf(nb, "%d", $1);
447 		$$ = ns(nb);
448 	      } ;
449 
450 
451 Save_id:
452 	ID
453 	      = { $$ = $1; }
454 	;
455 
456 Mkopt_list:
457 	Mkopt_list COMMA Mkoption
458 		|
459 	Mkoption
460 		;
461 
462 Mkoption:
463 	Save_id EQUALS Opt_value
464 	      = {
465 		struct opt *op = (struct opt *)malloc(sizeof (struct opt));
466 		memset(op, 0, sizeof(*op));
467 		op->op_name = $1;
468 		op->op_ownfile = 0;	/* for now */
469 		op->op_next = mkopt;
470 		op->op_value = $3;
471 		op->op_line = yyline + 1;
472 		mkopt = op;
473 	      } ;
474 
475 Dev:
476 	ID
477 	      = { $$ = $1; }
478 	;
479 
480 Device_spec:
481 	DEVICE Dev_name Dev_info Int_spec
482 	      = { cur.d_type = DEVICE; } |
483 	MASTER Dev_name Dev_info Int_spec
484 	      = { cur.d_type = MASTER; } |
485 	DISK Dev_name Dev_info Int_spec
486 	      = { cur.d_dk = 1; cur.d_type = DEVICE; } |
487 	CONTROLLER Dev_name Dev_info Int_spec
488 	      = { cur.d_type = CONTROLLER; } |
489 	PSEUDO_DEVICE Init_dev Dev
490 	      = {
491 		cur.d_name = $3;
492 		cur.d_type = PSEUDO_DEVICE;
493 		} |
494 	PSEUDO_DEVICE Init_dev Dev NUMBER
495 	      = {
496 		cur.d_name = $3;
497 		cur.d_type = PSEUDO_DEVICE;
498 		cur.d_slave = $4;
499 		} |
500 	PSEUDO_DEVICE Dev_name Cdev_init Cdev_info
501 	      = {
502 		if (!eq(cur.d_name, "cd"))
503 			yyerror("improper spec for pseudo-device");
504 		seen_cd = 1;
505 		cur.d_type = DEVICE;
506 		verifycomp(*compp);
507 		};
508 
509 Cdev_init:
510 	/* lambda */
511 	      = { mkcomp(&cur); };
512 
513 Cdev_info:
514 	  optional_on comp_device_list comp_option_list
515 	;
516 
517 comp_device_list:
518 	  comp_device_list AND comp_device
519 	| comp_device
520 	;
521 
522 comp_device:
523 	  comp_device_spec
524 	      = { addcomp(*compp, $1); }
525 	;
526 
527 comp_device_spec:
528 	  device_name
529 		= {
530 			struct file_list *fl = newflist(COMPSPEC);
531 
532 			fl->f_compdev = nametodev($1, 0, COMPATIBILITY_SLICE,
533 						  'c');
534 			fl->f_fn = devtoname(fl->f_compdev);
535 			$$ = fl;
536 		}
537 	| major_minor
538 		= {
539 			struct file_list *fl = newflist(COMPSPEC);
540 
541 			fl->f_compdev = $1;
542 			fl->f_fn = devtoname($1);
543 			$$ = fl;
544 		}
545 	;
546 
547 comp_option_list:
548 	  comp_option_list comp_option
549 		|
550 	  /* lambda */
551 		;
552 
553 comp_option:
554 	INTERLEAVE NUMBER
555 	      = { cur.d_pri = $2; } |
556 	FLAGS NUMBER
557 	      = { cur.d_flags = $2; };
558 
559 Dev_name:
560 	Init_dev Dev NUMBER
561 	      = {
562 		cur.d_name = $2;
563 		if (eq($2, "mba"))
564 			seen_mba = 1;
565 		else if (eq($2, "uba"))
566 			seen_uba = 1;
567 		else if (eq($2, "vba"))
568 			seen_vba = 1;
569 		else if (eq($2, "isa"))
570 			seen_isa = 1;
571 		else if (eq($2, "scbus"))
572 			seen_scbus = 1;
573 		cur.d_unit = $3;
574 		};
575 
576 Init_dev:
577 	/* lambda */
578 	      = { init_dev(&cur); };
579 
580 Dev_info:
581 	Con_info Info_list
582 		|
583 	/* lambda */
584 		;
585 
586 Con_info:
587 	AT Dev NUMBER
588 	      = {
589 		if (eq(cur.d_name, "mba") || eq(cur.d_name, "uba")) {
590 			(void) sprintf(errbuf,
591 				"%s must be connected to a nexus", cur.d_name);
592 			yyerror(errbuf);
593 		}
594 		cur.d_conn = connect($2, $3);
595 		} |
596 	AT NEXUS NUMBER
597 	      = { check_nexus(&cur, $3); cur.d_conn = TO_NEXUS; };
598 
599 Info_list:
600 	Info_list Info
601 		|
602 	/* lambda */
603 		;
604 
605 Info:
606 	CSR NUMBER
607 	      = { cur.d_addr = $2; } |
608 	BUS NUMBER
609 	      = {
610 		if (cur.d_conn != 0 && cur.d_conn->d_type == CONTROLLER)
611 			cur.d_slave = $2;
612 		else
613 			yyerror("can't specify a bus to something "
614 				 "other than a controller");
615 		} |
616 	TARGET NUMBER
617 	      = { cur.d_target = $2; } |
618 	UNIT NUMBER
619 	      = { cur.d_lun = $2; } |
620 	DRIVE NUMBER
621 	      = { cur.d_drive = $2; } |
622 	SLAVE NUMBER
623 	      = {
624 		if (cur.d_conn != 0 && cur.d_conn != TO_NEXUS &&
625 		    cur.d_conn->d_type == MASTER)
626 			cur.d_slave = $2;
627 		else
628 			yyerror("can't specify slave--not to master");
629 		} |
630 	IRQ NUMBER
631 	      = { cur.d_irq = $2; } |
632 	DRQ NUMBER
633 	      = { cur.d_drq = $2; } |
634 	IOMEM NUMBER
635 	      = { cur.d_maddr = $2; } |
636 	IOSIZ NUMBER
637 	      = { cur.d_msize = $2; } |
638 	PORT device_name
639 	      = { cur.d_port = $2; } |
640 	PORT NUMBER
641 	      = { cur.d_portn = $2; } |
642 	TTY
643 	      = { cur.d_mask = "tty"; } |
644 	BIO
645 	      = { cur.d_mask = "bio"; } |
646 	CAM
647 	      = { cur.d_mask = "cam"; } |
648 	HA
649 	      = { cur.d_mask = "ha"; } |
650 	NET
651 	      = { cur.d_mask = "net"; } |
652 	FLAGS NUMBER
653 	      = { cur.d_flags = $2; } |
654 	DISABLE
655 	      = { cur.d_disabled = 1; } |
656 	CONFLICTS
657 	      = { cur.d_conflicts = 1; };
658 
659 Int_spec:
660 	VECTOR Id_list
661 	      = { cur.d_vec = $2; } |
662 	PRIORITY NUMBER
663 	      = { cur.d_pri = $2; } |
664 	/* lambda */
665 		;
666 
667 Id_list:
668 	Save_id
669 	      = {
670 		struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
671 		memset(a, 0, sizeof(*a));
672 		a->id = $1; a->id_next = 0; $$ = a;
673 		} |
674 	Save_id Id_list =
675 		{
676 		struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
677 		memset(a, 0, sizeof(*a));
678 	        a->id = $1; a->id_next = $2; $$ = a;
679 		};
680 
681 %%
682 
683 void
684 yyerror(s)
685 	char *s;
686 {
687 
688 	warnx("line %d: %s", yyline + 1, s);
689 }
690 
691 /*
692  * add a device to the list of devices
693  */
694 void
695 newdev(dp)
696 	register struct device *dp;
697 {
698 	register struct device *np;
699 
700 	np = (struct device *) malloc(sizeof *np);
701 	memset(np, 0, sizeof(*np));
702 	*np = *dp;
703 	np->d_next = 0;
704 	if (curp == 0)
705 		dtab = np;
706 	else
707 		curp->d_next = np;
708 	curp = np;
709 }
710 
711 /*
712  * note that a configuration should be made
713  */
714 void
715 mkconf(sysname)
716 	char *sysname;
717 {
718 	register struct file_list *fl, **flp;
719 
720 	fl = (struct file_list *) malloc(sizeof *fl);
721 	memset(fl, 0, sizeof(*fl));
722 	fl->f_type = SYSTEMSPEC;
723 	fl->f_needs = sysname;
724 	fl->f_rootdev = NODEV;
725 	fl->f_dumpdev = NODEV;
726 	fl->f_fn = 0;
727 	fl->f_next = 0;
728 	for (flp = confp; *flp; flp = &(*flp)->f_next)
729 		;
730 	*flp = fl;
731 	confp = flp;
732 }
733 
734 struct file_list *
735 newflist(ftype)
736 	u_char ftype;
737 {
738 	struct file_list *fl = (struct file_list *)malloc(sizeof (*fl));
739 	memset(fl, 0, sizeof(*fl));
740 
741 	fl->f_type = ftype;
742 	fl->f_next = 0;
743 	fl->f_swapdev = NODEV;
744 	fl->f_swapsize = 0;
745 	fl->f_needs = 0;
746 	fl->f_fn = 0;
747 	return (fl);
748 }
749 
750 /*
751  * Add a swap device to the system's configuration
752  */
753 void
754 mkswap(system, fl, size, flag)
755 	struct file_list *system, *fl;
756 	int size, flag;
757 {
758 	register struct file_list **flp;
759 
760 	if (system == 0 || system->f_type != SYSTEMSPEC) {
761 		yyerror("\"swap\" spec precedes \"config\" specification");
762 		return;
763 	}
764 	if (size < 0) {
765 		yyerror("illegal swap partition size");
766 		return;
767 	}
768 	/*
769 	 * Append swap description to the end of the list.
770 	 */
771 	flp = &system->f_next;
772 	for (; *flp && (*flp)->f_type == SWAPSPEC; flp = &(*flp)->f_next)
773 		;
774 	fl->f_next = *flp;
775 	*flp = fl;
776 	fl->f_swapsize = size;
777 	fl->f_swapflag = flag;
778 	/*
779 	 * If first swap device for this system,
780 	 * set up f_fn field to insure swap
781 	 * files are created with unique names.
782 	 */
783 	if (system->f_fn)
784 		return;
785 	if (eq(fl->f_fn, "generic"))
786 		system->f_fn = ns(fl->f_fn);
787 	else
788 		system->f_fn = ns(system->f_needs);
789 }
790 
791 void
792 mkcomp(dp)
793 	register struct device *dp;
794 {
795 	register struct file_list *fl, **flp;
796 	char buf[80];
797 
798 	fl = (struct file_list *) malloc(sizeof *fl);
799 	memset(fl, 0, sizeof(*fl));
800 	fl->f_type = COMPDEVICE;
801 	fl->f_compinfo = dp->d_unit;
802 	fl->f_fn = ns(dp->d_name);
803 	(void) sprintf(buf, "%s%d", dp->d_name, dp->d_unit);
804 	fl->f_needs = ns(buf);
805 	fl->f_next = 0;
806 	for (flp = compp; *flp; flp = &(*flp)->f_next)
807 		;
808 	*flp = fl;
809 	compp = flp;
810 }
811 
812 void
813 addcomp(compdev, fl)
814 	struct file_list *compdev, *fl;
815 {
816 	register struct file_list **flp;
817 
818 	if (compdev == 0 || compdev->f_type != COMPDEVICE) {
819 		yyerror("component spec precedes device specification");
820 		return;
821 	}
822 	/*
823 	 * Append description to the end of the list.
824 	 */
825 	flp = &compdev->f_next;
826 	for (; *flp && (*flp)->f_type == COMPSPEC; flp = &(*flp)->f_next)
827 		;
828 	fl->f_next = *flp;
829 	*flp = fl;
830 }
831 
832 /*
833  * find the pointer to connect to the given device and number.
834  * returns 0 if no such device and prints an error message
835  */
836 struct device *
837 connect(dev, num)
838 	register char *dev;
839 	register int num;
840 {
841 	register struct device *dp;
842 	struct device *huhcon();
843 
844 	if (num == QUES)
845 		return (huhcon(dev));
846 	for (dp = dtab; dp != 0; dp = dp->d_next) {
847 		if ((num != dp->d_unit) || !eq(dev, dp->d_name))
848 			continue;
849 		if (dp->d_type != CONTROLLER && dp->d_type != MASTER) {
850 			(void) sprintf(errbuf,
851 			    "%s connected to non-controller", dev);
852 			yyerror(errbuf);
853 			return (0);
854 		}
855 		return (dp);
856 	}
857 	(void) sprintf(errbuf, "%s %d not defined", dev, num);
858 	yyerror(errbuf);
859 	return (0);
860 }
861 
862 /*
863  * connect to an unspecific thing
864  */
865 struct device *
866 huhcon(dev)
867 	register char *dev;
868 {
869 	register struct device *dp, *dcp;
870 	struct device rdev;
871 	int oldtype;
872 
873 	/*
874 	 * First make certain that there are some of these to wildcard on
875 	 */
876 	for (dp = dtab; dp != 0; dp = dp->d_next)
877 		if (eq(dp->d_name, dev))
878 			break;
879 	if (dp == 0) {
880 		(void) sprintf(errbuf, "no %s's to wildcard", dev);
881 		yyerror(errbuf);
882 		return (0);
883 	}
884 	oldtype = dp->d_type;
885 	dcp = dp->d_conn;
886 	/*
887 	 * Now see if there is already a wildcard entry for this device
888 	 * (e.g. Search for a "uba ?")
889 	 */
890 	for (; dp != 0; dp = dp->d_next)
891 		if (eq(dev, dp->d_name) && dp->d_unit == -1)
892 			break;
893 	/*
894 	 * If there isn't, make one because everything needs to be connected
895 	 * to something.
896 	 */
897 	if (dp == 0) {
898 		dp = &rdev;
899 		init_dev(dp);
900 		dp->d_unit = QUES;
901 		dp->d_name = ns(dev);
902 		dp->d_type = oldtype;
903 		newdev(dp);
904 		dp = curp;
905 		/*
906 		 * Connect it to the same thing that other similar things are
907 		 * connected to, but make sure it is a wildcard unit
908 		 * (e.g. up connected to sc ?, here we make connect sc? to a
909 		 * uba?).  If other things like this are on the NEXUS or
910 		 * if they aren't connected to anything, then make the same
911 		 * connection, else call ourself to connect to another
912 		 * unspecific device.
913 		 */
914 		if (dcp == TO_NEXUS || dcp == 0)
915 			dp->d_conn = dcp;
916 		else
917 			dp->d_conn = connect(dcp->d_name, QUES);
918 	}
919 	return (dp);
920 }
921 
922 void
923 init_dev(dp)
924 	register struct device *dp;
925 {
926 
927 	dp->d_name = "OHNO!!!";
928 	dp->d_type = DEVICE;
929 	dp->d_conn = 0;
930 	dp->d_conflicts = 0;
931 	dp->d_disabled = 0;
932 	dp->d_vec = 0;
933 	dp->d_addr = dp->d_flags = dp->d_dk = 0;
934 	dp->d_pri = -1;
935 	dp->d_slave = dp->d_lun = dp->d_target = dp->d_drive = dp->d_unit = UNKNOWN;
936 	dp->d_port = (char *)0;
937 	dp->d_portn = -1;
938 	dp->d_irq = -1;
939 	dp->d_drq = -1;
940 	dp->d_maddr = 0;
941 	dp->d_msize = 0;
942 	dp->d_mask = "null";
943 }
944 
945 /*
946  * make certain that this is a reasonable type of thing to connect to a nexus
947  */
948 void
949 check_nexus(dev, num)
950 	register struct device *dev;
951 	int num;
952 {
953 
954 	switch (machine) {
955 
956 	case MACHINE_VAX:
957 		if (!eq(dev->d_name, "uba") && !eq(dev->d_name, "mba") &&
958 		    !eq(dev->d_name, "bi"))
959 			yyerror("only uba's, mba's, and bi's should be connected to the nexus");
960 		if (num != QUES)
961 			yyerror("can't give specific nexus numbers");
962 		break;
963 
964 	case MACHINE_TAHOE:
965 		if (!eq(dev->d_name, "vba"))
966 			yyerror("only vba's should be connected to the nexus");
967 		break;
968 
969 	case MACHINE_HP300:
970 	case MACHINE_LUNA68K:
971 		if (num != QUES)
972 			dev->d_addr = num;
973 		break;
974 
975 	case MACHINE_I386:
976 	case MACHINE_PC98:
977 		if (!eq(dev->d_name, "isa"))
978 			yyerror("only isa's should be connected to the nexus");
979 		break;
980 
981 	case MACHINE_NEWS3400:
982 		if (!eq(dev->d_name, "iop") && !eq(dev->d_name, "hb") &&
983 		    !eq(dev->d_name, "vme"))
984 			yyerror("only iop's, hb's and vme's should be connected to the nexus");
985 		break;
986 	}
987 }
988 
989 /*
990  * Check system specification and apply defaulting
991  * rules on root, argument, dump, and swap devices.
992  */
993 void
994 checksystemspec(fl)
995 	register struct file_list *fl;
996 {
997 	char buf[BUFSIZ];
998 	register struct file_list *swap;
999 	int generic;
1000 
1001 	if (fl == 0 || fl->f_type != SYSTEMSPEC) {
1002 		yyerror("internal error, bad system specification");
1003 		exit(1);
1004 	}
1005 	swap = fl->f_next;
1006 	generic = swap && swap->f_type == SWAPSPEC && eq(swap->f_fn, "generic");
1007 	if (fl->f_rootdev == NODEV && !generic) {
1008 		yyerror("no root device specified");
1009 		exit(1);
1010 	}
1011 	/*
1012 	 * Default swap area to be in 'b' partition of root's
1013 	 * device.  If root specified to be other than on 'a'
1014 	 * partition, give warning, something probably amiss.
1015 	 */
1016 	if (swap == 0 || swap->f_type != SWAPSPEC) {
1017 		dev_t dev;
1018 
1019 		swap = newflist(SWAPSPEC);
1020 		dev = fl->f_rootdev;
1021 		if (dkpart(dev) != 0) {
1022 			(void) sprintf(buf,
1023 "Warning, swap defaulted to 'b' partition with root on '%c' partition",
1024 				dkpart(dev) + 'a');
1025 			yyerror(buf);
1026 		}
1027 		swap->f_swapdev = dkmodpart(dev, SWAP_PART);
1028 		swap->f_fn = devtoname(swap->f_swapdev);
1029 		mkswap(fl, swap, 0);
1030 	}
1031 	/*
1032 	 * Make sure a generic swap isn't specified, along with
1033 	 * other stuff (user must really be confused).
1034 	 */
1035 	if (generic) {
1036 		if (fl->f_rootdev != NODEV)
1037 			yyerror("root device specified with generic swap");
1038 		if (fl->f_dumpdev != NODEV)
1039 			yyerror("dump device specified with generic swap");
1040 		return;
1041 	}
1042 	/*
1043 	 * Warn if dump device is not a swap area.
1044 	 */
1045 	if (fl->f_dumpdev != NODEV && fl->f_dumpdev != swap->f_swapdev) {
1046 		struct file_list *p = swap->f_next;
1047 
1048 		for (; p && p->f_type == SWAPSPEC; p = p->f_next)
1049 			if (fl->f_dumpdev == p->f_swapdev)
1050 				return;
1051 		(void) sprintf(buf,
1052 		    "Warning: dump device is not a swap partition");
1053 		yyerror(buf);
1054 	}
1055 }
1056 
1057 /*
1058  * Verify all devices specified in the system specification
1059  * are present in the device specifications.
1060  */
1061 void
1062 verifysystemspecs()
1063 {
1064 	register struct file_list *fl;
1065 	dev_t checked[50], *verifyswap();
1066 	register dev_t *pchecked = checked;
1067 
1068 	for (fl = conf_list; fl; fl = fl->f_next) {
1069 		if (fl->f_type != SYSTEMSPEC)
1070 			continue;
1071 		if (!finddev(fl->f_rootdev))
1072 			deverror(fl->f_needs, "root");
1073 		*pchecked++ = fl->f_rootdev;
1074 		pchecked = verifyswap(fl->f_next, checked, pchecked);
1075 		if (!alreadychecked(fl->f_dumpdev, checked, pchecked)) {
1076 			if (!finddev(fl->f_dumpdev))
1077 				deverror(fl->f_needs, "dump");
1078 			*pchecked++ = fl->f_dumpdev;
1079 		}
1080 	}
1081 }
1082 
1083 /*
1084  * Do as above, but for swap devices.
1085  */
1086 dev_t *
1087 verifyswap(fl, checked, pchecked)
1088 	register struct file_list *fl;
1089 	dev_t checked[];
1090 	register dev_t *pchecked;
1091 {
1092 
1093 	for (;fl && fl->f_type == SWAPSPEC; fl = fl->f_next) {
1094 		if (eq(fl->f_fn, "generic"))
1095 			continue;
1096 		if (alreadychecked(fl->f_swapdev, checked, pchecked))
1097 			continue;
1098 		if (!finddev(fl->f_swapdev))
1099 			warnx("swap device %s not configured", fl->f_fn);
1100 		*pchecked++ = fl->f_swapdev;
1101 	}
1102 	return (pchecked);
1103 }
1104 
1105 /*
1106  * Verify that components of a compound device have themselves been config'ed
1107  */
1108 void
1109 verifycomp(fl)
1110 	register struct file_list *fl;
1111 {
1112 	char *dname = fl->f_needs;
1113 
1114 	for (fl = fl->f_next; fl; fl = fl->f_next) {
1115 		if (fl->f_type != COMPSPEC || finddev(fl->f_compdev))
1116 			continue;
1117 		warnx("%s: component device %s not configured", dname, fl->f_needs);
1118 	}
1119 }
1120 
1121 /*
1122  * Has a device already been checked
1123  * for its existence in the configuration?
1124  */
1125 int
1126 alreadychecked(dev, list, last)
1127 	dev_t dev, list[];
1128 	register dev_t *last;
1129 {
1130 	register dev_t *p;
1131 
1132 	for (p = list; p < last; p++)
1133 		if (dkmodpart(*p, 0) != dkmodpart(dev, 0))
1134 			return (1);
1135 	return (0);
1136 }
1137 
1138 void
1139 deverror(systemname, devtype)
1140 	char *systemname, *devtype;
1141 {
1142 
1143 	warnx("%s: %s device not configured", systemname, devtype);
1144 }
1145 
1146 /*
1147  * Look for the device in the list of
1148  * configured hardware devices.  Must
1149  * take into account stuff wildcarded.
1150  */
1151 /*ARGSUSED*/
1152 int
1153 finddev(dev)
1154 	dev_t dev;
1155 {
1156 
1157 	/* punt on this right now */
1158 	return (1);
1159 }
1160