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