xref: /openbsd-src/sys/kern/subr_userconf.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
1 /*	$OpenBSD: subr_userconf.c,v 1.11 1996/11/21 12:47:16 mickey Exp $	*/
2 
3 /*
4  * Copyright (c) 1996 Mats O Jansson <moj@stacken.kth.se>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Mats O Jansson.
18  * 4. The name of the author may not be used to endorse or promote
19  *    products derived from this software without specific prior written
20  *    permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 
40 #include <dev/cons.h>
41 
42 extern char *locnames[];
43 extern short locnamp[];
44 extern short cfroots[];
45 extern int cfroots_size;
46 extern int pv_size;
47 extern short pv[];
48 
49 int userconf_base = 16;				/* Base for "large" numbers */
50 int userconf_maxdev = -1;			/* # of used device slots   */
51 int userconf_totdev = -1;			/* # of device slots        */
52 int userconf_maxlocnames = -1;			/* # of locnames            */
53 int userconf_cnt = -1;				/* Line counter for ...     */
54 int userconf_lines = 12;			/* ... # of lines per page  */
55 char userconf_argbuf[40];			/* Additional input         */
56 char userconf_cmdbuf[40];			/* Command line             */
57 
58 void userconf_init __P((void));
59 int userconf_more __P((void));
60 void userconf_modify __P((char *, int*));
61 void userconf_pnum __P((int));
62 void userconf_pdevnam __P((short));
63 void userconf_pdev __P((short));
64 int userconf_number __P((char *, int *));
65 int userconf_device __P((char *, int *, short *, short *));
66 void userconf_modify __P((char *, int *));
67 void userconf_change __P((int));
68 void userconf_disable __P((int));
69 void userconf_enable __P((int));
70 void userconf_help __P((void));
71 void userconf_list __P((void));
72 void userconf_show __P((void));
73 void userconf_show_attr_val __P((short, int *));
74 void userconf_show_attr __P((char *));
75 void userconf_common_dev __P((char *, int, short, short, char));
76 void userconf_add_read __P((char *, char, char *, int, int *));
77 void userconf_add __P((char *, int, short, short));
78 int userconf_parse __P((char *));
79 
80 #define UC_CHANGE 'c'
81 #define UC_DISABLE 'd'
82 #define UC_ENABLE 'e'
83 #define UC_FIND 'f'
84 
85 char *userconf_cmds[] = {
86 	"add",		"a",
87         "base",         "b",
88 	"change",	"c",
89 	"disable",	"d",
90 	"enable",	"e",
91 	"exit",		"q",
92 	"find",		"f",
93 	"help",		"h",
94 	"list",		"l",
95 	"lines",	"L",
96 	"quit",		"q",
97 	"show",		"s",
98 	"?",		"h",
99 	"",		 "",
100 };
101 
102 void
103 userconf_init()
104 {
105 	int i = 0;
106 	struct cfdata *cd;
107 	int   ln;
108 
109 	while(cfdata[i].cf_attach != 0) {
110 
111 		userconf_maxdev = i;
112 		userconf_totdev = i;
113 
114 		cd = &cfdata[i];
115 		ln=cd->cf_locnames;
116 		while (locnamp[ln] != -1) {
117 			if (locnamp[ln] > userconf_maxlocnames) {
118 				userconf_maxlocnames = locnamp[ln];
119 			};
120 			ln++;
121 		}
122 		i++;
123 	}
124 
125 	while(cfdata[i].cf_attach == 0) {
126 		userconf_totdev = i;
127 		i++;
128 	}
129 
130 	userconf_totdev = userconf_totdev - 1;
131 }
132 
133 int
134 userconf_more()
135 {
136 	int quit = 0;
137 	char c;
138 
139 	if (userconf_cnt != -1) {
140 		if (userconf_cnt == userconf_lines) {
141 			printf("--- more ---");
142 			c = cngetc();
143 			userconf_cnt = 0;
144 			printf("\r            \r");
145 		}
146 		userconf_cnt++;
147 		if (c == 'q' || c == 'Q') quit = 1;
148 	}
149 	return(quit);
150 }
151 
152 void
153 userconf_pnum(val)
154 	int val;
155 {
156 	if (val > -2 && val < 16) {
157 		printf("%d",val);
158 	} else {
159 		switch(userconf_base) {
160 		case 8:
161 			printf("0%o",val);
162 			break;
163 		case 10:
164 			printf("%d",val);
165 			break;
166 		case 16:
167 		default:
168 			printf("0x%x",val);
169 			break;
170 		}
171 	}
172 }
173 
174 void
175 userconf_pdevnam(dev)
176 	short dev;
177 {
178 	struct cfdata *cd;
179 
180 	cd = &cfdata[dev];
181 	printf(cd->cf_driver->cd_name);
182 	switch(cd->cf_fstate) {
183 	case FSTATE_NOTFOUND:
184 	case FSTATE_DNOTFOUND:
185 		printf("%d",cd->cf_unit);
186 		break;
187 	case FSTATE_FOUND:
188 	  	printf("*FOUND*");
189 		break;
190 	case FSTATE_STAR:
191 	case FSTATE_DSTAR:
192 		printf("*");
193 		break;
194 	default:
195 		printf("*UNKNOWN*");
196 		break;
197 	}
198 }
199 
200 void
201 userconf_pdev(devno)
202 	short devno;
203 {
204 	struct cfdata *cd;
205 	short *p;
206 	int   *l;
207 	int   ln;
208 	char c;
209 
210 	if (devno >  userconf_maxdev) {
211 		printf("Unknown devno (max is %d)\n",userconf_maxdev);
212 		return;
213 	}
214 
215 	cd = &cfdata[devno];
216 
217 	printf("%3d ",devno);
218 /*
219 	printf("%3d",devno);
220 	switch(cd->cf_fstate) {
221 	case FSTATE_NOTFOUND:
222         case FSTATE_FOUND:
223         case FSTATE_STAR:
224 		printf(" E ");
225 		break;
226 	case FSTATE_DNOTFOUND:
227         case FSTATE_DSTAR:
228 		printf(" D ");
229 		break;
230         default:
231 		printf(" ? ");
232 		break;
233 	}
234 */
235 	userconf_pdevnam(devno);
236 	printf(" at");
237 	c=' ';
238 	p=cd->cf_parents;
239 	if (*p == -1) printf(" root");
240 	while (*p != -1) {
241 		printf("%c",c);
242 		userconf_pdevnam(*p++);
243 		c='|';
244 	};
245 	switch(cd->cf_fstate) {
246 	case FSTATE_NOTFOUND:
247         case FSTATE_FOUND:
248         case FSTATE_STAR:
249 		break;
250 	case FSTATE_DNOTFOUND:
251         case FSTATE_DSTAR:
252 		printf(" disable");
253 		break;
254         default:
255 		printf(" ???");
256 		break;
257 	}
258 	l=cd->cf_loc;
259 	ln=cd->cf_locnames;
260 	while (locnamp[ln] != -1) {
261 		printf(" %s ",locnames[locnamp[ln]]);
262 		ln++;
263 		userconf_pnum(*l++);
264 	}
265 	printf("\n");
266 
267 }
268 
269 int
270 userconf_number(c, val)
271 	char *c;
272 	int *val;
273 {
274 	u_int num = 0;
275 	int neg = 0;
276 	int base = 10;
277 
278 	if (*c == '-') {
279 		neg = 1;
280 		c++;
281 	}
282 	if (*c == '0') {
283 		base = 8;
284 		c++;
285 		if (*c == 'x' || *c == 'X') {
286 			base = 16;
287 			c++;
288 		}
289 	}
290 	while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\000') {
291 		u_char cc = *c;
292 
293 		if (cc >= '0' && cc <= '9')
294 			cc = cc - '0';
295 		else if (cc >= 'a' && cc <= 'f')
296 			cc = cc - 'a' + 10;
297 		else if (cc >= 'A' && cc <= 'F')
298 			cc = cc - 'A' + 10;
299 		else
300 			return (-1);
301 
302 		if (cc > base)
303 			return (-1);
304 		num = num * base + cc;
305 		c++;
306 	}
307 
308 	if (neg && num > INT_MAX)       /* overflow */
309 		return (1);
310 
311 	*val = neg ? - num : num;
312 
313 	return(0);
314 }
315 
316 int
317 userconf_device(cmd, len, unit, state)
318 	char *cmd;
319 	int *len;
320 	short *unit, *state;
321 {
322 	short u = 0, s = FSTATE_FOUND;
323 	int l = 0;
324 	char *c;
325 
326 	c = cmd;
327 	while(*c >= 'a' && *c <= 'z') { l++; c++; };
328 	if (*c == '*') {
329 		s = FSTATE_STAR;
330 		c++;
331 	} else {
332 		while(*c >= '0' && *c <= '9') {
333 			s = FSTATE_NOTFOUND;
334 			u=u*10 + *c - '0';
335 			c++;
336 		};
337 	}
338 	while(*c == ' ' || *c == '\t' || *c == '\n') c++;
339 
340 	if (*c == '\000') {
341 		*len = l;
342 		*unit = u;
343 		*state = s;
344 		return(0);
345 	}
346 
347 	return(-1);
348 }
349 
350 void
351 userconf_modify(item, val)
352 	char *item;
353 	int  *val;
354 {
355 	int ok = 0;
356 	int a;
357 	char *c;
358 	int i;
359 
360 	while(!ok) {
361 		printf("%s [",item);
362 		userconf_pnum(*val);
363 		printf("] ? ");
364 
365 		i = getsn(userconf_argbuf,sizeof(userconf_argbuf));
366 
367 		c = userconf_argbuf;
368 		while (*c == ' ' || *c == '\t' || *c == '\n') c++;
369 
370 		if (*c != '\000') {
371 			if (userconf_number(c,&a) == 0) {
372 				*val = a;
373 				ok = 1;
374 			} else {
375 				printf("Unknown argument\n");
376 			}
377 		} else {
378 			ok = 1;
379 		}
380 	}
381 }
382 
383 void
384 userconf_change(devno)
385 	int devno;
386 {
387 	struct cfdata *cd;
388 	char c = '\000';
389 	int   *l;
390 	int   ln;
391 
392 	if (devno <=  userconf_maxdev) {
393 
394 		userconf_pdev(devno);
395 
396 		while(c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
397 			printf("change (y/n) ?");
398 			c = cngetc();
399 			printf("\n");
400 		}
401 
402 		if (c == 'y' || c == 'Y') {
403 			int share = 0, i, *lk;
404 
405 			cd = &cfdata[devno];
406 			l=cd->cf_loc;
407 			ln=cd->cf_locnames;
408 
409 			/*
410 			 * Search for some other driver sharing this
411 			 * locator table. if one does, we may need to
412 			 * replace the locators with a malloc'd copy.
413 			 */
414 			for (i = 0; cfdata[i].cf_driver; i++)
415 				if (i != devno && cfdata[i].cf_loc == l)
416 					share = 1;
417 			if (share) {
418 				for (i = 0; locnamp[ln+i] != -1 ; i++)
419 					;
420 				lk = l = (int *)malloc(sizeof(int) * i,
421 				    M_TEMP, M_NOWAIT);
422 				bcopy(cd->cf_loc, l, sizeof(int) * i);
423 			}
424 
425 			while (locnamp[ln] != -1) {
426 				userconf_modify(locnames[locnamp[ln]],
427 						l);
428 				ln++;
429 				l++;
430 			}
431 
432 			if (share) {
433 				if (bcmp(cd->cf_loc, lk, sizeof(int) * i))
434 					cd->cf_loc = lk;
435 				else
436 					free(lk, M_TEMP);
437 			}
438 
439 			printf("%3d ",devno);
440 			userconf_pdevnam(devno);
441 			printf(" changed\n");
442 			userconf_pdev(devno);
443 
444 		}
445 
446 	} else {
447 		printf("Unknown devno (max is %d)\n",userconf_maxdev);
448 	}
449 
450 }
451 
452 void
453 userconf_disable(devno)
454 	int devno;
455 {
456 	int done = 0;
457 
458 	if (devno <= userconf_maxdev) {
459 
460 		switch(cfdata[devno].cf_fstate) {
461 		case FSTATE_NOTFOUND:
462 			cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
463 			break;
464 		case FSTATE_STAR:
465 			cfdata[devno].cf_fstate = FSTATE_DSTAR;
466 			break;
467 		case FSTATE_DNOTFOUND:
468 		case FSTATE_DSTAR:
469 			done = 1;
470 			break;
471 		default:
472 			printf("Error unknown state\n");
473 			break;
474 		}
475 
476 		printf("%3d ",devno);
477 		userconf_pdevnam(devno);
478 		if (done) printf(" already");
479 		printf(" disabled\n");
480 
481 	} else {
482 		printf("Unknown devno (max is %d)\n",userconf_maxdev);
483 	}
484 
485 }
486 
487 void
488 userconf_enable(devno)
489 	int devno;
490 {
491 	int done = 0;
492 
493 	if (devno <= userconf_maxdev) {
494 
495 		switch(cfdata[devno].cf_fstate) {
496 		case FSTATE_DNOTFOUND:
497 			cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
498 			break;
499 		case FSTATE_DSTAR:
500 			cfdata[devno].cf_fstate = FSTATE_STAR;
501 			break;
502 		case FSTATE_NOTFOUND:
503 		case FSTATE_STAR:
504 			done = 1;
505 			break;
506 		default:
507 			printf("Error unknown state\n");
508 			break;
509 		}
510 
511 		printf("%3d ",devno);
512 		userconf_pdevnam(devno);
513 		if (done) printf(" already");
514 		printf(" enabled\n");
515 
516 	} else {
517 		printf("Unknown devno (max is %d)\n",userconf_maxdev);
518 	}
519 
520 }
521 
522 void
523 userconf_help()
524 {
525 	int j = 0,k;
526 
527 	printf("command   args          description\n");
528 	while(*userconf_cmds[j] != '\000') {
529 		printf(userconf_cmds[j]);
530 		k=strlen(userconf_cmds[j]);
531 		while (k < 10) { printf(" "); k++; }
532 		switch(*userconf_cmds[j+1]) {
533 		case 'L':
534 			printf("[count]       number of lines before more");
535 			break;
536 		case 'a':
537 			printf("dev           add a device");
538 			break;
539 		case 'b':
540 			printf("8|10|16       base on large numbers");
541 			break;
542 		case 'c':
543 			printf("devno|dev     %s devices","change");
544 			break;
545 		case 'd':
546 			printf("devno|dev     %s devices","disable");
547 			break;
548 		case 'e':
549 			printf("devno|dev     %s devices","enable");
550 			break;
551 		case 'f':
552 			printf("devno|dev     %s devices","find");
553 			break;
554 		case 'h':
555 			printf("              %s","this message");
556 			break;
557 		case 'l':
558 			printf("              %s","list configuration");
559 			break;
560 		case 'q':
561 			printf("              %s","leave UKC");
562 			break;
563 		case 's':
564 			printf("[attr [val]]  %s",
565 			   "show attributes (or devices with an attribute)");
566 			break;
567 		default:
568 			printf("              %s","don't know");
569 			break;
570 		}
571 		printf("\n");
572 		j++; j++;
573 	}
574 
575 }
576 
577 void
578 userconf_list()
579 {
580 	int i = 0;
581 
582 	userconf_cnt = 0;
583 
584 	while(cfdata[i].cf_attach != 0) {
585 		if (userconf_more()) break;
586 		userconf_pdev(i++);
587 	};
588 
589 	userconf_cnt = -1;
590 }
591 
592 void
593 userconf_show()
594 {
595 	int i = 0;
596 
597 	userconf_cnt = 0;
598 
599 	while(i <= userconf_maxlocnames) {
600 		if (userconf_more()) break;
601 		printf("%s\n",locnames[i++]);
602 	}
603 
604 	userconf_cnt = -1;
605 }
606 
607 void
608 userconf_show_attr_val(attr, val)
609 	short attr;
610 	int   *val;
611 {
612 	struct cfdata *cd;
613 	int   *l;
614 	int   ln;
615 	int i = 0, quit = 0;
616 
617 	userconf_cnt = 0;
618 
619 	while(i <= userconf_maxdev) {
620 		cd = &cfdata[i];
621 		l=cd->cf_loc;
622 		ln=cd->cf_locnames;
623 		while (locnamp[ln] != -1) {
624 			if (locnamp[ln] == attr) {
625 				if (val == NULL) {
626 					quit = userconf_more();
627 					userconf_pdev(i);
628 				} else {
629 					if (*val == *l) {
630 						quit = userconf_more();
631 						userconf_pdev(i);
632 					}
633 				}
634 			}
635 			if (quit) break;
636 			ln++;
637 			l++;
638 		}
639 		if (quit) break;
640 		i++;
641 	}
642 
643 	userconf_cnt = -1;
644 }
645 
646 void
647 userconf_show_attr(cmd)
648 	char *cmd;
649 {
650 	char *c;
651 	short attr = -1, i = 0, l = 0;
652 	int a;
653 
654 	c = cmd;
655 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\000') {
656 		c++; l++;
657 	}
658 	while (*c == ' ' || *c == '\t' || *c == '\n') {
659 		c++;
660 	}
661 
662 	while(i <= userconf_maxlocnames) {
663 		if (strlen(locnames[i]) == l) {
664 			if (strncasecmp(cmd,locnames[i],l) == 0) {
665 				attr = i;
666 			}
667 		}
668 		i++;
669 	}
670 
671 	if (attr == -1) {
672 		printf("Unknown attribute\n");
673 		return;
674 	}
675 
676 	if (*c == '\000') {
677 		userconf_show_attr_val(attr,NULL);
678 	} else {
679 		if (userconf_number(c,&a) == 0) {
680 			userconf_show_attr_val(attr,&a);
681 		} else {
682 			printf("Unknown argument\n");
683 		}
684 	}
685 }
686 
687 void
688 userconf_common_dev(dev, len, unit, state, routine)
689 	char *dev;
690 	int len;
691 	short unit, state;
692 	char routine;
693 {
694 	int i = 0;
695 
696 	switch(routine) {
697 	case UC_CHANGE:
698 		break;
699 	default:
700 		userconf_cnt = 0;
701 		break;
702 	}
703 
704 	while(cfdata[i].cf_attach != 0) {
705 
706 		if (strlen(cfdata[i].cf_driver->cd_name) == len) {
707 
708 			/*
709 			 * Ok, if device name is correct
710 			 *  If state == FSTATE_FOUND, look for "dev"
711 			 *  If state == FSTATE_STAR, look for "dev*"
712 			 *  If state == FSTATE_NOTFOUND, look for "dev0"
713 			 */
714 			if (strncasecmp(dev,cfdata[i].cf_driver->cd_name,
715 					len) == 0 &&
716 			    (state == FSTATE_FOUND ||
717 			     (state == FSTATE_STAR &&
718 			      (cfdata[i].cf_fstate == FSTATE_STAR ||
719 			       cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
720 			     (state == FSTATE_NOTFOUND &&
721 			      cfdata[i].cf_unit == unit &&
722 			      (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
723 			       cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
724 			  	if (userconf_more()) break;
725 				switch(routine) {
726 				case UC_CHANGE:
727 					userconf_change(i);
728 					break;
729 				case UC_ENABLE:
730 					userconf_enable(i);
731 					break;
732 				case UC_DISABLE:
733 					userconf_disable(i);
734 					break;
735 				case UC_FIND:
736 					userconf_pdev(i);
737 					break;
738 				default:
739 					printf("Unknown routine /%c/\n",
740 					       routine);
741 					break;
742 				}
743 			}
744 		}
745 		i++;
746 
747 	};
748 
749 	switch(routine) {
750 	case UC_CHANGE:
751 		break;
752 	default:
753 		userconf_cnt = -1;
754 		break;
755 	}
756 
757 }
758 
759 void
760 userconf_add_read(prompt,field,dev,len,val)
761 	char *prompt;
762 	char field;
763 	char *dev;
764 	int len;
765 	int *val;
766 {
767 	int ok = 0;
768 	int a;
769 	char *c;
770 	int i;
771 
772 	*val = -1;
773 
774 	while(!ok) {
775 		printf("%s ? ",prompt);
776 
777 		i = getsn(userconf_argbuf,sizeof(userconf_argbuf));
778 
779 		c = userconf_argbuf;
780 		while (*c == ' ' || *c == '\t' || *c == '\n') c++;
781 
782 		if (*c != '\000') {
783 			if (userconf_number(c,&a) == 0) {
784 				if (a >  userconf_maxdev) {
785 					printf("Unknown devno (max is %d)\n",
786 					       userconf_maxdev);
787 				} else if (strncasecmp(dev,
788 					   cfdata[a].cf_driver->cd_name,
789 					   len) != 0) {
790 					printf("Not same device type\n");
791 				} else {
792 					*val = a;
793 					ok = 1;
794 				}
795 			} else if (*c == '?') {
796 				userconf_common_dev(dev,len,0,
797 						    FSTATE_FOUND,UC_FIND);
798 			} else if (*c == 'q' || *c == 'Q') {
799 				ok = 1;
800 			} else {
801 				printf("Unknown argument\n");
802 			}
803 		} else {
804 			ok = 1;
805 		}
806 	}
807 }
808 
809 void
810 userconf_add(dev,len,unit,state)
811 	char *dev;
812 	int len;
813 	short unit, state;
814 {
815 	int i = 0, found = 0;
816 	struct cfdata new;
817 	int  val, max_unit;
818 
819 	bzero(&new, sizeof(struct cfdata));
820 
821 	if (userconf_maxdev == userconf_totdev) {
822 		printf("No more space for new devices.\n");
823 		return;
824 	}
825 
826 	if (state == FSTATE_FOUND) {
827 		printf("Device not complete number or * is missing/n");
828 		return;
829 	}
830 
831 	for (i = 0; cfdata[i].cf_driver; i++)
832 		if (strlen(cfdata[i].cf_driver->cd_name) == len &&
833 		    strncasecmp(dev,cfdata[i].cf_driver->cd_name,len) == 0)
834 			found = 1;
835 
836 	if (!found) {
837 		printf("No device of this type exists.\n");
838 		return;
839 	}
840 
841 	userconf_add_read("Clone Device (DevNo, 'q' or '?')",
842 			  'a',dev,len,&val);
843 
844 	if (val != -1) {
845 
846 		new = cfdata[val];
847 		new.cf_unit = unit;
848 		new.cf_fstate = state;
849 
850 		userconf_add_read("Insert before Device (DevNo, 'q' or '?')",
851 				  'i',dev,len,&val);
852 
853 	}
854 
855 	if (val != -1) {
856 
857 		/* Insert the new record */
858 
859 		for (i = userconf_maxdev; val <= i; i--) {
860 			cfdata[i+1] = cfdata[i];
861 		}
862 		cfdata[val] = new;
863 
864 		/* Fix indexs in pv */
865 
866 		for (i = 0; i < pv_size; i++) {
867 			if ((pv[i] != -1) && (pv[i] >= val)) {
868 				pv[i] = pv[i]++;
869 			}
870 		}
871 
872 		/* Fix indexs in cfroots */
873 
874 		for (i = 0; i < cfroots_size; i++) {
875 			if ((cfroots[i] != -1) && (cfroots[i] >= val)) {
876 				cfroots[i] = cfroots[i]++;
877 			}
878 		}
879 
880 		userconf_maxdev++;
881 
882 		max_unit = -1;
883 
884 		/* Find max unit number of the device type */
885 
886 		i = 0;
887 		while(cfdata[i].cf_attach != 0) {
888 			if (strlen(cfdata[i].cf_driver->cd_name) == len &&
889 			    strncasecmp(dev,
890 					cfdata[i].cf_driver->cd_name,
891 					len) == 0) {
892 				switch (cfdata[i].cf_fstate) {
893 				case FSTATE_NOTFOUND:
894 				case FSTATE_DNOTFOUND:
895 					if (cfdata[i].cf_unit > max_unit)
896 						max_unit = cfdata[i].cf_unit;
897 					break;
898 				default:
899 					break;
900 				}
901 			}
902 			i++;
903 		}
904 
905 		/* For all * entries set unit number to max+1 */
906 
907 		max_unit++;
908 
909 		i = 0;
910 		while(cfdata[i].cf_attach != 0) {
911 			if (strlen(cfdata[i].cf_driver->cd_name) == len &&
912 			    strncasecmp(dev,
913 					cfdata[i].cf_driver->cd_name,
914 					len) == 0) {
915 				switch (cfdata[i].cf_fstate) {
916 				case FSTATE_STAR:
917 				case FSTATE_DSTAR:
918 					cfdata[i].cf_unit = max_unit;
919 					break;
920 				default:
921 					break;
922 				}
923 			}
924 			i++;
925 		}
926 
927 		userconf_pdev(val);
928 
929 	}
930 
931 	/* cf_attach, cf_driver, cf_unit, cf_state, cf_loc, cf_flags,
932 	   cf_parents, cf_locnames, cf_locnames and cf_ivstubs */
933 
934 }
935 
936 int
937 userconf_parse(cmd)
938 	char *cmd;
939 {
940 	char *c, *v;
941 	int i = 0, j = 0, k, a;
942 	short unit, state;
943 
944 	c = cmd;
945 	while (*c == ' ' || *c == '\t') c++;
946 	v = c;
947 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\000') {
948 	  c++; i++;
949 	}
950 
951 	k = -1;
952 	while(*userconf_cmds[j] != '\000') {
953 		if (strlen(userconf_cmds[j]) == i) {
954 			if (strncasecmp(v,userconf_cmds[j],i) == 0) {
955 				k = j;
956 			}
957 		}
958 		j++; j++;
959 	}
960 
961 	while (*c == ' ' || *c == '\t' || *c == '\n') {
962 		c++;
963 	}
964 
965 	if (k == -1) {
966 		if (*v != '\n') {
967 			printf("Unknown command, try help\n");
968 		};
969 	} else {
970 		switch(*userconf_cmds[k+1]) {
971 		case 'L':
972 			if (*c == '\000') {
973 				printf("Argument expected\n");
974 			} else if (userconf_number(c,&a) == 0) {
975 				userconf_lines = a;
976 			} else {
977 				printf("Unknown argument\n");
978 			}
979 			break;
980 		case 'a':
981 			if (*c == '\000') {
982 				printf("Dev expected\n");
983 			} else if (userconf_device(c,&a,&unit,&state) == 0) {
984 				userconf_add(c,a,unit,state);
985 			} else {
986 				printf("Unknown argument\n");
987 			}
988 			break;
989 		case 'b':
990 			if (*c == '\000') {
991 				printf("8|10|16 expected\n");
992 			} else if (userconf_number(c,&a) == 0) {
993 				if (a == 8 || a == 10 || a == 16) {
994 					userconf_base = a;
995 				} else {
996 					printf("8|10|16 expected\n");
997 				}
998 			} else {
999 				printf("Unknown argument\n");
1000 			}
1001 			break;
1002 		case 'c':
1003 			if (*c == '\000') {
1004 				printf("DevNo or Dev expected\n");
1005 			} else if (userconf_number(c,&a) == 0) {
1006 				userconf_change(a);
1007 			} else if (userconf_device(c,&a,&unit,&state) == 0) {
1008 				userconf_common_dev(c,a,unit,state,UC_CHANGE);
1009 			} else {
1010 				printf("Unknown argument\n");
1011 			}
1012 			break;
1013 		case 'd':
1014 			if (*c == '\000') {
1015 				printf("DevNo or Dev expected\n");
1016 			} else if (userconf_number(c,&a) == 0) {
1017 				userconf_disable(a);
1018 			} else if (userconf_device(c,&a,&unit,&state) == 0) {
1019 				userconf_common_dev(c,a,unit,state,UC_DISABLE);
1020 			} else {
1021 				printf("Unknown argument\n");
1022 			}
1023 			break;
1024 		case 'e':
1025 			if (*c == '\000') {
1026 				printf("DevNo or Dev expected\n");
1027 			} else if (userconf_number(c,&a) == 0) {
1028 				userconf_enable(a);
1029 			} else if (userconf_device(c,&a,&unit,&state) == 0) {
1030 				userconf_common_dev(c,a,unit,state,UC_ENABLE);
1031 			} else {
1032 				printf("Unknown argument\n");
1033 			}
1034 			break;
1035 		case 'f':
1036 			if (*c == '\000') {
1037 				printf("DevNo or Dev expected\n");
1038 			} else if (userconf_number(c,&a) == 0) {
1039 				userconf_pdev(a);
1040 			} else if (userconf_device(c,&a,&unit,&state) == 0) {
1041 				userconf_common_dev(c,a,unit,state,UC_FIND);
1042 			} else {
1043 				printf("Unknown argument\n");
1044 			}
1045 			break;
1046 		case 'h':
1047 			userconf_help();
1048 			break;
1049 		case 'l':
1050 			if (*c == '\000') {
1051 				userconf_list();
1052 			} else {
1053 				printf("Unknown argument\n");
1054 			}
1055 			break;
1056 		case 'q':
1057 			return(-1);
1058 			break;
1059 		case 's':
1060 			if (*c == '\000') {
1061 				userconf_show();
1062 			} else {
1063 				userconf_show_attr(c);
1064 			}
1065 			break;
1066 		default:
1067 			printf("Unknown command\n");
1068 			break;
1069 		}
1070 	}
1071 	return(0);
1072 }
1073 
1074 void
1075 user_config()
1076 {
1077 	char prompt[] = "UKC> ";
1078 
1079 	userconf_init();
1080 	printf("User Kernel Config\n");
1081 
1082 	while (1) {
1083 		printf(prompt);
1084 		if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
1085 		    userconf_parse(userconf_cmdbuf))
1086 			break;
1087 	}
1088 	printf("Continuing...\n");
1089 }
1090