subr_userconf.c revision 1.4.2.3 1 /* $NetBSD: subr_userconf.c,v 1.4.2.3 2001/11/14 19:16:41 nathanw Exp $ */
2
3 /*
4 * Copyright (c) 1996 Mats O Jansson <moj (at) 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 * OpenBSD: subr_userconf.c,v 1.19 2000/01/08 23:23:37 d Exp
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: subr_userconf.c,v 1.4.2.3 2001/11/14 19:16:41 nathanw Exp $");
39
40 #include "opt_userconf.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 #include <sys/time.h>
47
48 #include <dev/cons.h>
49
50 extern struct cfdata cfdata[];
51
52 int userconf_base = 16; /* Base for "large" numbers */
53 int userconf_maxdev = -1; /* # of used device slots */
54 int userconf_totdev = -1; /* # of device slots */
55 int userconf_maxlocnames = -1; /* # of locnames */
56 int userconf_cnt = -1; /* Line counter for ... */
57 int userconf_lines = 12; /* ... # of lines per page */
58 int userconf_histlen = 0;
59 int userconf_histcur = 0;
60 char userconf_history[1024];
61 int userconf_histsz = sizeof(userconf_history);
62 char userconf_argbuf[40]; /* Additional input */
63 char userconf_cmdbuf[40]; /* Command line */
64 char userconf_histbuf[40];
65
66 void userconf_init __P((void));
67 int userconf_more __P((void));
68 void userconf_modify __P((const char *, int*));
69 void userconf_hist_cmd __P((char));
70 void userconf_hist_int __P((int));
71 void userconf_hist_eoc __P((void));
72 void userconf_pnum __P((int));
73 void userconf_pdevnam __P((short));
74 void userconf_pdev __P((short));
75 int userconf_number __P((char *, int *));
76 int userconf_device __P((char *, int *, short *, short *));
77 void userconf_change __P((int));
78 void userconf_disable __P((int));
79 void userconf_enable __P((int));
80 void userconf_help __P((void));
81 void userconf_list __P((void));
82 void userconf_common_dev __P((char *, int, short, short, char));
83 void userconf_add_read __P((char *, char, char *, int, int *));
84 int userconf_parse __P((char *));
85
86 static int getsn __P((char *, int));
87
88 #define UC_CHANGE 'c'
89 #define UC_DISABLE 'd'
90 #define UC_ENABLE 'e'
91 #define UC_FIND 'f'
92 #define UC_SHOW 's'
93
94 char *userconf_cmds[] = {
95 "base", "b",
96 "change", "c",
97 "disable", "d",
98 "enable", "e",
99 "exit", "q",
100 "find", "f",
101 "help", "h",
102 "list", "l",
103 "lines", "L",
104 "quit", "q",
105 "?", "h",
106 "", "",
107 };
108
109 void
110 userconf_init()
111 {
112 int i;
113 struct cfdata *cf;
114
115 i = 0;
116 for (cf = cfdata; cf->cf_driver; cf++)
117 i++;
118
119 userconf_maxdev = i - 1;
120 userconf_totdev = i - 1;
121 }
122
123 int
124 userconf_more()
125 {
126 int quit = 0;
127 char c = '\0';
128
129 if (userconf_cnt != -1) {
130 if (userconf_cnt == userconf_lines) {
131 printf("-- more --");
132 c = cngetc();
133 userconf_cnt = 0;
134 printf("\r \r");
135 }
136 userconf_cnt++;
137 if (c == 'q' || c == 'Q')
138 quit = 1;
139 }
140 return (quit);
141 }
142
143 void
144 userconf_hist_cmd(cmd)
145 char cmd;
146 {
147 userconf_histcur = userconf_histlen;
148 if (userconf_histcur < userconf_histsz) {
149 userconf_history[userconf_histcur] = cmd;
150 userconf_histcur++;
151 }
152 }
153
154 void
155 userconf_hist_int(val)
156 int val;
157 {
158 sprintf(userconf_histbuf," %d",val);
159 if ((userconf_histcur + strlen(userconf_histbuf)) < userconf_histsz) {
160 memcpy(&userconf_history[userconf_histcur],
161 userconf_histbuf,
162 strlen(userconf_histbuf));
163 userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
164 }
165 }
166
167 void
168 userconf_hist_eoc()
169 {
170 if (userconf_histcur < userconf_histsz) {
171 userconf_history[userconf_histcur] = '\n';
172 userconf_histcur++;
173 userconf_histlen = userconf_histcur;
174 }
175 }
176
177 void
178 userconf_pnum(val)
179 int val;
180 {
181 if (val > -2 && val < 16) {
182 printf("%d",val);
183 } else {
184 switch (userconf_base) {
185 case 8:
186 printf("0%o",val);
187 break;
188 case 10:
189 printf("%d",val);
190 break;
191 case 16:
192 default:
193 printf("0x%x",val);
194 break;
195 }
196 }
197 }
198
199 void
200 userconf_pdevnam(dev)
201 short dev;
202 {
203 struct cfdata *cd;
204
205 cd = &cfdata[dev];
206 printf("%s", cd->cf_driver->cd_name);
207 switch (cd->cf_fstate) {
208 case FSTATE_NOTFOUND:
209 case FSTATE_DNOTFOUND:
210 printf("%d", cd->cf_unit);
211 break;
212 case FSTATE_FOUND:
213 printf("*FOUND*");
214 break;
215 case FSTATE_STAR:
216 case FSTATE_DSTAR:
217 printf("*");
218 break;
219 default:
220 printf("*UNKNOWN*");
221 break;
222 }
223 }
224
225 void
226 userconf_pdev(devno)
227 short devno;
228 {
229 struct cfdata *cd;
230 short *p;
231 int *l;
232 const char **ln;
233 char c;
234
235 if (devno > userconf_maxdev) {
236 printf("Unknown devno (max is %d)\n", userconf_maxdev);
237 return;
238 }
239
240 cd = &cfdata[devno];
241
242 printf("[%3d] ", devno);
243 userconf_pdevnam(devno);
244 printf(" at");
245 c = ' ';
246 p = cd->cf_parents;
247 if (*p == -1)
248 printf(" root");
249 while (*p != -1) {
250 printf("%c", c);
251 userconf_pdevnam(*p++);
252 c = '|';
253 }
254 switch (cd->cf_fstate) {
255 case FSTATE_NOTFOUND:
256 case FSTATE_FOUND:
257 case FSTATE_STAR:
258 break;
259 case FSTATE_DNOTFOUND:
260 case FSTATE_DSTAR:
261 printf(" disable");
262 break;
263 default:
264 printf(" ???");
265 break;
266 }
267 l = cd->cf_loc;
268 ln = cd->cf_locnames;
269 while (ln && *ln) {
270 printf(" %s ", *ln++);
271 userconf_pnum(*l++);
272 }
273 printf("\n");
274 }
275
276 int
277 userconf_number(c, val)
278 char *c;
279 int *val;
280 {
281 u_int num = 0;
282 int neg = 0;
283 int base = 10;
284
285 if (*c == '-') {
286 neg = 1;
287 c++;
288 }
289 if (*c == '0') {
290 base = 8;
291 c++;
292 if (*c == 'x' || *c == 'X') {
293 base = 16;
294 c++;
295 }
296 }
297 while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
298 u_char cc = *c;
299
300 if (cc >= '0' && cc <= '9')
301 cc = cc - '0';
302 else if (cc >= 'a' && cc <= 'f')
303 cc = cc - 'a' + 10;
304 else if (cc >= 'A' && cc <= 'F')
305 cc = cc - 'A' + 10;
306 else
307 return (-1);
308
309 if (cc > base)
310 return (-1);
311 num = num * base + cc;
312 c++;
313 }
314
315 if (neg && num > INT_MAX) /* overflow */
316 return (1);
317 *val = neg ? - num : num;
318 return (0);
319 }
320
321 int
322 userconf_device(cmd, len, unit, state)
323 char *cmd;
324 int *len;
325 short *unit, *state;
326 {
327 short u = 0, s = FSTATE_FOUND;
328 int l = 0;
329 char *c;
330
331 c = cmd;
332 while (*c >= 'a' && *c <= 'z') {
333 l++;
334 c++;
335 }
336 if (*c == '*') {
337 s = FSTATE_STAR;
338 c++;
339 } else {
340 while (*c >= '0' && *c <= '9') {
341 s = FSTATE_NOTFOUND;
342 u = u*10 + *c - '0';
343 c++;
344 }
345 }
346 while (*c == ' ' || *c == '\t' || *c == '\n')
347 c++;
348
349 if (*c == '\0') {
350 *len = l;
351 *unit = u;
352 *state = s;
353 return(0);
354 }
355
356 return(-1);
357 }
358
359 void
360 userconf_modify(item, val)
361 const char *item;
362 int *val;
363 {
364 int ok = 0;
365 int a;
366 char *c;
367 int i;
368
369 while (!ok) {
370 printf("%s [", item);
371 userconf_pnum(*val);
372 printf("] ? ");
373
374 i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
375
376 c = userconf_argbuf;
377 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
378
379 if (*c != '\0') {
380 if (userconf_number(c, &a) == 0) {
381 *val = a;
382 ok = 1;
383 } else {
384 printf("Unknown argument\n");
385 }
386 } else {
387 ok = 1;
388 }
389 }
390 }
391
392 void
393 userconf_change(devno)
394 int devno;
395 {
396 struct cfdata *cd;
397 char c = '\0';
398 int *l;
399 int ln;
400 const char **locnames;
401
402 if (devno <= userconf_maxdev) {
403
404 userconf_pdev(devno);
405
406 while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
407 printf("change (y/n) ?");
408 c = cngetc();
409 printf("\n");
410 }
411
412 if (c == 'y' || c == 'Y') {
413
414 /* XXX add cmd 'c' <devno> */
415 userconf_hist_cmd('c');
416 userconf_hist_int(devno);
417
418 cd = &cfdata[devno];
419 l = cd->cf_loc;
420 locnames = cd->cf_locnames;
421 ln = 0;
422
423 while (locnames[ln])
424 {
425 userconf_modify(locnames[ln], l);
426
427 /* XXX add *l */
428 userconf_hist_int(*l);
429
430 ln++;
431 l++;
432 }
433
434 printf("[%3d] ", devno);
435 userconf_pdevnam(devno);
436 printf(" changed\n");
437 userconf_pdev(devno);
438
439 /* XXX add eoc */
440 userconf_hist_eoc();
441
442 }
443 } else {
444 printf("Unknown devno (max is %d)\n", userconf_maxdev);
445 }
446 }
447
448 void
449 userconf_disable(devno)
450 int devno;
451 {
452 int done = 0;
453
454 if (devno <= userconf_maxdev) {
455 switch (cfdata[devno].cf_fstate) {
456 case FSTATE_NOTFOUND:
457 cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
458 break;
459 case FSTATE_STAR:
460 cfdata[devno].cf_fstate = FSTATE_DSTAR;
461 break;
462 case FSTATE_DNOTFOUND:
463 case FSTATE_DSTAR:
464 done = 1;
465 break;
466 default:
467 printf("Error unknown state\n");
468 break;
469 }
470
471 printf("[%3d] ", devno);
472 userconf_pdevnam(devno);
473 if (done) {
474 printf(" already");
475 } else {
476 /* XXX add cmd 'd' <devno> eoc */
477 userconf_hist_cmd('d');
478 userconf_hist_int(devno);
479 userconf_hist_eoc();
480 }
481 printf(" disabled\n");
482 } else {
483 printf("Unknown devno (max is %d)\n", userconf_maxdev);
484 }
485 }
486
487 void
488 userconf_enable(devno)
489 int devno;
490 {
491 int done = 0;
492
493 if (devno <= userconf_maxdev) {
494 switch (cfdata[devno].cf_fstate) {
495 case FSTATE_DNOTFOUND:
496 cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
497 break;
498 case FSTATE_DSTAR:
499 cfdata[devno].cf_fstate = FSTATE_STAR;
500 break;
501 case FSTATE_NOTFOUND:
502 case FSTATE_STAR:
503 done = 1;
504 break;
505 default:
506 printf("Error unknown state\n");
507 break;
508 }
509
510 printf("[%3d] ", devno);
511 userconf_pdevnam(devno);
512 if (done) {
513 printf(" already");
514 } else {
515 /* XXX add cmd 'e' <devno> eoc */
516 userconf_hist_cmd('d');
517 userconf_hist_int(devno);
518 userconf_hist_eoc();
519 }
520 printf(" enabled\n");
521 } else {
522 printf("Unknown devno (max is %d)\n", userconf_maxdev);
523 }
524 }
525
526 void
527 userconf_help()
528 {
529 int j = 0, k;
530
531 printf("command args description\n");
532 while (*userconf_cmds[j] != '\0') {
533 printf(userconf_cmds[j]);
534 k = strlen(userconf_cmds[j]);
535 while (k < 10) {
536 printf(" ");
537 k++;
538 }
539 switch (*userconf_cmds[j+1]) {
540 case 'L':
541 printf("[count] number of lines before more");
542 break;
543 case 'b':
544 printf("8|10|16 base on large numbers");
545 break;
546 case 'c':
547 printf("devno|dev change devices");
548 break;
549 case 'd':
550 printf("devno|dev disable devices");
551 break;
552 case 'e':
553 printf("devno|dev enable devices");
554 break;
555 case 'f':
556 printf("devno|dev find devices");
557 break;
558 case 'h':
559 printf(" this message");
560 break;
561 case 'l':
562 printf(" list configuration");
563 break;
564 case 'q':
565 printf(" leave userconf");
566 break;
567 default:
568 printf(" don't know");
569 break;
570 }
571 printf("\n");
572 j += 2;
573 }
574 }
575
576 void
577 userconf_list()
578 {
579 int i = 0;
580
581 userconf_cnt = 0;
582
583 while (cfdata[i].cf_attach != 0) {
584 if (userconf_more())
585 break;
586 userconf_pdev(i++);
587 }
588
589 userconf_cnt = -1;
590 }
591
592 void
593 userconf_common_dev(dev, len, unit, state, routine)
594 char *dev;
595 int len;
596 short unit, state;
597 char routine;
598 {
599 int i = 0;
600
601 switch (routine) {
602 case UC_CHANGE:
603 break;
604 default:
605 userconf_cnt = 0;
606 break;
607 }
608
609 while (cfdata[i].cf_attach != 0) {
610 if (strlen(cfdata[i].cf_driver->cd_name) == len) {
611
612 /*
613 * Ok, if device name is correct
614 * If state == FSTATE_FOUND, look for "dev"
615 * If state == FSTATE_STAR, look for "dev*"
616 * If state == FSTATE_NOTFOUND, look for "dev0"
617 */
618 if (strncasecmp(dev, cfdata[i].cf_driver->cd_name,
619 len) == 0 &&
620 (state == FSTATE_FOUND ||
621 (state == FSTATE_STAR &&
622 (cfdata[i].cf_fstate == FSTATE_STAR ||
623 cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
624 (state == FSTATE_NOTFOUND &&
625 cfdata[i].cf_unit == unit &&
626 (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
627 cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
628 if (userconf_more())
629 break;
630 switch (routine) {
631 case UC_CHANGE:
632 userconf_change(i);
633 break;
634 case UC_ENABLE:
635 userconf_enable(i);
636 break;
637 case UC_DISABLE:
638 userconf_disable(i);
639 break;
640 case UC_FIND:
641 userconf_pdev(i);
642 break;
643 default:
644 printf("Unknown routine /%c/\n",
645 routine);
646 break;
647 }
648 }
649 }
650 i++;
651 }
652
653 switch (routine) {
654 case UC_CHANGE:
655 break;
656 default:
657 userconf_cnt = -1;
658 break;
659 }
660 }
661
662 void
663 userconf_add_read(prompt, field, dev, len, val)
664 char *prompt;
665 char field;
666 char *dev;
667 int len;
668 int *val;
669 {
670 int ok = 0;
671 int a;
672 char *c;
673 int i;
674
675 *val = -1;
676
677 while (!ok) {
678 printf("%s ? ", prompt);
679
680 i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
681
682 c = userconf_argbuf;
683 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
684
685 if (*c != '\0') {
686 if (userconf_number(c, &a) == 0) {
687 if (a > userconf_maxdev) {
688 printf("Unknown devno (max is %d)\n",
689 userconf_maxdev);
690 } else if (strncasecmp(dev,
691 cfdata[a].cf_driver->cd_name, len) != 0 &&
692 field == 'a') {
693 printf("Not same device type\n");
694 } else {
695 *val = a;
696 ok = 1;
697 }
698 } else if (*c == '?') {
699 userconf_common_dev(dev, len, 0,
700 FSTATE_FOUND, UC_FIND);
701 } else if (*c == 'q' || *c == 'Q') {
702 ok = 1;
703 } else {
704 printf("Unknown argument\n");
705 }
706 } else {
707 ok = 1;
708 }
709 }
710 }
711
712 int
713 userconf_parse(cmd)
714 char *cmd;
715 {
716 char *c, *v;
717 int i = 0, j = 0, k, a;
718 short unit, state;
719
720 c = cmd;
721 while (*c == ' ' || *c == '\t')
722 c++;
723 v = c;
724 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
725 c++;
726 i++;
727 }
728
729 k = -1;
730 while (*userconf_cmds[j] != '\0') {
731 if (strlen(userconf_cmds[j]) == i) {
732 if (strncasecmp(v, userconf_cmds[j], i) == 0)
733 k = j;
734 }
735 j += 2;
736 }
737
738 while (*c == ' ' || *c == '\t' || *c == '\n')
739 c++;
740
741 if (k == -1) {
742 if (*v != '\n')
743 printf("Unknown command, try help\n");
744 } else {
745 switch (*userconf_cmds[k+1]) {
746 case 'L':
747 if (*c == '\0')
748 printf("Argument expected\n");
749 else if (userconf_number(c, &a) == 0)
750 userconf_lines = a;
751 else
752 printf("Unknown argument\n");
753 break;
754 case 'b':
755 if (*c == '\0')
756 printf("8|10|16 expected\n");
757 else if (userconf_number(c, &a) == 0) {
758 if (a == 8 || a == 10 || a == 16) {
759 userconf_base = a;
760 } else {
761 printf("8|10|16 expected\n");
762 }
763 } else
764 printf("Unknown argument\n");
765 break;
766 case 'c':
767 if (*c == '\0')
768 printf("DevNo or Dev expected\n");
769 else if (userconf_number(c, &a) == 0)
770 userconf_change(a);
771 else if (userconf_device(c, &a, &unit, &state) == 0)
772 userconf_common_dev(c, a, unit, state, UC_CHANGE);
773 else
774 printf("Unknown argument\n");
775 break;
776 case 'd':
777 if (*c == '\0')
778 printf("Attr, DevNo or Dev expected\n");
779 else if (userconf_number(c, &a) == 0)
780 userconf_disable(a);
781 else if (userconf_device(c, &a, &unit, &state) == 0)
782 userconf_common_dev(c, a, unit, state, UC_DISABLE);
783 else
784 printf("Unknown argument\n");
785 break;
786 case 'e':
787 if (*c == '\0')
788 printf("Attr, DevNo or Dev expected\n");
789 else if (userconf_number(c, &a) == 0)
790 userconf_enable(a);
791 else if (userconf_device(c, &a, &unit, &state) == 0)
792 userconf_common_dev(c, a, unit, state, UC_ENABLE);
793 else
794 printf("Unknown argument\n");
795 break;
796 case 'f':
797 if (*c == '\0')
798 printf("DevNo or Dev expected\n");
799 else if (userconf_number(c, &a) == 0)
800 userconf_pdev(a);
801 else if (userconf_device(c, &a, &unit, &state) == 0)
802 userconf_common_dev(c, a, unit, state, UC_FIND);
803 else
804 printf("Unknown argument\n");
805 break;
806 case 'h':
807 userconf_help();
808 break;
809 case 'l':
810 if (*c == '\0')
811 userconf_list();
812 else
813 printf("Unknown argument\n");
814 break;
815 case 'q':
816 /* XXX add cmd 'q' eoc */
817 userconf_hist_cmd('q');
818 userconf_hist_eoc();
819 return(-1);
820 break;
821 case 's':
822 default:
823 printf("Unknown command\n");
824 break;
825 }
826 }
827 return(0);
828 }
829
830 extern void user_config __P((void));
831
832 void
833 user_config()
834 {
835 char prompt[] = "uc> ";
836
837 userconf_init();
838 printf("userconf: configure system autoconfiguration:\n");
839
840 while (1) {
841 printf(prompt);
842 if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
843 userconf_parse(userconf_cmdbuf))
844 break;
845 }
846 printf("Continuing...\n");
847 }
848
849 /*
850 * XXX shouldn't this be a common function?
851 */
852 static int
853 getsn(cp, size)
854 char *cp;
855 int size;
856 {
857 char *lp;
858 int c, len;
859
860 cnpollc(1);
861
862 lp = cp;
863 len = 0;
864 for (;;) {
865 c = cngetc();
866 switch (c) {
867 case '\n':
868 case '\r':
869 printf("\n");
870 *lp++ = '\0';
871 cnpollc(0);
872 return (len);
873 case '\b':
874 case '\177':
875 case '#':
876 if (len) {
877 --len;
878 --lp;
879 printf("\b \b");
880 }
881 continue;
882 case '@':
883 case 'u'&037:
884 len = 0;
885 lp = cp;
886 printf("\n");
887 continue;
888 default:
889 if (len + 1 >= size || c < ' ') {
890 printf("\007");
891 continue;
892 }
893 printf("%c", c);
894 ++len;
895 *lp++ = c;
896 }
897 }
898 }
899