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