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