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