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