xref: /openbsd-src/sys/kern/subr_userconf.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: subr_userconf.c,v 1.33 2003/06/02 21:14:47 maja Exp $	*/
2 
3 /*
4  * Copyright (c) 1996-2001 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/malloc.h>
33 #include <sys/time.h>
34 
35 #include <dev/cons.h>
36 
37 extern char *locnames[];
38 extern short locnamp[];
39 extern short cfroots[];
40 extern int cfroots_size;
41 extern int pv_size;
42 extern short pv[];
43 extern struct timezone tz;
44 extern char *pdevnames[];
45 extern int pdevnames_size;
46 extern struct pdevinit pdevinit[];
47 
48 int userconf_base = 16;				/* Base for "large" numbers */
49 int userconf_maxdev = -1;			/* # of used device slots   */
50 int userconf_totdev = -1;			/* # of device slots        */
51 int userconf_maxlocnames = -1;			/* # of locnames            */
52 int userconf_cnt = -1;				/* Line counter for ...     */
53 int userconf_lines = 12;			/* ... # of lines per page  */
54 int userconf_histlen = 0;
55 int userconf_histcur = 0;
56 char userconf_history[1024];
57 int userconf_histsz = sizeof(userconf_history);
58 char userconf_argbuf[40];			/* Additional input         */
59 char userconf_cmdbuf[40];			/* Command line             */
60 char userconf_histbuf[40];
61 
62 void userconf_init(void);
63 int userconf_more(void);
64 void userconf_modify(char *, int *);
65 void userconf_hist_cmd(char);
66 void userconf_hist_int(int);
67 void userconf_hist_eoc(void);
68 void userconf_pnum(int);
69 void userconf_pdevnam(short);
70 void userconf_pdev(short);
71 int userconf_number(char *, int *);
72 int userconf_device(char *, int *, short *, short *);
73 int userconf_attr(char *, int *);
74 void userconf_modify(char *, int *);
75 void userconf_change(int);
76 void userconf_disable(int);
77 void userconf_enable(int);
78 void userconf_help(void);
79 void userconf_list(void);
80 void userconf_show(void);
81 void userconf_common_attr_val(short, int *, char);
82 void userconf_show_attr(char *);
83 void userconf_common_dev(char *, int, short, short, char);
84 void userconf_common_attr(char *, int, char);
85 void userconf_add_read(char *, char, char *, int, int *);
86 void userconf_add(char *, int, short, short);
87 int userconf_parse(char *);
88 
89 #define UC_CHANGE 'c'
90 #define UC_DISABLE 'd'
91 #define UC_ENABLE 'e'
92 #define UC_FIND 'f'
93 #define UC_SHOW 's'
94 
95 char *userconf_cmds[] = {
96 	"add",		"a",
97 	"base",		"b",
98 	"change",	"c",
99 #if defined(DDB)
100 	"ddb",		"D",
101 #endif
102 	"disable",	"d",
103 	"enable",	"e",
104 	"exit",		"q",
105 	"find",		"f",
106 	"help",		"h",
107 	"list",		"l",
108 	"lines",	"L",
109 	"quit",		"q",
110 	"show",		"s",
111 	"timezone",	"t",
112 	"verbose",	"v",
113 	"?",		"h",
114 	"",		 "",
115 };
116 
117 void
118 userconf_init()
119 {
120 	int i = 0;
121 	struct cfdata *cd;
122 	int   ln;
123 
124 	while (cfdata[i].cf_attach != 0) {
125 		userconf_maxdev = i;
126 		userconf_totdev = i;
127 
128 		cd = &cfdata[i];
129 		ln = cd->cf_locnames;
130 		while (locnamp[ln] != -1) {
131 			if (locnamp[ln] > userconf_maxlocnames)
132 				userconf_maxlocnames = locnamp[ln];
133 			ln++;
134 		}
135 		i++;
136 	}
137 
138 	while (cfdata[i].cf_attach == 0) {
139 		userconf_totdev = i;
140 		i++;
141 	}
142 	userconf_totdev = userconf_totdev - 1;
143 }
144 
145 int
146 userconf_more()
147 {
148 	int quit = 0;
149 	char c = '\0';
150 
151 	if (userconf_cnt != -1) {
152 		if (userconf_cnt == userconf_lines) {
153 			printf("--- more ---");
154 			c = cngetc();
155 			userconf_cnt = 0;
156 			printf("\r            \r");
157 		}
158 		userconf_cnt++;
159 		if (c == 'q' || c == 'Q')
160 			quit = 1;
161 	}
162 	return (quit);
163 }
164 
165 void
166 userconf_hist_cmd(cmd)
167 	char cmd;
168 {
169 	userconf_histcur = userconf_histlen;
170 	if (userconf_histcur < userconf_histsz) {
171 		userconf_history[userconf_histcur] = cmd;
172 		userconf_histcur++;
173 	}
174 }
175 
176 void
177 userconf_hist_int(val)
178 	int val;
179 {
180 	snprintf(userconf_histbuf, sizeof userconf_histbuf, " %d",val);
181 	if (userconf_histcur + strlen(userconf_histbuf) < userconf_histsz) {
182 		bcopy(userconf_histbuf,
183 		    &userconf_history[userconf_histcur],
184 		    strlen(userconf_histbuf));
185 		userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
186 	}
187 }
188 
189 void
190 userconf_hist_eoc()
191 {
192 	if (userconf_histcur < userconf_histsz) {
193 		userconf_history[userconf_histcur] = '\n';
194 		userconf_histcur++;
195 		userconf_histlen = userconf_histcur;
196 	}
197 }
198 
199 void
200 userconf_pnum(val)
201 	int val;
202 {
203 	if (val > -2 && val < 16) {
204 		printf("%d",val);
205 		return;
206 	}
207 
208 	switch (userconf_base) {
209 	case 8:
210 		printf("0%o",val);
211 		break;
212 	case 10:
213 		printf("%d",val);
214 		break;
215 	case 16:
216 	default:
217 		printf("0x%x",val);
218 		break;
219 	}
220 }
221 
222 void
223 userconf_pdevnam(dev)
224 	short dev;
225 {
226 	struct cfdata *cd;
227 
228 	cd = &cfdata[dev];
229 	printf("%s", cd->cf_driver->cd_name);
230 	switch (cd->cf_fstate) {
231 	case FSTATE_NOTFOUND:
232 	case FSTATE_DNOTFOUND:
233 		printf("%d", cd->cf_unit);
234 		break;
235 	case FSTATE_FOUND:
236 		printf("*FOUND*");
237 		break;
238 	case FSTATE_STAR:
239 	case FSTATE_DSTAR:
240 		printf("*");
241 		break;
242 	default:
243 		printf("*UNKNOWN*");
244 		break;
245 	}
246 }
247 
248 void
249 userconf_pdev(devno)
250 	short devno;
251 {
252 	struct cfdata *cd;
253 	short *p;
254 	int   *l;
255 	int   ln;
256 	char c;
257 
258 	if (devno > userconf_maxdev && devno <= userconf_totdev) {
259 		printf("%3d free slot (for add)\n", devno);
260 		return;
261 	}
262 
263 	if (devno > userconf_totdev &&
264 	    devno <= userconf_totdev+pdevnames_size) {
265 		printf("%3d %s count %d (pseudo device)\n", devno,
266 		    pdevnames[devno-userconf_totdev-1],
267 		    pdevinit[devno-userconf_totdev-1].pdev_count);
268 		return;
269 	}
270 
271 	if (devno >  userconf_maxdev) {
272 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
273 		return;
274 	}
275 
276 	cd = &cfdata[devno];
277 
278 	printf("%3d ", devno);
279 	userconf_pdevnam(devno);
280 	printf(" at");
281 	c = ' ';
282 	p = cd->cf_parents;
283 	if (*p == -1)
284 		printf(" root");
285 	while (*p != -1) {
286 		printf("%c", c);
287 		userconf_pdevnam(*p++);
288 		c = '|';
289 	}
290 	switch (cd->cf_fstate) {
291 	case FSTATE_NOTFOUND:
292 	case FSTATE_FOUND:
293 	case FSTATE_STAR:
294 		break;
295 	case FSTATE_DNOTFOUND:
296 	case FSTATE_DSTAR:
297 		printf(" disable");
298 		break;
299 	default:
300 		printf(" ???");
301 		break;
302 	}
303 	l = cd->cf_loc;
304 	ln = cd->cf_locnames;
305 	while (locnamp[ln] != -1) {
306 		printf(" %s ", locnames[locnamp[ln]]);
307 		ln++;
308 		userconf_pnum(*l++);
309 	}
310 	printf(" flags 0x%x\n", cd->cf_flags);
311 }
312 
313 int
314 userconf_number(c, val)
315 	char *c;
316 	int *val;
317 {
318 	u_int num = 0;
319 	int neg = 0;
320 	int base = 10;
321 
322 	if (*c == '-') {
323 		neg = 1;
324 		c++;
325 	}
326 	if (*c == '0') {
327 		base = 8;
328 		c++;
329 		if (*c == 'x' || *c == 'X') {
330 			base = 16;
331 			c++;
332 		}
333 	}
334 	while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
335 		u_char cc = *c;
336 
337 		if (cc >= '0' && cc <= '9')
338 			cc = cc - '0';
339 		else if (cc >= 'a' && cc <= 'f')
340 			cc = cc - 'a' + 10;
341 		else if (cc >= 'A' && cc <= 'F')
342 			cc = cc - 'A' + 10;
343 		else
344 			return (-1);
345 
346 		if (cc > base)
347 			return (-1);
348 		num = num * base + cc;
349 		c++;
350 	}
351 
352 	if (neg && num > INT_MAX)	/* overflow */
353 		return (1);
354 	*val = neg ? - num : num;
355 	return (0);
356 }
357 
358 int
359 userconf_device(cmd, len, unit, state)
360 	char *cmd;
361 	int *len;
362 	short *unit, *state;
363 {
364 	short u = 0, s = FSTATE_FOUND;
365 	int l = 0;
366 	char *c;
367 
368 	c = cmd;
369 	while (*c >= 'a' && *c <= 'z') {
370 		l++;
371 		c++;
372 	}
373 	if (*c == '*') {
374 		s = FSTATE_STAR;
375 		c++;
376 	} else {
377 		while (*c >= '0' && *c <= '9') {
378 			s = FSTATE_NOTFOUND;
379 			u = u*10 + *c - '0';
380 			c++;
381 		}
382 	}
383 	while (*c == ' ' || *c == '\t' || *c == '\n')
384 		c++;
385 
386 	if (*c == '\0') {
387 		*len = l;
388 		*unit = u;
389 		*state = s;
390 		return(0);
391 	}
392 
393 	return(-1);
394 }
395 
396 int
397 userconf_attr(cmd, val)
398 	char *cmd;
399 	int *val;
400 {
401 	char *c;
402 	short attr = -1, i = 0, l = 0;
403 
404 	c = cmd;
405 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
406 		c++;
407 		l++;
408 	}
409 
410 	while (i <= userconf_maxlocnames) {
411 		if (strlen(locnames[i]) == l) {
412 			if (strncasecmp(cmd, locnames[i], l) == 0)
413 				attr = i;
414 		}
415 		i++;
416 	}
417 
418 	if (attr == -1) {
419 		return (-1);
420 	}
421 
422 	*val = attr;
423 
424 	return(0);
425 }
426 
427 void
428 userconf_modify(item, val)
429 	char *item;
430 	int  *val;
431 {
432 	int ok = 0;
433 	int a;
434 	char *c;
435 	int i;
436 
437 	while (!ok) {
438 		printf("%s [", item);
439 		userconf_pnum(*val);
440 		printf("] ? ");
441 
442 		i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
443 
444 		c = userconf_argbuf;
445 		while (*c == ' ' || *c == '\t' || *c == '\n') c++;
446 
447 		if (*c != '\0') {
448 			if (userconf_number(c, &a) == 0) {
449 				*val = a;
450 				ok = 1;
451 			} else {
452 				printf("Unknown argument\n");
453 			}
454 		} else {
455 			ok = 1;
456 		}
457 	}
458 }
459 
460 void
461 userconf_change(devno)
462 	int devno;
463 {
464 	struct cfdata *cd;
465 	char c = '\0';
466 	int   *l;
467 	int   ln;
468 
469 	if (devno <=  userconf_maxdev) {
470 		userconf_pdev(devno);
471 
472 		while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
473 			printf("change (y/n) ?");
474 			c = cngetc();
475 			printf("\n");
476 		}
477 
478 		if (c == 'y' || c == 'Y') {
479 			int share = 0, i, *lk;
480 
481 			/* XXX add cmd 'c' <devno> */
482 			userconf_hist_cmd('c');
483 			userconf_hist_int(devno);
484 
485 			cd = &cfdata[devno];
486 			l = cd->cf_loc;
487 			ln = cd->cf_locnames;
488 
489 			/*
490 			 * Search for some other driver sharing this
491 			 * locator table. if one does, we may need to
492 			 * replace the locators with a malloc'd copy.
493 			 */
494 			for (i = 0; cfdata[i].cf_driver; i++)
495 				if (i != devno && cfdata[i].cf_loc == l)
496 					share = 1;
497 			if (share) {
498 				for (i = 0; locnamp[ln+i] != -1 ; i++)
499 					;
500 				lk = l = (int *)malloc(sizeof(int) * i,
501 				    M_TEMP, M_NOWAIT);
502 				if (lk == NULL) {
503 					printf("out of memory.\n");
504 					return;
505 				}
506 				bcopy(cd->cf_loc, l, sizeof(int) * i);
507 			}
508 
509 			while (locnamp[ln] != -1) {
510 				userconf_modify(locnames[locnamp[ln]], l);
511 
512 				/* XXX add *l */
513 				userconf_hist_int(*l);
514 
515 				ln++;
516 				l++;
517 			}
518 			userconf_modify("flags", &cd->cf_flags);
519 			userconf_hist_int(cd->cf_flags);
520 
521 			if (share) {
522 				if (bcmp(cd->cf_loc, lk, sizeof(int) * i))
523 					cd->cf_loc = lk;
524 				else
525 					free(lk, M_TEMP);
526 			}
527 
528 			printf("%3d ", devno);
529 			userconf_pdevnam(devno);
530 			printf(" changed\n");
531 			userconf_pdev(devno);
532 		}
533 		return;
534 	}
535 
536 	if (devno > userconf_maxdev && devno <= userconf_totdev) {
537 		printf("%3d can't change free slot\n", devno);
538 		return;
539 	}
540 
541 	if (devno > userconf_totdev &&
542 	    devno <= userconf_totdev+pdevnames_size) {
543 		userconf_pdev(devno);
544 		while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
545 			printf("change (y/n) ?");
546 			c = cngetc();
547 			printf("\n");
548 		}
549 
550 		if (c == 'y' || c == 'Y') {
551 			/* XXX add cmd 'c' <devno> */
552 			userconf_hist_cmd('c');
553 			userconf_hist_int(devno);
554 
555 			userconf_modify("count",
556 			    &pdevinit[devno-userconf_totdev-1].pdev_count);
557 			userconf_hist_int(pdevinit[devno-userconf_totdev-1].pdev_count);
558 
559 			printf("%3d %s changed\n", devno,
560 			    pdevnames[devno-userconf_totdev-1]);
561 			userconf_pdev(devno);
562 
563 			/* XXX add eoc */
564 			userconf_hist_eoc();
565 		}
566 		return;
567 	}
568 
569 	printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size);
570 }
571 
572 void
573 userconf_disable(devno)
574 	int devno;
575 {
576 	int done = 0;
577 
578 	if (devno <= userconf_maxdev) {
579 		switch (cfdata[devno].cf_fstate) {
580 		case FSTATE_NOTFOUND:
581 			cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
582 			break;
583 		case FSTATE_STAR:
584 			cfdata[devno].cf_fstate = FSTATE_DSTAR;
585 			break;
586 		case FSTATE_DNOTFOUND:
587 		case FSTATE_DSTAR:
588 			done = 1;
589 			break;
590 		default:
591 			printf("Error unknown state\n");
592 			break;
593 		}
594 
595 		printf("%3d ", devno);
596 		userconf_pdevnam(devno);
597 		if (done) {
598 			printf(" already");
599 		} else {
600 			/* XXX add cmd 'd' <devno> eoc */
601 			userconf_hist_cmd('d');
602 			userconf_hist_int(devno);
603 			userconf_hist_eoc();
604 		}
605 		printf(" disabled\n");
606 
607 		return;
608 	}
609 
610 	if (devno > userconf_maxdev && devno <= userconf_totdev) {
611 		printf("%3d can't disable free slot\n", devno);
612 		return;
613 	}
614 
615 	if (devno > userconf_totdev &&
616 	    devno <= userconf_totdev+pdevnames_size) {
617 		printf("%3d %s can't disable pseudo device\n", devno,
618 		    pdevnames[devno-userconf_totdev-1]);
619 		return;
620 	}
621 
622 	printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size);
623 }
624 
625 void
626 userconf_enable(devno)
627 	int devno;
628 {
629 	int done = 0;
630 
631 	if (devno <= userconf_maxdev) {
632 		switch (cfdata[devno].cf_fstate) {
633 		case FSTATE_DNOTFOUND:
634 			cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
635 			break;
636 		case FSTATE_DSTAR:
637 			cfdata[devno].cf_fstate = FSTATE_STAR;
638 			break;
639 		case FSTATE_NOTFOUND:
640 		case FSTATE_STAR:
641 			done = 1;
642 			break;
643 		default:
644 			printf("Error unknown state\n");
645 			break;
646 		}
647 
648 		printf("%3d ", devno);
649 		userconf_pdevnam(devno);
650 		if (done) {
651 			printf(" already");
652 		} else {
653 			/* XXX add cmd 'e' <devno> eoc */
654 			userconf_hist_cmd('e');
655 			userconf_hist_int(devno);
656 			userconf_hist_eoc();
657 		}
658 		printf(" enabled\n");
659 		return;
660 	}
661 
662 	if (devno > userconf_maxdev && devno <= userconf_totdev) {
663 		printf("%3d can't enable free slot\n", devno);
664 		return;
665 	}
666 
667 	if (devno > userconf_totdev &&
668 	    devno <= userconf_totdev+pdevnames_size) {
669 		printf("%3d %s can't enable pseudo device\n", devno,
670 		    pdevnames[devno-userconf_totdev-1]);
671 		return;
672 	}
673 
674 	printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size);
675 }
676 
677 void
678 userconf_help()
679 {
680 	int j = 0, k;
681 
682 	printf("command   args                description\n");
683 	while (*userconf_cmds[j] != '\0') {
684 		printf(userconf_cmds[j]);
685 		k = strlen(userconf_cmds[j]);
686 		while (k < 10) {
687 			printf(" ");
688 			k++;
689 		}
690 		switch (*userconf_cmds[j+1]) {
691 		case 'L':
692 			printf("[count]             number of lines before more");
693 			break;
694 		case 'a':
695 			printf("dev                 add a device");
696 			break;
697 		case 'b':
698 			printf("8|10|16             base on large numbers");
699 			break;
700 		case 'c':
701 			printf("devno|dev           change devices");
702 			break;
703 #if defined(DDB)
704 		case 'D':
705 			printf("                    enter ddb");
706 			break;
707 #endif
708 		case 'd':
709 			printf("attr val|devno|dev  disable devices");
710 			break;
711 		case 'e':
712 			printf("attr val|devno|dev  enable devices");
713 			break;
714 		case 'f':
715 			printf("devno|dev           find devices");
716 			break;
717 		case 'h':
718 			printf("                    this message");
719 			break;
720 		case 'l':
721 			printf("                    list configuration");
722 			break;
723 		case 'q':
724 			printf("                    leave UKC");
725 			break;
726 		case 's':
727 			printf("[attr [val]]        "
728 			   "show attributes (or devices with an attribute)");
729 			break;
730 		case 't':
731 			printf("[mins [dst]]        set timezone/dst");
732 			break;
733 		case 'v':
734 			printf("                    toggle verbose booting");
735 			break;
736 		default:
737 			printf("                    don't know");
738 			break;
739 		}
740 		printf("\n");
741 		j += 2;
742 	}
743 }
744 
745 void
746 userconf_list()
747 {
748 	int i = 0;
749 
750 	userconf_cnt = 0;
751 
752 	while (i <= (userconf_totdev+pdevnames_size)) {
753 		if (userconf_more())
754 			break;
755 		userconf_pdev(i++);
756 	}
757 
758 	userconf_cnt = -1;
759 }
760 
761 void
762 userconf_show()
763 {
764 	int i = 0;
765 
766 	userconf_cnt = 0;
767 
768 	while (i <= userconf_maxlocnames) {
769 		if (userconf_more())
770 			break;
771 		printf("%s\n", locnames[i++]);
772 	}
773 
774 	userconf_cnt = -1;
775 }
776 
777 void
778 userconf_common_attr_val(attr, val, routine)
779 	short attr;
780 	int   *val;
781 	char  routine;
782 {
783 	struct cfdata *cd;
784 	int   *l;
785 	int   ln;
786 	int i = 0, quit = 0;
787 
788 	userconf_cnt = 0;
789 
790 	while (i <= userconf_maxdev) {
791 		cd = &cfdata[i];
792 		l = cd->cf_loc;
793 		ln = cd->cf_locnames;
794 		while (locnamp[ln] != -1) {
795 			if (locnamp[ln] == attr) {
796 				if (val == NULL) {
797 					quit = userconf_more();
798 					userconf_pdev(i);
799 				} else {
800 					if (*val == *l) {
801 						quit = userconf_more();
802 						switch (routine) {
803 						case UC_ENABLE:
804 							userconf_enable(i);
805 							break;
806 						case UC_DISABLE:
807 							userconf_disable(i);
808 							break;
809 						case UC_SHOW:
810 							userconf_pdev(i);
811 							break;
812 						default:
813 							printf("Unknown routine /%c/\n",
814 							    routine);
815 							break;
816 						}
817 					}
818 				}
819 			}
820 			if (quit)
821 				break;
822 			ln++;
823 			l++;
824 		}
825 		if (quit)
826 			break;
827 		i++;
828 	}
829 
830 	userconf_cnt = -1;
831 }
832 
833 void
834 userconf_show_attr(cmd)
835 	char *cmd;
836 {
837 	char *c;
838 	short attr = -1, i = 0, l = 0;
839 	int a;
840 
841 	c = cmd;
842 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
843 		c++;
844 		l++;
845 	}
846 	while (*c == ' ' || *c == '\t' || *c == '\n') {
847 		c++;
848 	}
849 	while (i <= userconf_maxlocnames) {
850 		if (strlen(locnames[i]) == l) {
851 			if (strncasecmp(cmd, locnames[i], l) == 0) {
852 				attr = i;
853 			}
854 		}
855 		i++;
856 	}
857 
858 	if (attr == -1) {
859 		printf("Unknown attribute\n");
860 		return;
861 	}
862 
863 	if (*c == '\0') {
864 		userconf_common_attr_val(attr, NULL, UC_SHOW);
865 	} else {
866 		if (userconf_number(c, &a) == 0) {
867 			userconf_common_attr_val(attr, &a, UC_SHOW);
868 		} else {
869 			printf("Unknown argument\n");
870 		}
871 	}
872 }
873 
874 void
875 userconf_common_dev(dev, len, unit, state, routine)
876 	char *dev;
877 	int len;
878 	short unit, state;
879 	char routine;
880 {
881 	int i = 0;
882 
883 	switch (routine) {
884 	case UC_CHANGE:
885 		break;
886 	default:
887 		userconf_cnt = 0;
888 		break;
889 	}
890 
891 	while (cfdata[i].cf_attach != 0) {
892 		if (strlen(cfdata[i].cf_driver->cd_name) == len) {
893 
894 			/*
895 			 * Ok, if device name is correct
896 			 *  If state == FSTATE_FOUND, look for "dev"
897 			 *  If state == FSTATE_STAR, look for "dev*"
898 			 *  If state == FSTATE_NOTFOUND, look for "dev0"
899 			 */
900 			if (strncasecmp(dev, cfdata[i].cf_driver->cd_name,
901 					len) == 0 &&
902 			    (state == FSTATE_FOUND ||
903 			     (state == FSTATE_STAR &&
904 			      (cfdata[i].cf_fstate == FSTATE_STAR ||
905 			       cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
906 			     (state == FSTATE_NOTFOUND &&
907 			      cfdata[i].cf_unit == unit &&
908 			      (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
909 			       cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
910 				if (userconf_more())
911 					break;
912 				switch (routine) {
913 				case UC_CHANGE:
914 					userconf_change(i);
915 					break;
916 				case UC_ENABLE:
917 					userconf_enable(i);
918 					break;
919 				case UC_DISABLE:
920 					userconf_disable(i);
921 					break;
922 				case UC_FIND:
923 					userconf_pdev(i);
924 					break;
925 				default:
926 					printf("Unknown routine /%c/\n",
927 					    routine);
928 					break;
929 				}
930 			}
931 		}
932 		i++;
933 	}
934 
935 	for (i = 0; i < pdevnames_size; i++) {
936 		if (strncasecmp(dev, pdevnames[i], len) == 0 &&
937 		    state == FSTATE_FOUND) {
938 			switch(routine) {
939 			case UC_CHANGE:
940 				userconf_change(userconf_totdev+1+i);
941 				break;
942 			case UC_ENABLE:
943 				userconf_enable(userconf_totdev+1+i);
944 				break;
945 			case UC_DISABLE:
946 				userconf_disable(userconf_totdev+1+i);
947 				break;
948 			case UC_FIND:
949 				userconf_pdev(userconf_totdev+1+i);
950 				break;
951 			default:
952 				printf("Unknown pseudo routine /%c/\n",routine);
953 				break;
954 			}
955 		}
956 	}
957 
958 	switch (routine) {
959 	case UC_CHANGE:
960 		break;
961 	default:
962 		userconf_cnt = -1;
963 		break;
964 	}
965 }
966 
967 void
968 userconf_common_attr(cmd, attr, routine)
969 	char *cmd;
970 	int attr;
971 	char routine;
972 {
973 	char *c;
974 	short l = 0;
975 	int a;
976 
977 	c = cmd;
978 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
979 		c++;
980 		l++;
981 	}
982 	while (*c == ' ' || *c == '\t' || *c == '\n')
983 		c++;
984 
985 	if (*c == '\0') {
986 		printf("Value missing for attribute\n");
987 		return;
988 	}
989 
990 	if (userconf_number(c, &a) == 0) {
991 		userconf_common_attr_val(attr, &a, routine);
992 	} else {
993 		printf("Unknown argument\n");
994 	}
995 }
996 
997 void
998 userconf_add_read(prompt, field, dev, len, val)
999 	char *prompt;
1000 	char field;
1001 	char *dev;
1002 	int len;
1003 	int *val;
1004 {
1005 	int ok = 0;
1006 	int a;
1007 	char *c;
1008 	int i;
1009 
1010 	*val = -1;
1011 
1012 	while (!ok) {
1013 		printf("%s ? ", prompt);
1014 
1015 		i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
1016 
1017 		c = userconf_argbuf;
1018 		while (*c == ' ' || *c == '\t' || *c == '\n')
1019 			c++;
1020 
1021 		if (*c != '\0') {
1022 			if (userconf_number(c, &a) == 0) {
1023 				if (a > userconf_maxdev) {
1024 					printf("Unknown devno (max is %d)\n",
1025 					    userconf_maxdev);
1026 				} else if (strncasecmp(dev,
1027 				    cfdata[a].cf_driver->cd_name, len) != 0 &&
1028 				    field == 'a') {
1029 					printf("Not same device type\n");
1030 				} else {
1031 					*val = a;
1032 					ok = 1;
1033 				}
1034 			} else if (*c == '?') {
1035 				userconf_common_dev(dev, len, 0,
1036 				    FSTATE_FOUND, UC_FIND);
1037 			} else if (*c == 'q' || *c == 'Q') {
1038 				ok = 1;
1039 			} else {
1040 				printf("Unknown argument\n");
1041 			}
1042 		} else {
1043 			ok = 1;
1044 		}
1045 	}
1046 }
1047 
1048 void
1049 userconf_add(dev, len, unit, state)
1050 	char *dev;
1051 	int len;
1052 	short unit, state;
1053 {
1054 	int i = 0, found = 0;
1055 	struct cfdata new;
1056 	int  val, max_unit, star_unit, orig;
1057 
1058 	bzero(&new, sizeof(struct cfdata));
1059 
1060 	if (userconf_maxdev == userconf_totdev) {
1061 		printf("No more space for new devices.\n");
1062 		return;
1063 	}
1064 
1065 	if (state == FSTATE_FOUND) {
1066 		printf("Device not complete number or * is missing\n");
1067 		return;
1068 	}
1069 
1070 	for (i = 0; cfdata[i].cf_driver; i++)
1071 		if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1072 		    strncasecmp(dev, cfdata[i].cf_driver->cd_name, len) == 0)
1073 			found = 1;
1074 
1075 	if (!found) {
1076 		printf("No device of this type exists.\n");
1077 		return;
1078 	}
1079 
1080 	userconf_add_read("Clone Device (DevNo, 'q' or '?')",
1081 	    'a', dev, len, &val);
1082 
1083 	if (val != -1) {
1084 		orig = val;
1085 		new = cfdata[val];
1086 		new.cf_unit = unit;
1087 		new.cf_fstate = state;
1088 		userconf_add_read("Insert before Device (DevNo, 'q' or '?')",
1089 		    'i', dev, len, &val);
1090 	}
1091 
1092 	if (val != -1) {
1093 		/* XXX add cmd 'a' <orig> <val> eoc */
1094 		userconf_hist_cmd('a');
1095 		userconf_hist_int(orig);
1096 		userconf_hist_int(unit);
1097 		userconf_hist_int(state);
1098 		userconf_hist_int(val);
1099 		userconf_hist_eoc();
1100 
1101 		/* Insert the new record */
1102 		for (i = userconf_maxdev; val <= i; i--)
1103 			cfdata[i+1] = cfdata[i];
1104 		cfdata[val] = new;
1105 
1106 		/* Fix indexs in pv */
1107 		for (i = 0; i < pv_size; i++) {
1108 			if (pv[i] != -1 && pv[i] >= val)
1109 				pv[i]++;
1110 		}
1111 
1112 		/* Fix indexs in cfroots */
1113 		for (i = 0; i < cfroots_size; i++) {
1114 			if (cfroots[i] != -1 && cfroots[i] >= val)
1115 				cfroots[i]++;
1116 		}
1117 
1118 		userconf_maxdev++;
1119 
1120 		max_unit = -1;
1121 
1122 		/* Find max unit number of the device type */
1123 
1124 		i = 0;
1125 		while (cfdata[i].cf_attach != 0) {
1126 			if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1127 			    strncasecmp(dev, cfdata[i].cf_driver->cd_name,
1128 			    len) == 0) {
1129 				switch (cfdata[i].cf_fstate) {
1130 				case FSTATE_NOTFOUND:
1131 				case FSTATE_DNOTFOUND:
1132 					if (cfdata[i].cf_unit > max_unit)
1133 						max_unit = cfdata[i].cf_unit;
1134 					break;
1135 				default:
1136 					break;
1137 				}
1138 			}
1139 			i++;
1140 		}
1141 
1142 		/*
1143 		 * For all * entries set unit number to max+1, and update
1144 		 * cf_starunit1 if necessary.
1145 		 */
1146 		max_unit++;
1147 		star_unit = -1;
1148 
1149 		i = 0;
1150 		while (cfdata[i].cf_attach != 0) {
1151 			if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1152 			    strncasecmp(dev, cfdata[i].cf_driver->cd_name,
1153 			    len) == 0) {
1154 				switch (cfdata[i].cf_fstate) {
1155 				case FSTATE_NOTFOUND:
1156 				case FSTATE_DNOTFOUND:
1157 					if (cfdata[i].cf_unit > star_unit)
1158 						star_unit = cfdata[i].cf_unit;
1159 					break;
1160 				default:
1161 					break;
1162 				}
1163 			}
1164 			i++;
1165 		}
1166 		star_unit++;
1167 
1168 		i = 0;
1169 		while (cfdata[i].cf_attach != 0) {
1170 			if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1171 			    strncasecmp(dev, cfdata[i].cf_driver->cd_name,
1172 			    len) == 0) {
1173 				switch (cfdata[i].cf_fstate) {
1174 				case FSTATE_STAR:
1175 				case FSTATE_DSTAR:
1176 					cfdata[i].cf_unit = max_unit;
1177 					if (cfdata[i].cf_starunit1 < star_unit)
1178 						cfdata[i].cf_starunit1 =
1179 						    star_unit;
1180 					break;
1181 				default:
1182 					break;
1183 				}
1184 			}
1185 			i++;
1186 		}
1187 		userconf_pdev(val);
1188 	}
1189 
1190 	/* cf_attach, cf_driver, cf_unit, cf_fstate, cf_loc, cf_flags,
1191 	   cf_parents, cf_locnames, cf_locnames and cf_ivstubs */
1192 }
1193 
1194 int
1195 userconf_parse(cmd)
1196 	char *cmd;
1197 {
1198 	char *c, *v;
1199 	int i = 0, j = 0, k, a;
1200 	short unit, state;
1201 
1202 	c = cmd;
1203 	while (*c == ' ' || *c == '\t')
1204 		c++;
1205 	v = c;
1206 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
1207 		c++;
1208 		i++;
1209 	}
1210 
1211 	k = -1;
1212 	while (*userconf_cmds[j] != '\0') {
1213 		if (strlen(userconf_cmds[j]) == i) {
1214 			if (strncasecmp(v, userconf_cmds[j], i) == 0)
1215 				k = j;
1216 		}
1217 		j += 2;
1218 	}
1219 
1220 	while (*c == ' ' || *c == '\t' || *c == '\n')
1221 		c++;
1222 
1223 	if (k == -1) {
1224 		if (*v != '\n')
1225 			printf("Unknown command, try help\n");
1226 	} else {
1227 		switch (*userconf_cmds[k+1]) {
1228 		case 'L':
1229 			if (*c == '\0')
1230 				printf("Argument expected\n");
1231 			else if (userconf_number(c, &a) == 0)
1232 				userconf_lines = a;
1233 			else
1234 				printf("Unknown argument\n");
1235 			break;
1236 		case 'a':
1237 			if (*c == '\0')
1238 				printf("Dev expected\n");
1239 			else if (userconf_device(c, &a, &unit, &state) == 0)
1240 				userconf_add(c, a, unit, state);
1241 			else
1242 				printf("Unknown argument\n");
1243 			break;
1244 		case 'b':
1245 			if (*c == '\0')
1246 				printf("8|10|16 expected\n");
1247 			else if (userconf_number(c, &a) == 0) {
1248 				if (a == 8 || a == 10 || a == 16) {
1249 					userconf_base = a;
1250 				} else {
1251 					printf("8|10|16 expected\n");
1252 				}
1253 			} else
1254 				printf("Unknown argument\n");
1255 			break;
1256 		case 'c':
1257 			if (*c == '\0')
1258 				printf("DevNo or Dev expected\n");
1259 			else if (userconf_number(c, &a) == 0)
1260 				userconf_change(a);
1261 			else if (userconf_device(c, &a, &unit, &state) == 0)
1262 				userconf_common_dev(c, a, unit, state, UC_CHANGE);
1263 			else
1264 				printf("Unknown argument\n");
1265 			break;
1266 #if defined(DDB)
1267 		case 'D':
1268 			Debugger();
1269 			break;
1270 #endif
1271 		case 'd':
1272 			if (*c == '\0')
1273 				printf("Attr, DevNo or Dev expected\n");
1274 			else if (userconf_attr(c, &a) == 0)
1275 				userconf_common_attr(c, a, UC_DISABLE);
1276 			else if (userconf_number(c, &a) == 0)
1277 				userconf_disable(a);
1278 			else if (userconf_device(c, &a, &unit, &state) == 0)
1279 				userconf_common_dev(c, a, unit, state, UC_DISABLE);
1280 			else
1281 				printf("Unknown argument\n");
1282 			break;
1283 		case 'e':
1284 			if (*c == '\0')
1285 				printf("Attr, DevNo or Dev expected\n");
1286 			else if (userconf_attr(c, &a) == 0)
1287 				userconf_common_attr(c, a, UC_ENABLE);
1288 			else if (userconf_number(c, &a) == 0)
1289 				userconf_enable(a);
1290 			else if (userconf_device(c, &a, &unit, &state) == 0)
1291 				userconf_common_dev(c, a, unit, state, UC_ENABLE);
1292 			else
1293 				printf("Unknown argument\n");
1294 			break;
1295 		case 'f':
1296 			if (*c == '\0')
1297 				printf("DevNo or Dev expected\n");
1298 			else if (userconf_number(c, &a) == 0)
1299 				userconf_pdev(a);
1300 			else if (userconf_device(c, &a, &unit, &state) == 0)
1301 				userconf_common_dev(c, a, unit, state, UC_FIND);
1302 			else
1303 				printf("Unknown argument\n");
1304 			break;
1305 		case 'h':
1306 			userconf_help();
1307 			break;
1308 		case 'l':
1309 			if (*c == '\0')
1310 				userconf_list();
1311 			else
1312 				printf("Unknown argument\n");
1313 			break;
1314 		case 'q':
1315 			/* XXX add cmd 'q' eoc */
1316 			userconf_hist_cmd('q');
1317 			userconf_hist_eoc();
1318 			return(-1);
1319 			break;
1320 		case 's':
1321 			if (*c == '\0')
1322 				userconf_show();
1323 			else
1324 				userconf_show_attr(c);
1325 			break;
1326 		case 't':
1327 			if (*c == '\0' || userconf_number(c, &a) == 0) {
1328 				if (*c != '\0') {
1329 					tz.tz_minuteswest = a;
1330 					while (*c != '\n' && *c != '\t' &&
1331 					    *c != ' ' && *c != '\0')
1332 						c++;
1333 					while (*c == '\t' || *c == ' ')
1334 						c++;
1335 					if (*c != '\0' &&
1336 					    userconf_number(c, &a) == 0)
1337 						tz.tz_dsttime = a;
1338 					userconf_hist_cmd('t');
1339 					userconf_hist_int(tz.tz_minuteswest);
1340 					userconf_hist_int(tz.tz_dsttime);
1341 					userconf_hist_eoc();
1342 				}
1343 				printf("timezone = %d, dst = %d\n",
1344 				    tz.tz_minuteswest, tz.tz_dsttime);
1345 			} else
1346 				printf("Unknown argument\n");
1347 			break;
1348 		case 'v':
1349 			autoconf_verbose = !autoconf_verbose;
1350 			printf("autoconf verbose %sabled\n",
1351 			    autoconf_verbose ? "en" : "dis");
1352 			break;
1353 		default:
1354 			printf("Unknown command\n");
1355 			break;
1356 		}
1357 	}
1358 	return(0);
1359 }
1360 
1361 void
1362 user_config()
1363 {
1364 	userconf_init();
1365 	printf("User Kernel Config\n");
1366 
1367 	while (1) {
1368 		printf("UKC> ");
1369 		if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
1370 		    userconf_parse(userconf_cmdbuf))
1371 			break;
1372 	}
1373 	printf("Continuing...\n");
1374 }
1375