subr_userconf.c revision 1.2 1 /* $NetBSD: subr_userconf.c,v 1.2 2001/07/02 23:02:11 itojun 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 bcopy(userconf_histbuf,
158 &userconf_history[userconf_histcur],
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 #ifdef __OpenBSD__
432 if (share) {
433 if (bcmp(cd->cf_loc, lk, sizeof(int) * i))
434 cd->cf_loc = lk;
435 else
436 free(lk, M_TEMP);
437 }
438 #endif
439
440 printf("[%3d] ", devno);
441 userconf_pdevnam(devno);
442 printf(" changed\n");
443 userconf_pdev(devno);
444
445 /* XXX add eoc */
446 userconf_hist_eoc();
447
448 }
449 } else {
450 printf("Unknown devno (max is %d)\n", userconf_maxdev);
451 }
452 }
453
454 void
455 userconf_disable(devno)
456 int devno;
457 {
458 int done = 0;
459
460 if (devno <= userconf_maxdev) {
461 switch (cfdata[devno].cf_fstate) {
462 case FSTATE_NOTFOUND:
463 cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
464 break;
465 case FSTATE_STAR:
466 cfdata[devno].cf_fstate = FSTATE_DSTAR;
467 break;
468 case FSTATE_DNOTFOUND:
469 case FSTATE_DSTAR:
470 done = 1;
471 break;
472 default:
473 printf("Error unknown state\n");
474 break;
475 }
476
477 printf("[%3d] ", devno);
478 userconf_pdevnam(devno);
479 if (done) {
480 printf(" already");
481 } else {
482 /* XXX add cmd 'd' <devno> eoc */
483 userconf_hist_cmd('d');
484 userconf_hist_int(devno);
485 userconf_hist_eoc();
486 }
487 printf(" disabled\n");
488 } else {
489 printf("Unknown devno (max is %d)\n", userconf_maxdev);
490 }
491 }
492
493 void
494 userconf_enable(devno)
495 int devno;
496 {
497 int done = 0;
498
499 if (devno <= userconf_maxdev) {
500 switch (cfdata[devno].cf_fstate) {
501 case FSTATE_DNOTFOUND:
502 cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
503 break;
504 case FSTATE_DSTAR:
505 cfdata[devno].cf_fstate = FSTATE_STAR;
506 break;
507 case FSTATE_NOTFOUND:
508 case FSTATE_STAR:
509 done = 1;
510 break;
511 default:
512 printf("Error unknown state\n");
513 break;
514 }
515
516 printf("[%3d] ", devno);
517 userconf_pdevnam(devno);
518 if (done) {
519 printf(" already");
520 } else {
521 /* XXX add cmd 'e' <devno> eoc */
522 userconf_hist_cmd('d');
523 userconf_hist_int(devno);
524 userconf_hist_eoc();
525 }
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 'b':
550 printf("8|10|16 base on large numbers");
551 break;
552 case 'c':
553 printf("devno|dev change devices");
554 break;
555 case 'd':
556 printf("devno|dev disable devices");
557 break;
558 case 'e':
559 printf("devno|dev enable devices");
560 break;
561 case 'f':
562 printf("devno|dev find devices");
563 break;
564 case 'h':
565 printf(" this message");
566 break;
567 case 'l':
568 printf(" list configuration");
569 break;
570 case 'q':
571 printf(" leave userconf");
572 break;
573 default:
574 printf(" don't know");
575 break;
576 }
577 printf("\n");
578 j += 2;
579 }
580 }
581
582 void
583 userconf_list()
584 {
585 int i = 0;
586
587 userconf_cnt = 0;
588
589 while (cfdata[i].cf_attach != 0) {
590 if (userconf_more())
591 break;
592 userconf_pdev(i++);
593 }
594
595 userconf_cnt = -1;
596 }
597
598 void
599 userconf_common_dev(dev, len, unit, state, routine)
600 char *dev;
601 int len;
602 short unit, state;
603 char routine;
604 {
605 int i = 0;
606
607 switch (routine) {
608 case UC_CHANGE:
609 break;
610 default:
611 userconf_cnt = 0;
612 break;
613 }
614
615 while (cfdata[i].cf_attach != 0) {
616 if (strlen(cfdata[i].cf_driver->cd_name) == len) {
617
618 /*
619 * Ok, if device name is correct
620 * If state == FSTATE_FOUND, look for "dev"
621 * If state == FSTATE_STAR, look for "dev*"
622 * If state == FSTATE_NOTFOUND, look for "dev0"
623 */
624 if (strncasecmp(dev, cfdata[i].cf_driver->cd_name,
625 len) == 0 &&
626 (state == FSTATE_FOUND ||
627 (state == FSTATE_STAR &&
628 (cfdata[i].cf_fstate == FSTATE_STAR ||
629 cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
630 (state == FSTATE_NOTFOUND &&
631 cfdata[i].cf_unit == unit &&
632 (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
633 cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
634 if (userconf_more())
635 break;
636 switch (routine) {
637 case UC_CHANGE:
638 userconf_change(i);
639 break;
640 case UC_ENABLE:
641 userconf_enable(i);
642 break;
643 case UC_DISABLE:
644 userconf_disable(i);
645 break;
646 case UC_FIND:
647 userconf_pdev(i);
648 break;
649 default:
650 printf("Unknown routine /%c/\n",
651 routine);
652 break;
653 }
654 }
655 }
656 i++;
657 }
658
659 switch (routine) {
660 case UC_CHANGE:
661 break;
662 default:
663 userconf_cnt = -1;
664 break;
665 }
666 }
667
668 void
669 userconf_add_read(prompt, field, dev, len, val)
670 char *prompt;
671 char field;
672 char *dev;
673 int len;
674 int *val;
675 {
676 int ok = 0;
677 int a;
678 char *c;
679 int i;
680
681 *val = -1;
682
683 while (!ok) {
684 printf("%s ? ", prompt);
685
686 i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
687
688 c = userconf_argbuf;
689 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
690
691 if (*c != '\0') {
692 if (userconf_number(c, &a) == 0) {
693 if (a > userconf_maxdev) {
694 printf("Unknown devno (max is %d)\n",
695 userconf_maxdev);
696 } else if (strncasecmp(dev,
697 cfdata[a].cf_driver->cd_name, len) != 0 &&
698 field == 'a') {
699 printf("Not same device type\n");
700 } else {
701 *val = a;
702 ok = 1;
703 }
704 } else if (*c == '?') {
705 userconf_common_dev(dev, len, 0,
706 FSTATE_FOUND, UC_FIND);
707 } else if (*c == 'q' || *c == 'Q') {
708 ok = 1;
709 } else {
710 printf("Unknown argument\n");
711 }
712 } else {
713 ok = 1;
714 }
715 }
716 }
717
718 int
719 userconf_parse(cmd)
720 char *cmd;
721 {
722 char *c, *v;
723 int i = 0, j = 0, k, a;
724 short unit, state;
725
726 c = cmd;
727 while (*c == ' ' || *c == '\t')
728 c++;
729 v = c;
730 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
731 c++;
732 i++;
733 }
734
735 k = -1;
736 while (*userconf_cmds[j] != '\0') {
737 if (strlen(userconf_cmds[j]) == i) {
738 if (strncasecmp(v, userconf_cmds[j], i) == 0)
739 k = j;
740 }
741 j += 2;
742 }
743
744 while (*c == ' ' || *c == '\t' || *c == '\n')
745 c++;
746
747 if (k == -1) {
748 if (*v != '\n')
749 printf("Unknown command, try help\n");
750 } else {
751 switch (*userconf_cmds[k+1]) {
752 case 'L':
753 if (*c == '\0')
754 printf("Argument expected\n");
755 else if (userconf_number(c, &a) == 0)
756 userconf_lines = a;
757 else
758 printf("Unknown argument\n");
759 break;
760 case 'b':
761 if (*c == '\0')
762 printf("8|10|16 expected\n");
763 else if (userconf_number(c, &a) == 0) {
764 if (a == 8 || a == 10 || a == 16) {
765 userconf_base = a;
766 } else {
767 printf("8|10|16 expected\n");
768 }
769 } else
770 printf("Unknown argument\n");
771 break;
772 case 'c':
773 if (*c == '\0')
774 printf("DevNo or Dev expected\n");
775 else if (userconf_number(c, &a) == 0)
776 userconf_change(a);
777 else if (userconf_device(c, &a, &unit, &state) == 0)
778 userconf_common_dev(c, a, unit, state, UC_CHANGE);
779 else
780 printf("Unknown argument\n");
781 break;
782 case 'd':
783 if (*c == '\0')
784 printf("Attr, DevNo or Dev expected\n");
785 else if (userconf_number(c, &a) == 0)
786 userconf_disable(a);
787 else if (userconf_device(c, &a, &unit, &state) == 0)
788 userconf_common_dev(c, a, unit, state, UC_DISABLE);
789 else
790 printf("Unknown argument\n");
791 break;
792 case 'e':
793 if (*c == '\0')
794 printf("Attr, DevNo or Dev expected\n");
795 else if (userconf_number(c, &a) == 0)
796 userconf_enable(a);
797 else if (userconf_device(c, &a, &unit, &state) == 0)
798 userconf_common_dev(c, a, unit, state, UC_ENABLE);
799 else
800 printf("Unknown argument\n");
801 break;
802 case 'f':
803 if (*c == '\0')
804 printf("DevNo or Dev expected\n");
805 else if (userconf_number(c, &a) == 0)
806 userconf_pdev(a);
807 else if (userconf_device(c, &a, &unit, &state) == 0)
808 userconf_common_dev(c, a, unit, state, UC_FIND);
809 else
810 printf("Unknown argument\n");
811 break;
812 case 'h':
813 userconf_help();
814 break;
815 case 'l':
816 if (*c == '\0')
817 userconf_list();
818 else
819 printf("Unknown argument\n");
820 break;
821 case 'q':
822 /* XXX add cmd 'q' eoc */
823 userconf_hist_cmd('q');
824 userconf_hist_eoc();
825 return(-1);
826 break;
827 case 's':
828 default:
829 printf("Unknown command\n");
830 break;
831 }
832 }
833 return(0);
834 }
835
836 extern void user_config __P((void));
837
838 void
839 user_config()
840 {
841 char prompt[] = "uc> ";
842
843 userconf_init();
844 printf("userconf: configure system autoconfiguration:\n");
845
846 while (1) {
847 printf(prompt);
848 if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
849 userconf_parse(userconf_cmdbuf))
850 break;
851 }
852 printf("Continuing...\n");
853 }
854
855 /*
856 * XXX shouldn't this be a common function?
857 */
858 static int
859 getsn(cp, size)
860 char *cp;
861 int size;
862 {
863 char *lp;
864 int c, len;
865
866 cnpollc(1);
867
868 lp = cp;
869 len = 0;
870 for (;;) {
871 c = cngetc();
872 switch (c) {
873 case '\n':
874 case '\r':
875 printf("\n");
876 *lp++ = '\0';
877 cnpollc(0);
878 return (len);
879 case '\b':
880 case '\177':
881 case '#':
882 if (len) {
883 --len;
884 --lp;
885 printf("\b \b");
886 }
887 continue;
888 case '@':
889 case 'u'&037:
890 len = 0;
891 lp = cp;
892 printf("\n");
893 continue;
894 default:
895 if (len + 1 >= size || c < ' ') {
896 printf("\007");
897 continue;
898 }
899 printf("%c", c);
900 ++len;
901 *lp++ = c;
902 }
903 }
904 }
905