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