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