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