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