No empty .Rs/.Re
[netbsd-mini2440.git] / sys / kern / subr_userconf.c
blob215dfded33ee7989bd628a581c1e3a642ef1cec1
1 /* $NetBSD: subr_userconf.c,v 1.18 2005/12/11 12:24:30 christos Exp $ */
3 /*
4 * Copyright (c) 1996 Mats O Jansson <moj@stacken.kth.se>
5 * All rights reserved.
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.
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.
28 * OpenBSD: subr_userconf.c,v 1.19 2000/01/08 23:23:37 d Exp
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: subr_userconf.c,v 1.18 2005/12/11 12:24:30 christos Exp $");
34 #include "opt_userconf.h"
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/time.h>
42 #include <dev/cons.h>
44 extern struct cfdata cfdata[];
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];
62 static int getsn(char *, int);
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'
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 "", "",
85 static void
86 userconf_init(void)
88 int i;
89 struct cfdata *cf;
91 i = 0;
92 for (cf = cfdata; cf->cf_name; cf++)
93 i++;
95 userconf_maxdev = i - 1;
96 userconf_totdev = i - 1;
99 static int
100 userconf_more(void)
102 int quit = 0;
103 char c = '\0';
105 if (userconf_cnt != -1) {
106 if (userconf_cnt == userconf_lines) {
107 printf("-- more --");
108 c = cngetc();
109 userconf_cnt = 0;
110 printf("\r \r");
112 userconf_cnt++;
113 if (c == 'q' || c == 'Q')
114 quit = 1;
116 return (quit);
119 static void
120 userconf_hist_cmd(char cmd)
122 userconf_histcur = userconf_histlen;
123 if (userconf_histcur < userconf_histsz) {
124 userconf_history[userconf_histcur] = cmd;
125 userconf_histcur++;
129 static void
130 userconf_hist_int(int val)
132 snprintf(userconf_histbuf, sizeof(userconf_histbuf), " %d", val);
133 if ((userconf_histcur + strlen(userconf_histbuf)) < userconf_histsz) {
134 memcpy(&userconf_history[userconf_histcur],
135 userconf_histbuf,
136 strlen(userconf_histbuf));
137 userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
141 static void
142 userconf_hist_eoc(void)
144 if (userconf_histcur < userconf_histsz) {
145 userconf_history[userconf_histcur] = '\n';
146 userconf_histcur++;
147 userconf_histlen = userconf_histcur;
151 static void
152 userconf_pnum(int val)
154 if (val > -2 && val < 16) {
155 printf("%d",val);
156 } else {
157 switch (userconf_base) {
158 case 8:
159 printf("0%o",val);
160 break;
161 case 10:
162 printf("%d",val);
163 break;
164 case 16:
165 default:
166 printf("0x%x",val);
167 break;
172 static void
173 userconf_pdevnam(short dev)
175 struct cfdata *cd;
177 cd = &cfdata[dev];
178 printf("%s", cd->cf_name);
179 switch (cd->cf_fstate) {
180 case FSTATE_NOTFOUND:
181 case FSTATE_DNOTFOUND:
182 printf("%d", cd->cf_unit);
183 break;
184 case FSTATE_FOUND:
185 printf("*FOUND*");
186 break;
187 case FSTATE_STAR:
188 case FSTATE_DSTAR:
189 printf("*");
190 break;
191 default:
192 printf("*UNKNOWN*");
193 break;
197 static void
198 userconf_pdev(short devno)
200 struct cfdata *cd;
201 const struct cfparent *cfp;
202 int *l;
203 const struct cfiattrdata *ia;
204 const struct cflocdesc *ld;
205 int nld, i;
207 if (devno > userconf_maxdev) {
208 printf("Unknown devno (max is %d)\n", userconf_maxdev);
209 return;
212 cd = &cfdata[devno];
214 printf("[%3d] ", devno);
215 userconf_pdevnam(devno);
216 printf(" at");
217 cfp = cd->cf_pspec;
218 if (cfp == NULL)
219 printf(" root");
220 else if (cfp->cfp_parent != NULL && cfp->cfp_unit != -1)
221 printf(" %s%d", cfp->cfp_parent, cfp->cfp_unit);
222 else
223 printf(" %s?", cfp->cfp_parent != NULL ? cfp->cfp_parent
224 : cfp->cfp_iattr);
225 switch (cd->cf_fstate) {
226 case FSTATE_NOTFOUND:
227 case FSTATE_FOUND:
228 case FSTATE_STAR:
229 break;
230 case FSTATE_DNOTFOUND:
231 case FSTATE_DSTAR:
232 printf(" disable");
233 break;
234 default:
235 printf(" ???");
236 break;
238 if (cfp) {
239 l = cd->cf_loc;
240 ia = cfiattr_lookup(cfp->cfp_iattr, 0);
241 KASSERT(ia);
242 ld = ia->ci_locdesc;
243 nld = ia->ci_loclen;
244 for (i = 0; i < nld; i++) {
245 printf(" %s ", ld[i].cld_name);
246 if (!ld[i].cld_defaultstr
247 || (l[i] != ld[i].cld_default))
248 userconf_pnum(l[i]);
249 else
250 printf("?");
253 printf("\n");
256 static int
257 userconf_number(char *c, int *val)
259 u_int num = 0;
260 int neg = 0;
261 int base = 10;
263 if (*c == '-') {
264 neg = 1;
265 c++;
267 if (*c == '0') {
268 base = 8;
269 c++;
270 if (*c == 'x' || *c == 'X') {
271 base = 16;
272 c++;
275 while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
276 u_char cc = *c;
278 if (cc >= '0' && cc <= '9')
279 cc = cc - '0';
280 else if (cc >= 'a' && cc <= 'f')
281 cc = cc - 'a' + 10;
282 else if (cc >= 'A' && cc <= 'F')
283 cc = cc - 'A' + 10;
284 else
285 return (-1);
287 if (cc > base)
288 return (-1);
289 num = num * base + cc;
290 c++;
293 if (neg && num > INT_MAX) /* overflow */
294 return (1);
295 *val = neg ? - num : num;
296 return (0);
299 static int
300 userconf_device(char *cmd, int *len, short *unit, short *state)
302 short u = 0, s = FSTATE_FOUND;
303 int l = 0;
304 char *c;
306 c = cmd;
307 while (*c >= 'a' && *c <= 'z') {
308 l++;
309 c++;
311 if (*c == '*') {
312 s = FSTATE_STAR;
313 c++;
314 } else {
315 while (*c >= '0' && *c <= '9') {
316 s = FSTATE_NOTFOUND;
317 u = u*10 + *c - '0';
318 c++;
321 while (*c == ' ' || *c == '\t' || *c == '\n')
322 c++;
324 if (*c == '\0') {
325 *len = l;
326 *unit = u;
327 *state = s;
328 return(0);
331 return(-1);
334 static void
335 userconf_modify(const struct cflocdesc *item, int *val)
337 int ok = 0;
338 int a;
339 char *c;
341 while (!ok) {
342 printf("%s [", item->cld_name);
343 if (item->cld_defaultstr && (*val == item->cld_default))
344 printf("?");
345 else
346 userconf_pnum(*val);
347 printf("] ? ");
349 getsn(userconf_argbuf, sizeof(userconf_argbuf));
351 c = userconf_argbuf;
352 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
354 if (*c != '\0') {
355 if (*c == '?') {
356 if (item->cld_defaultstr) {
357 *val = item->cld_default;
358 ok = 1;
359 } else
360 printf("No default\n");
361 } else if (userconf_number(c, &a) == 0) {
362 *val = a;
363 ok = 1;
364 } else {
365 printf("Unknown argument\n");
367 } else {
368 ok = 1;
373 static void
374 userconf_change(int devno)
376 struct cfdata *cd;
377 char c = '\0';
378 int *l;
379 int ln;
380 const struct cfiattrdata *ia;
381 const struct cflocdesc *ld;
382 int nld;
384 if (devno <= userconf_maxdev) {
386 userconf_pdev(devno);
388 while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
389 printf("change (y/n) ?");
390 c = cngetc();
391 printf("\n");
394 if (c == 'y' || c == 'Y') {
396 /* XXX add cmd 'c' <devno> */
397 userconf_hist_cmd('c');
398 userconf_hist_int(devno);
400 cd = &cfdata[devno];
401 l = cd->cf_loc;
402 ia = cfiattr_lookup(cd->cf_pspec->cfp_iattr, 0);
403 KASSERT(ia);
404 ld = ia->ci_locdesc;
405 nld = ia->ci_loclen;
407 for (ln = 0; ln < nld; ln++)
409 userconf_modify(&ld[ln], l);
411 /* XXX add *l */
412 userconf_hist_int(*l);
414 l++;
417 printf("[%3d] ", devno);
418 userconf_pdevnam(devno);
419 printf(" changed\n");
420 userconf_pdev(devno);
422 /* XXX add eoc */
423 userconf_hist_eoc();
426 } else {
427 printf("Unknown devno (max is %d)\n", userconf_maxdev);
431 static void
432 userconf_disable(int devno)
434 int done = 0;
436 if (devno <= userconf_maxdev) {
437 switch (cfdata[devno].cf_fstate) {
438 case FSTATE_NOTFOUND:
439 cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
440 break;
441 case FSTATE_STAR:
442 cfdata[devno].cf_fstate = FSTATE_DSTAR;
443 break;
444 case FSTATE_DNOTFOUND:
445 case FSTATE_DSTAR:
446 done = 1;
447 break;
448 default:
449 printf("Error unknown state\n");
450 break;
453 printf("[%3d] ", devno);
454 userconf_pdevnam(devno);
455 if (done) {
456 printf(" already");
457 } else {
458 /* XXX add cmd 'd' <devno> eoc */
459 userconf_hist_cmd('d');
460 userconf_hist_int(devno);
461 userconf_hist_eoc();
463 printf(" disabled\n");
464 } else {
465 printf("Unknown devno (max is %d)\n", userconf_maxdev);
469 static void
470 userconf_enable(int devno)
472 int done = 0;
474 if (devno <= userconf_maxdev) {
475 switch (cfdata[devno].cf_fstate) {
476 case FSTATE_DNOTFOUND:
477 cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
478 break;
479 case FSTATE_DSTAR:
480 cfdata[devno].cf_fstate = FSTATE_STAR;
481 break;
482 case FSTATE_NOTFOUND:
483 case FSTATE_STAR:
484 done = 1;
485 break;
486 default:
487 printf("Error unknown state\n");
488 break;
491 printf("[%3d] ", devno);
492 userconf_pdevnam(devno);
493 if (done) {
494 printf(" already");
495 } else {
496 /* XXX add cmd 'e' <devno> eoc */
497 userconf_hist_cmd('d');
498 userconf_hist_int(devno);
499 userconf_hist_eoc();
501 printf(" enabled\n");
502 } else {
503 printf("Unknown devno (max is %d)\n", userconf_maxdev);
507 static void
508 userconf_help(void)
510 int j = 0, k;
512 printf("command args description\n");
513 while (*userconf_cmds[j] != '\0') {
514 printf(userconf_cmds[j]);
515 k = strlen(userconf_cmds[j]);
516 while (k < 10) {
517 printf(" ");
518 k++;
520 switch (*userconf_cmds[j+1]) {
521 case 'L':
522 printf("[count] number of lines before more");
523 break;
524 case 'b':
525 printf("8|10|16 base on large numbers");
526 break;
527 case 'c':
528 printf("devno|dev change devices");
529 break;
530 case 'd':
531 printf("devno|dev disable devices");
532 break;
533 case 'e':
534 printf("devno|dev enable devices");
535 break;
536 case 'f':
537 printf("devno|dev find devices");
538 break;
539 case 'h':
540 printf(" this message");
541 break;
542 case 'l':
543 printf(" list configuration");
544 break;
545 case 'q':
546 printf(" leave userconf");
547 break;
548 default:
549 printf(" don't know");
550 break;
552 printf("\n");
553 j += 2;
557 static void
558 userconf_list(void)
560 int i = 0;
562 userconf_cnt = 0;
564 while (cfdata[i].cf_name != NULL) {
565 if (userconf_more())
566 break;
567 userconf_pdev(i++);
570 userconf_cnt = -1;
573 static void
574 userconf_common_dev(char *dev, int len, short unit, short state, char routine)
576 int i = 0;
578 switch (routine) {
579 case UC_CHANGE:
580 break;
581 default:
582 userconf_cnt = 0;
583 break;
586 while (cfdata[i].cf_name != NULL) {
587 if (strlen(cfdata[i].cf_name) == len) {
590 * Ok, if device name is correct
591 * If state == FSTATE_FOUND, look for "dev"
592 * If state == FSTATE_STAR, look for "dev*"
593 * If state == FSTATE_NOTFOUND, look for "dev0"
595 if (strncasecmp(dev, cfdata[i].cf_name,
596 len) == 0 &&
597 (state == FSTATE_FOUND ||
598 (state == FSTATE_STAR &&
599 (cfdata[i].cf_fstate == FSTATE_STAR ||
600 cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
601 (state == FSTATE_NOTFOUND &&
602 cfdata[i].cf_unit == unit &&
603 (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
604 cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
605 if (userconf_more())
606 break;
607 switch (routine) {
608 case UC_CHANGE:
609 userconf_change(i);
610 break;
611 case UC_ENABLE:
612 userconf_enable(i);
613 break;
614 case UC_DISABLE:
615 userconf_disable(i);
616 break;
617 case UC_FIND:
618 userconf_pdev(i);
619 break;
620 default:
621 printf("Unknown routine /%c/\n",
622 routine);
623 break;
627 i++;
630 switch (routine) {
631 case UC_CHANGE:
632 break;
633 default:
634 userconf_cnt = -1;
635 break;
639 #if 0
640 static void
641 userconf_add_read(char *prompt, char field, char *dev, int len, int *val)
643 int ok = 0;
644 int a;
645 char *c;
647 *val = -1;
649 while (!ok) {
650 printf("%s ? ", prompt);
652 getsn(userconf_argbuf, sizeof(userconf_argbuf));
654 c = userconf_argbuf;
655 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
657 if (*c != '\0') {
658 if (userconf_number(c, &a) == 0) {
659 if (a > userconf_maxdev) {
660 printf("Unknown devno (max is %d)\n",
661 userconf_maxdev);
662 } else if (strncasecmp(dev,
663 cfdata[a].cf_name, len) != 0 &&
664 field == 'a') {
665 printf("Not same device type\n");
666 } else {
667 *val = a;
668 ok = 1;
670 } else if (*c == '?') {
671 userconf_common_dev(dev, len, 0,
672 FSTATE_FOUND, UC_FIND);
673 } else if (*c == 'q' || *c == 'Q') {
674 ok = 1;
675 } else {
676 printf("Unknown argument\n");
678 } else {
679 ok = 1;
683 #endif /* 0 */
685 static int
686 userconf_parse(char *cmd)
688 char *c, *v;
689 int i = 0, j = 0, k, a;
690 short unit, state;
692 c = cmd;
693 while (*c == ' ' || *c == '\t')
694 c++;
695 v = c;
696 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
697 c++;
698 i++;
701 k = -1;
702 while (*userconf_cmds[j] != '\0') {
703 if (strlen(userconf_cmds[j]) == i) {
704 if (strncasecmp(v, userconf_cmds[j], i) == 0)
705 k = j;
707 j += 2;
710 while (*c == ' ' || *c == '\t' || *c == '\n')
711 c++;
713 if (k == -1) {
714 if (*v != '\n')
715 printf("Unknown command, try help\n");
716 } else {
717 switch (*userconf_cmds[k+1]) {
718 case 'L':
719 if (*c == '\0')
720 printf("Argument expected\n");
721 else if (userconf_number(c, &a) == 0)
722 userconf_lines = a;
723 else
724 printf("Unknown argument\n");
725 break;
726 case 'b':
727 if (*c == '\0')
728 printf("8|10|16 expected\n");
729 else if (userconf_number(c, &a) == 0) {
730 if (a == 8 || a == 10 || a == 16) {
731 userconf_base = a;
732 } else {
733 printf("8|10|16 expected\n");
735 } else
736 printf("Unknown argument\n");
737 break;
738 case 'c':
739 if (*c == '\0')
740 printf("DevNo or Dev expected\n");
741 else if (userconf_number(c, &a) == 0)
742 userconf_change(a);
743 else if (userconf_device(c, &a, &unit, &state) == 0)
744 userconf_common_dev(c, a, unit, state, UC_CHANGE);
745 else
746 printf("Unknown argument\n");
747 break;
748 case 'd':
749 if (*c == '\0')
750 printf("Attr, DevNo or Dev expected\n");
751 else if (userconf_number(c, &a) == 0)
752 userconf_disable(a);
753 else if (userconf_device(c, &a, &unit, &state) == 0)
754 userconf_common_dev(c, a, unit, state, UC_DISABLE);
755 else
756 printf("Unknown argument\n");
757 break;
758 case 'e':
759 if (*c == '\0')
760 printf("Attr, DevNo or Dev expected\n");
761 else if (userconf_number(c, &a) == 0)
762 userconf_enable(a);
763 else if (userconf_device(c, &a, &unit, &state) == 0)
764 userconf_common_dev(c, a, unit, state, UC_ENABLE);
765 else
766 printf("Unknown argument\n");
767 break;
768 case 'f':
769 if (*c == '\0')
770 printf("DevNo or Dev expected\n");
771 else if (userconf_number(c, &a) == 0)
772 userconf_pdev(a);
773 else if (userconf_device(c, &a, &unit, &state) == 0)
774 userconf_common_dev(c, a, unit, state, UC_FIND);
775 else
776 printf("Unknown argument\n");
777 break;
778 case 'h':
779 userconf_help();
780 break;
781 case 'l':
782 if (*c == '\0')
783 userconf_list();
784 else
785 printf("Unknown argument\n");
786 break;
787 case 'q':
788 /* XXX add cmd 'q' eoc */
789 userconf_hist_cmd('q');
790 userconf_hist_eoc();
791 return(-1);
792 case 's':
793 default:
794 printf("Unknown command\n");
795 break;
798 return(0);
801 extern void user_config(void);
803 void
804 user_config(void)
806 char prompt[] = "uc> ";
808 userconf_init();
809 printf("userconf: configure system autoconfiguration:\n");
811 while (1) {
812 printf(prompt);
813 if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
814 userconf_parse(userconf_cmdbuf))
815 break;
817 printf("Continuing...\n");
821 * XXX shouldn't this be a common function?
823 static int
824 getsn(char *cp, int size)
826 char *lp;
827 int c, len;
829 cnpollc(1);
831 lp = cp;
832 len = 0;
833 for (;;) {
834 c = cngetc();
835 switch (c) {
836 case '\n':
837 case '\r':
838 printf("\n");
839 *lp++ = '\0';
840 cnpollc(0);
841 return (len);
842 case '\b':
843 case '\177':
844 case '#':
845 if (len) {
846 --len;
847 --lp;
848 printf("\b \b");
850 continue;
851 case '@':
852 case 'u'&037:
853 len = 0;
854 lp = cp;
855 printf("\n");
856 continue;
857 default:
858 if (len + 1 >= size || c < ' ') {
859 printf("\007");
860 continue;
862 printf("%c", c);
863 ++len;
864 *lp++ = c;