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