Mark up sysctl node with Li, like in sysctl(7).
[netbsd-mini2440.git] / sys / kern / subr_userconf.c
blobe9742e4aae13982c6b5c37a45f8ae04809b49bee
1 /* $NetBSD: subr_userconf.c,v 1.10.6.5 2005/11/10 14:09:45 skrll 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.
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.
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.
34 * OpenBSD: subr_userconf.c,v 1.19 2000/01/08 23:23:37 d Exp
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: subr_userconf.c,v 1.10.6.5 2005/11/10 14:09:45 skrll Exp $");
40 #include "opt_userconf.h"
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>
48 #include <dev/cons.h>
50 extern struct cfdata cfdata[];
52 static int userconf_base = 16; /* Base for "large" numbers */
53 static int userconf_maxdev = -1; /* # of used device slots */
54 static int userconf_totdev = -1; /* # of device slots */
55 #if 0
56 static int userconf_maxlocnames = -1; /* # of locnames */
57 #endif
58 static int userconf_cnt = -1; /* Line counter for ... */
59 static int userconf_lines = 12; /* ... # of lines per page */
60 static int userconf_histlen = 0;
61 static int userconf_histcur = 0;
62 static char userconf_history[1024];
63 static int userconf_histsz = sizeof(userconf_history);
64 static char userconf_argbuf[40]; /* Additional input */
65 static char userconf_cmdbuf[40]; /* Command line */
66 static char userconf_histbuf[40];
68 static int getsn(char *, int);
70 #define UC_CHANGE 'c'
71 #define UC_DISABLE 'd'
72 #define UC_ENABLE 'e'
73 #define UC_FIND 'f'
74 #define UC_SHOW 's'
76 static const char *userconf_cmds[] = {
77 "base", "b",
78 "change", "c",
79 "disable", "d",
80 "enable", "e",
81 "exit", "q",
82 "find", "f",
83 "help", "h",
84 "list", "l",
85 "lines", "L",
86 "quit", "q",
87 "?", "h",
88 "", "",
91 static void
92 userconf_init(void)
94 int i;
95 struct cfdata *cf;
97 i = 0;
98 for (cf = cfdata; cf->cf_name; cf++)
99 i++;
101 userconf_maxdev = i - 1;
102 userconf_totdev = i - 1;
105 static int
106 userconf_more(void)
108 int quit = 0;
109 char c = '\0';
111 if (userconf_cnt != -1) {
112 if (userconf_cnt == userconf_lines) {
113 printf("-- more --");
114 c = cngetc();
115 userconf_cnt = 0;
116 printf("\r \r");
118 userconf_cnt++;
119 if (c == 'q' || c == 'Q')
120 quit = 1;
122 return (quit);
125 static void
126 userconf_hist_cmd(char cmd)
128 userconf_histcur = userconf_histlen;
129 if (userconf_histcur < userconf_histsz) {
130 userconf_history[userconf_histcur] = cmd;
131 userconf_histcur++;
135 static void
136 userconf_hist_int(int val)
138 snprintf(userconf_histbuf, sizeof(userconf_histbuf), " %d", val);
139 if ((userconf_histcur + strlen(userconf_histbuf)) < userconf_histsz) {
140 memcpy(&userconf_history[userconf_histcur],
141 userconf_histbuf,
142 strlen(userconf_histbuf));
143 userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
147 static void
148 userconf_hist_eoc(void)
150 if (userconf_histcur < userconf_histsz) {
151 userconf_history[userconf_histcur] = '\n';
152 userconf_histcur++;
153 userconf_histlen = userconf_histcur;
157 static void
158 userconf_pnum(int val)
160 if (val > -2 && val < 16) {
161 printf("%d",val);
162 } else {
163 switch (userconf_base) {
164 case 8:
165 printf("0%o",val);
166 break;
167 case 10:
168 printf("%d",val);
169 break;
170 case 16:
171 default:
172 printf("0x%x",val);
173 break;
178 static void
179 userconf_pdevnam(short dev)
181 struct cfdata *cd;
183 cd = &cfdata[dev];
184 printf("%s", cd->cf_name);
185 switch (cd->cf_fstate) {
186 case FSTATE_NOTFOUND:
187 case FSTATE_DNOTFOUND:
188 printf("%d", cd->cf_unit);
189 break;
190 case FSTATE_FOUND:
191 printf("*FOUND*");
192 break;
193 case FSTATE_STAR:
194 case FSTATE_DSTAR:
195 printf("*");
196 break;
197 default:
198 printf("*UNKNOWN*");
199 break;
203 static void
204 userconf_pdev(short devno)
206 struct cfdata *cd;
207 const struct cfparent *cfp;
208 int *l;
209 const struct cfiattrdata *ia;
210 const struct cflocdesc *ld;
211 int nld, i;
213 if (devno > userconf_maxdev) {
214 printf("Unknown devno (max is %d)\n", userconf_maxdev);
215 return;
218 cd = &cfdata[devno];
220 printf("[%3d] ", devno);
221 userconf_pdevnam(devno);
222 printf(" at");
223 cfp = cd->cf_pspec;
224 if (cfp == NULL)
225 printf(" root");
226 else if (cfp->cfp_parent != NULL && cfp->cfp_unit != -1)
227 printf(" %s%d", cfp->cfp_parent, cfp->cfp_unit);
228 else
229 printf(" %s?", cfp->cfp_parent != NULL ? cfp->cfp_parent
230 : cfp->cfp_iattr);
231 switch (cd->cf_fstate) {
232 case FSTATE_NOTFOUND:
233 case FSTATE_FOUND:
234 case FSTATE_STAR:
235 break;
236 case FSTATE_DNOTFOUND:
237 case FSTATE_DSTAR:
238 printf(" disable");
239 break;
240 default:
241 printf(" ???");
242 break;
244 if (cfp) {
245 l = cd->cf_loc;
246 ia = cfiattr_lookup(cfp->cfp_iattr, 0);
247 KASSERT(ia);
248 ld = ia->ci_locdesc;
249 nld = ia->ci_loclen;
250 for (i = 0; i < nld; i++) {
251 printf(" %s ", ld[i].cld_name);
252 if (!ld[i].cld_defaultstr
253 || (l[i] != ld[i].cld_default))
254 userconf_pnum(l[i]);
255 else
256 printf("?");
259 printf("\n");
262 static int
263 userconf_number(char *c, int *val)
265 u_int num = 0;
266 int neg = 0;
267 int base = 10;
269 if (*c == '-') {
270 neg = 1;
271 c++;
273 if (*c == '0') {
274 base = 8;
275 c++;
276 if (*c == 'x' || *c == 'X') {
277 base = 16;
278 c++;
281 while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
282 u_char cc = *c;
284 if (cc >= '0' && cc <= '9')
285 cc = cc - '0';
286 else if (cc >= 'a' && cc <= 'f')
287 cc = cc - 'a' + 10;
288 else if (cc >= 'A' && cc <= 'F')
289 cc = cc - 'A' + 10;
290 else
291 return (-1);
293 if (cc > base)
294 return (-1);
295 num = num * base + cc;
296 c++;
299 if (neg && num > INT_MAX) /* overflow */
300 return (1);
301 *val = neg ? - num : num;
302 return (0);
305 static int
306 userconf_device(char *cmd, int *len, short *unit, short *state)
308 short u = 0, s = FSTATE_FOUND;
309 int l = 0;
310 char *c;
312 c = cmd;
313 while (*c >= 'a' && *c <= 'z') {
314 l++;
315 c++;
317 if (*c == '*') {
318 s = FSTATE_STAR;
319 c++;
320 } else {
321 while (*c >= '0' && *c <= '9') {
322 s = FSTATE_NOTFOUND;
323 u = u*10 + *c - '0';
324 c++;
327 while (*c == ' ' || *c == '\t' || *c == '\n')
328 c++;
330 if (*c == '\0') {
331 *len = l;
332 *unit = u;
333 *state = s;
334 return(0);
337 return(-1);
340 static void
341 userconf_modify(const struct cflocdesc *item, int *val)
343 int ok = 0;
344 int a;
345 char *c;
347 while (!ok) {
348 printf("%s [", item->cld_name);
349 if (item->cld_defaultstr && (*val == item->cld_default))
350 printf("?");
351 else
352 userconf_pnum(*val);
353 printf("] ? ");
355 getsn(userconf_argbuf, sizeof(userconf_argbuf));
357 c = userconf_argbuf;
358 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
360 if (*c != '\0') {
361 if (*c == '?') {
362 if (item->cld_defaultstr) {
363 *val = item->cld_default;
364 ok = 1;
365 } else
366 printf("No default\n");
367 } else if (userconf_number(c, &a) == 0) {
368 *val = a;
369 ok = 1;
370 } else {
371 printf("Unknown argument\n");
373 } else {
374 ok = 1;
379 static void
380 userconf_change(int devno)
382 struct cfdata *cd;
383 char c = '\0';
384 int *l;
385 int ln;
386 const struct cfiattrdata *ia;
387 const struct cflocdesc *ld;
388 int nld;
390 if (devno <= userconf_maxdev) {
392 userconf_pdev(devno);
394 while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
395 printf("change (y/n) ?");
396 c = cngetc();
397 printf("\n");
400 if (c == 'y' || c == 'Y') {
402 /* XXX add cmd 'c' <devno> */
403 userconf_hist_cmd('c');
404 userconf_hist_int(devno);
406 cd = &cfdata[devno];
407 l = cd->cf_loc;
408 ia = cfiattr_lookup(cd->cf_pspec->cfp_iattr, 0);
409 KASSERT(ia);
410 ld = ia->ci_locdesc;
411 nld = ia->ci_loclen;
413 for (ln = 0; ln < nld; ln++)
415 userconf_modify(&ld[ln], l);
417 /* XXX add *l */
418 userconf_hist_int(*l);
420 l++;
423 printf("[%3d] ", devno);
424 userconf_pdevnam(devno);
425 printf(" changed\n");
426 userconf_pdev(devno);
428 /* XXX add eoc */
429 userconf_hist_eoc();
432 } else {
433 printf("Unknown devno (max is %d)\n", userconf_maxdev);
437 static void
438 userconf_disable(int devno)
440 int done = 0;
442 if (devno <= userconf_maxdev) {
443 switch (cfdata[devno].cf_fstate) {
444 case FSTATE_NOTFOUND:
445 cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
446 break;
447 case FSTATE_STAR:
448 cfdata[devno].cf_fstate = FSTATE_DSTAR;
449 break;
450 case FSTATE_DNOTFOUND:
451 case FSTATE_DSTAR:
452 done = 1;
453 break;
454 default:
455 printf("Error unknown state\n");
456 break;
459 printf("[%3d] ", devno);
460 userconf_pdevnam(devno);
461 if (done) {
462 printf(" already");
463 } else {
464 /* XXX add cmd 'd' <devno> eoc */
465 userconf_hist_cmd('d');
466 userconf_hist_int(devno);
467 userconf_hist_eoc();
469 printf(" disabled\n");
470 } else {
471 printf("Unknown devno (max is %d)\n", userconf_maxdev);
475 static void
476 userconf_enable(int devno)
478 int done = 0;
480 if (devno <= userconf_maxdev) {
481 switch (cfdata[devno].cf_fstate) {
482 case FSTATE_DNOTFOUND:
483 cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
484 break;
485 case FSTATE_DSTAR:
486 cfdata[devno].cf_fstate = FSTATE_STAR;
487 break;
488 case FSTATE_NOTFOUND:
489 case FSTATE_STAR:
490 done = 1;
491 break;
492 default:
493 printf("Error unknown state\n");
494 break;
497 printf("[%3d] ", devno);
498 userconf_pdevnam(devno);
499 if (done) {
500 printf(" already");
501 } else {
502 /* XXX add cmd 'e' <devno> eoc */
503 userconf_hist_cmd('d');
504 userconf_hist_int(devno);
505 userconf_hist_eoc();
507 printf(" enabled\n");
508 } else {
509 printf("Unknown devno (max is %d)\n", userconf_maxdev);
513 static void
514 userconf_help(void)
516 int j = 0, k;
518 printf("command args description\n");
519 while (*userconf_cmds[j] != '\0') {
520 printf(userconf_cmds[j]);
521 k = strlen(userconf_cmds[j]);
522 while (k < 10) {
523 printf(" ");
524 k++;
526 switch (*userconf_cmds[j+1]) {
527 case 'L':
528 printf("[count] number of lines before more");
529 break;
530 case 'b':
531 printf("8|10|16 base on large numbers");
532 break;
533 case 'c':
534 printf("devno|dev change devices");
535 break;
536 case 'd':
537 printf("devno|dev disable devices");
538 break;
539 case 'e':
540 printf("devno|dev enable devices");
541 break;
542 case 'f':
543 printf("devno|dev find devices");
544 break;
545 case 'h':
546 printf(" this message");
547 break;
548 case 'l':
549 printf(" list configuration");
550 break;
551 case 'q':
552 printf(" leave userconf");
553 break;
554 default:
555 printf(" don't know");
556 break;
558 printf("\n");
559 j += 2;
563 static void
564 userconf_list(void)
566 int i = 0;
568 userconf_cnt = 0;
570 while (cfdata[i].cf_name != NULL) {
571 if (userconf_more())
572 break;
573 userconf_pdev(i++);
576 userconf_cnt = -1;
579 static void
580 userconf_common_dev(char *dev, int len, short unit, short state, char routine)
582 int i = 0;
584 switch (routine) {
585 case UC_CHANGE:
586 break;
587 default:
588 userconf_cnt = 0;
589 break;
592 while (cfdata[i].cf_name != NULL) {
593 if (strlen(cfdata[i].cf_name) == len) {
596 * Ok, if device name is correct
597 * If state == FSTATE_FOUND, look for "dev"
598 * If state == FSTATE_STAR, look for "dev*"
599 * If state == FSTATE_NOTFOUND, look for "dev0"
601 if (strncasecmp(dev, cfdata[i].cf_name,
602 len) == 0 &&
603 (state == FSTATE_FOUND ||
604 (state == FSTATE_STAR &&
605 (cfdata[i].cf_fstate == FSTATE_STAR ||
606 cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
607 (state == FSTATE_NOTFOUND &&
608 cfdata[i].cf_unit == unit &&
609 (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
610 cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
611 if (userconf_more())
612 break;
613 switch (routine) {
614 case UC_CHANGE:
615 userconf_change(i);
616 break;
617 case UC_ENABLE:
618 userconf_enable(i);
619 break;
620 case UC_DISABLE:
621 userconf_disable(i);
622 break;
623 case UC_FIND:
624 userconf_pdev(i);
625 break;
626 default:
627 printf("Unknown routine /%c/\n",
628 routine);
629 break;
633 i++;
636 switch (routine) {
637 case UC_CHANGE:
638 break;
639 default:
640 userconf_cnt = -1;
641 break;
645 #if 0
646 static void
647 userconf_add_read(char *prompt, char field, char *dev, int len, int *val)
649 int ok = 0;
650 int a;
651 char *c;
653 *val = -1;
655 while (!ok) {
656 printf("%s ? ", prompt);
658 getsn(userconf_argbuf, sizeof(userconf_argbuf));
660 c = userconf_argbuf;
661 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
663 if (*c != '\0') {
664 if (userconf_number(c, &a) == 0) {
665 if (a > userconf_maxdev) {
666 printf("Unknown devno (max is %d)\n",
667 userconf_maxdev);
668 } else if (strncasecmp(dev,
669 cfdata[a].cf_name, len) != 0 &&
670 field == 'a') {
671 printf("Not same device type\n");
672 } else {
673 *val = a;
674 ok = 1;
676 } else if (*c == '?') {
677 userconf_common_dev(dev, len, 0,
678 FSTATE_FOUND, UC_FIND);
679 } else if (*c == 'q' || *c == 'Q') {
680 ok = 1;
681 } else {
682 printf("Unknown argument\n");
684 } else {
685 ok = 1;
689 #endif /* 0 */
691 static int
692 userconf_parse(char *cmd)
694 char *c, *v;
695 int i = 0, j = 0, k, a;
696 short unit, state;
698 c = cmd;
699 while (*c == ' ' || *c == '\t')
700 c++;
701 v = c;
702 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
703 c++;
704 i++;
707 k = -1;
708 while (*userconf_cmds[j] != '\0') {
709 if (strlen(userconf_cmds[j]) == i) {
710 if (strncasecmp(v, userconf_cmds[j], i) == 0)
711 k = j;
713 j += 2;
716 while (*c == ' ' || *c == '\t' || *c == '\n')
717 c++;
719 if (k == -1) {
720 if (*v != '\n')
721 printf("Unknown command, try help\n");
722 } else {
723 switch (*userconf_cmds[k+1]) {
724 case 'L':
725 if (*c == '\0')
726 printf("Argument expected\n");
727 else if (userconf_number(c, &a) == 0)
728 userconf_lines = a;
729 else
730 printf("Unknown argument\n");
731 break;
732 case 'b':
733 if (*c == '\0')
734 printf("8|10|16 expected\n");
735 else if (userconf_number(c, &a) == 0) {
736 if (a == 8 || a == 10 || a == 16) {
737 userconf_base = a;
738 } else {
739 printf("8|10|16 expected\n");
741 } else
742 printf("Unknown argument\n");
743 break;
744 case 'c':
745 if (*c == '\0')
746 printf("DevNo or Dev expected\n");
747 else if (userconf_number(c, &a) == 0)
748 userconf_change(a);
749 else if (userconf_device(c, &a, &unit, &state) == 0)
750 userconf_common_dev(c, a, unit, state, UC_CHANGE);
751 else
752 printf("Unknown argument\n");
753 break;
754 case 'd':
755 if (*c == '\0')
756 printf("Attr, DevNo or Dev expected\n");
757 else if (userconf_number(c, &a) == 0)
758 userconf_disable(a);
759 else if (userconf_device(c, &a, &unit, &state) == 0)
760 userconf_common_dev(c, a, unit, state, UC_DISABLE);
761 else
762 printf("Unknown argument\n");
763 break;
764 case 'e':
765 if (*c == '\0')
766 printf("Attr, DevNo or Dev expected\n");
767 else if (userconf_number(c, &a) == 0)
768 userconf_enable(a);
769 else if (userconf_device(c, &a, &unit, &state) == 0)
770 userconf_common_dev(c, a, unit, state, UC_ENABLE);
771 else
772 printf("Unknown argument\n");
773 break;
774 case 'f':
775 if (*c == '\0')
776 printf("DevNo or Dev expected\n");
777 else if (userconf_number(c, &a) == 0)
778 userconf_pdev(a);
779 else if (userconf_device(c, &a, &unit, &state) == 0)
780 userconf_common_dev(c, a, unit, state, UC_FIND);
781 else
782 printf("Unknown argument\n");
783 break;
784 case 'h':
785 userconf_help();
786 break;
787 case 'l':
788 if (*c == '\0')
789 userconf_list();
790 else
791 printf("Unknown argument\n");
792 break;
793 case 'q':
794 /* XXX add cmd 'q' eoc */
795 userconf_hist_cmd('q');
796 userconf_hist_eoc();
797 return(-1);
798 case 's':
799 default:
800 printf("Unknown command\n");
801 break;
804 return(0);
807 extern void user_config(void);
809 void
810 user_config(void)
812 char prompt[] = "uc> ";
814 userconf_init();
815 printf("userconf: configure system autoconfiguration:\n");
817 while (1) {
818 printf(prompt);
819 if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
820 userconf_parse(userconf_cmdbuf))
821 break;
823 printf("Continuing...\n");
827 * XXX shouldn't this be a common function?
829 static int
830 getsn(char *cp, int size)
832 char *lp;
833 int c, len;
835 cnpollc(1);
837 lp = cp;
838 len = 0;
839 for (;;) {
840 c = cngetc();
841 switch (c) {
842 case '\n':
843 case '\r':
844 printf("\n");
845 *lp++ = '\0';
846 cnpollc(0);
847 return (len);
848 case '\b':
849 case '\177':
850 case '#':
851 if (len) {
852 --len;
853 --lp;
854 printf("\b \b");
856 continue;
857 case '@':
858 case 'u'&037:
859 len = 0;
860 lp = cp;
861 printf("\n");
862 continue;
863 default:
864 if (len + 1 >= size || c < ' ') {
865 printf("\007");
866 continue;
868 printf("%c", c);
869 ++len;
870 *lp++ = c;