1 /* $NetBSD: subr_userconf.c,v 1.11 2004/03/23 13:22:04 junyoung Exp $ */
2
3 /*
4 * Copyright (c) 1996 Mats O Jansson <moj@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 <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: subr_userconf.c,v 1.11 2004/03/23 13:22:04 junyoung Exp $");
39
40 #include "opt_userconf.h"
41
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>
47
48 #include <dev/cons.h>
49
50 extern struct cfdata cfdata[];
51
52 int userconf_base = 16; /* Base for "large" numbers */
53 int userconf_maxdev = -1; /* # of used device slots */
54 int userconf_totdev = -1; /* # of device slots */
55 int userconf_maxlocnames = -1; /* # of locnames */
56 int userconf_cnt = -1; /* Line counter for ... */
57 int userconf_lines = 12; /* ... # of lines per page */
58 int userconf_histlen = 0;
59 int userconf_histcur = 0;
60 char userconf_history[1024];
61 int userconf_histsz = sizeof(userconf_history);
62 char userconf_argbuf[40]; /* Additional input */
63 char userconf_cmdbuf[40]; /* Command line */
64 char userconf_histbuf[40];
65
66 void userconf_init(void);
67 int userconf_more(void);
68 void userconf_modify(const char *, int*);
69 void userconf_hist_cmd(char);
70 void userconf_hist_int(int);
71 void userconf_hist_eoc(void);
72 void userconf_pnum(int);
73 void userconf_pdevnam(short);
74 void userconf_pdev(short);
75 int userconf_number(char *, int *);
76 int userconf_device(char *, int *, short *, short *);
77 void userconf_change(int);
78 void userconf_disable(int);
79 void userconf_enable(int);
80 void userconf_help(void);
81 void userconf_list(void);
82 void userconf_common_dev(char *, int, short, short, char);
83 void userconf_add_read(char *, char, char *, int, int *);
84 int userconf_parse(char *);
85
86 static int getsn(char *, int);
87
88 #define UC_CHANGE 'c'
89 #define UC_DISABLE 'd'
90 #define UC_ENABLE 'e'
91 #define UC_FIND 'f'
92 #define UC_SHOW 's'
93
94 char *userconf_cmds[] = {
95 "base", "b",
96 "change", "c",
97 "disable", "d",
98 "enable", "e",
99 "exit", "q",
100 "find", "f",
101 "help", "h",
102 "list", "l",
103 "lines", "L",
104 "quit", "q",
105 "?", "h",
106 "", "",
107 };
108
109 void
110 userconf_init()
111 {
112 int i;
113 struct cfdata *cf;
114
115 i = 0;
116 for (cf = cfdata; cf->cf_name; cf++)
117 i++;
118
119 userconf_maxdev = i - 1;
120 userconf_totdev = i - 1;
121 }
122
123 int
124 userconf_more()
125 {
126 int quit = 0;
127 char c = '\0';
128
129 if (userconf_cnt != -1) {
130 if (userconf_cnt == userconf_lines) {
131 printf("-- more --");
132 c = cngetc();
133 userconf_cnt = 0;
134 printf("\r \r");
135 }
136 userconf_cnt++;
137 if (c == 'q' || c == 'Q')
138 quit = 1;
139 }
140 return (quit);
141 }
142
143 void
144 userconf_hist_cmd(cmd)
145 char cmd;
146 {
147 userconf_histcur = userconf_histlen;
148 if (userconf_histcur < userconf_histsz) {
149 userconf_history[userconf_histcur] = cmd;
150 userconf_histcur++;
151 }
152 }
153
154 void
155 userconf_hist_int(val)
156 int val;
157 {
158 sprintf(userconf_histbuf," %d",val);
159 if ((userconf_histcur + strlen(userconf_histbuf)) < userconf_histsz) {
160 memcpy(&userconf_history[userconf_histcur],
161 userconf_histbuf,
162 strlen(userconf_histbuf));
163 userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
164 }
165 }
166
167 void
168 userconf_hist_eoc()
169 {
170 if (userconf_histcur < userconf_histsz) {
171 userconf_history[userconf_histcur] = '\n';
172 userconf_histcur++;
173 userconf_histlen = userconf_histcur;
174 }
175 }
176
177 void
178 userconf_pnum(val)
179 int val;
180 {
181 if (val > -2 && val < 16) {
182 printf("%d",val);
183 } else {
184 switch (userconf_base) {
185 case 8:
186 printf("0%o",val);
187 break;
188 case 10:
189 printf("%d",val);
190 break;
191 case 16:
192 default:
193 printf("0x%x",val);
194 break;
195 }
196 }
197 }
198
199 void
200 userconf_pdevnam(dev)
201 short dev;
202 {
203 struct cfdata *cd;
204
205 cd = &cfdata[dev];
206 printf("%s", cd->cf_name);
207 switch (cd->cf_fstate) {
208 case FSTATE_NOTFOUND:
209 case FSTATE_DNOTFOUND:
210 printf("%d", cd->cf_unit);
211 break;
212 case FSTATE_FOUND:
213 printf("*FOUND*");
214 break;
215 case FSTATE_STAR:
216 case FSTATE_DSTAR:
217 printf("*");
218 break;
219 default:
220 printf("*UNKNOWN*");
221 break;
222 }
223 }
224
225 void
226 userconf_pdev(devno)
227 short devno;
228 {
229 struct cfdata *cd;
230 const struct cfparent *cfp;
231 int *l;
232 const char * const *ln;
233
234 if (devno > userconf_maxdev) {
235 printf("Unknown devno (max is %d)\n", userconf_maxdev);
236 return;
237 }
238
239 cd = &cfdata[devno];
240
241 printf("[%3d] ", devno);
242 userconf_pdevnam(devno);
243 printf(" at");
244 cfp = cd->cf_pspec;
245 if (cfp == NULL)
246 printf(" root");
247 else if (cfp->cfp_parent != NULL && cfp->cfp_unit != -1)
248 printf(" %s%d", cfp->cfp_parent, cfp->cfp_unit);
249 else
250 printf(" %s?", cfp->cfp_parent != NULL ? cfp->cfp_parent
251 : cfp->cfp_iattr);
252 switch (cd->cf_fstate) {
253 case FSTATE_NOTFOUND:
254 case FSTATE_FOUND:
255 case FSTATE_STAR:
256 break;
257 case FSTATE_DNOTFOUND:
258 case FSTATE_DSTAR:
259 printf(" disable");
260 break;
261 default:
262 printf(" ???");
263 break;
264 }
265 l = cd->cf_loc;
266 ln = cd->cf_locnames;
267 while (ln && *ln) {
268 printf(" %s ", *ln++);
269 userconf_pnum(*l++);
270 }
271 printf("\n");
272 }
273
274 int
275 userconf_number(c, val)
276 char *c;
277 int *val;
278 {
279 u_int num = 0;
280 int neg = 0;
281 int base = 10;
282
283 if (*c == '-') {
284 neg = 1;
285 c++;
286 }
287 if (*c == '') {
288 base = 8;
289 c++;
290 if (*c == 'x' || *c == 'X') {
291 base = 16;
292 c++;
293 }
294 }
295 while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
296 u_char cc = *c;
297
298 if (cc >= '' && cc <= '9')
299 cc = cc - '';
300 else if (cc >= 'a' && cc <= 'f')
301 cc = cc - 'a' + 10;
302 else if (cc >= 'A' && cc <= 'F')
303 cc = cc - 'A' + 10;
304 else
305 return (-1);
306
307 if (cc > base)
308 return (-1);
309 num = num * base + cc;
310 c++;
311 }
312
313 if (neg && num > INT_MAX) /* overflow */
314 return (1);
315 *val = neg ? - num : num;
316 return (0);
317 }
318
319 int
320 userconf_device(cmd, len, unit, state)
321 char *cmd;
322 int *len;
323 short *unit, *state;
324 {
325 short u = 0, s = FSTATE_FOUND;
326 int l = 0;
327 char *c;
328
329 c = cmd;
330 while (*c >= 'a' && *c <= 'z') {
331 l++;
332 c++;
333 }
334 if (*c == '*') {
335 s = FSTATE_STAR;
336 c++;
337 } else {
338 while (*c >= '' && *c <= '9') {
339 s = FSTATE_NOTFOUND;
340 u = u*10 + *c - '';
341 c++;
342 }
343 }
344 while (*c == ' ' || *c == '\t' || *c == '\n')
345 c++;
346
347 if (*c == '\0') {
348 *len = l;
349 *unit = u;
350 *state = s;
351 return(0);
352 }
353
354 return(-1);
355 }
356
357 void
358 userconf_modify(item, val)
359 const char *item;
360 int *val;
361 {
362 int ok = 0;
363 int a;
364 char *c;
365
366 while (!ok) {
367 printf("%s [", item);
368 userconf_pnum(*val);
369 printf("] ? ");
370
371 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 * const *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_name != NULL) {
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_name != NULL) {
607 if (strlen(cfdata[i].cf_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_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
671 *val = -1;
672
673 while (!ok) {
674 printf("%s ? ", prompt);
675
676 getsn(userconf_argbuf, sizeof(userconf_argbuf));
677
678 c = userconf_argbuf;
679 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
680
681 if (*c != '\0') {
682 if (userconf_number(c, &a) == 0) {
683 if (a > userconf_maxdev) {
684 printf("Unknown devno (max is %d)\n",
685 userconf_maxdev);
686 } else if (strncasecmp(dev,
687 cfdata[a].cf_name, len) != 0 &&
688 field == 'a') {
689 printf("Not same device type\n");
690 } else {
691 *val = a;
692 ok = 1;
693 }
694 } else if (*c == '?') {
695 userconf_common_dev(dev, len, 0,
696 FSTATE_FOUND, UC_FIND);
697 } else if (*c == 'q' || *c == 'Q') {
698 ok = 1;
699 } else {
700 printf("Unknown argument\n");
701 }
702 } else {
703 ok = 1;
704 }
705 }
706 }
707
708 int
709 userconf_parse(cmd)
710 char *cmd;
711 {
712 char *c, *v;
713 int i = 0, j = 0, k, a;
714 short unit, state;
715
716 c = cmd;
717 while (*c == ' ' || *c == '\t')
718 c++;
719 v = c;
720 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
721 c++;
722 i++;
723 }
724
725 k = -1;
726 while (*userconf_cmds[j] != '\0') {
727 if (strlen(userconf_cmds[j]) == i) {
728 if (strncasecmp(v, userconf_cmds[j], i) == 0)
729 k = j;
730 }
731 j += 2;
732 }
733
734 while (*c == ' ' || *c == '\t' || *c == '\n')
735 c++;
736
737 if (k == -1) {
738 if (*v != '\n')
739 printf("Unknown command, try help\n");
740 } else {
741 switch (*userconf_cmds[k+1]) {
742 case 'L':
743 if (*c == '\0')
744 printf("Argument expected\n");
745 else if (userconf_number(c, &a) == 0)
746 userconf_lines = a;
747 else
748 printf("Unknown argument\n");
749 break;
750 case 'b':
751 if (*c == '\0')
752 printf("8|10|16 expected\n");
753 else if (userconf_number(c, &a) == 0) {
754 if (a == 8 || a == 10 || a == 16) {
755 userconf_base = a;
756 } else {
757 printf("8|10|16 expected\n");
758 }
759 } else
760 printf("Unknown argument\n");
761 break;
762 case 'c':
763 if (*c == '\0')
764 printf("DevNo or Dev expected\n");
765 else if (userconf_number(c, &a) == 0)
766 userconf_change(a);
767 else if (userconf_device(c, &a, &unit, &state) == 0)
768 userconf_common_dev(c, a, unit, state, UC_CHANGE);
769 else
770 printf("Unknown argument\n");
771 break;
772 case 'd':
773 if (*c == '\0')
774 printf("Attr, DevNo or Dev expected\n");
775 else if (userconf_number(c, &a) == 0)
776 userconf_disable(a);
777 else if (userconf_device(c, &a, &unit, &state) == 0)
778 userconf_common_dev(c, a, unit, state, UC_DISABLE);
779 else
780 printf("Unknown argument\n");
781 break;
782 case 'e':
783 if (*c == '\0')
784 printf("Attr, DevNo or Dev expected\n");
785 else if (userconf_number(c, &a) == 0)
786 userconf_enable(a);
787 else if (userconf_device(c, &a, &unit, &state) == 0)
788 userconf_common_dev(c, a, unit, state, UC_ENABLE);
789 else
790 printf("Unknown argument\n");
791 break;
792 case 'f':
793 if (*c == '\0')
794 printf("DevNo or Dev expected\n");
795 else if (userconf_number(c, &a) == 0)
796 userconf_pdev(a);
797 else if (userconf_device(c, &a, &unit, &state) == 0)
798 userconf_common_dev(c, a, unit, state, UC_FIND);
799 else
800 printf("Unknown argument\n");
801 break;
802 case 'h':
803 userconf_help();
804 break;
805 case 'l':
806 if (*c == '\0')
807 userconf_list();
808 else
809 printf("Unknown argument\n");
810 break;
811 case 'q':
812 /* XXX add cmd 'q' eoc */
813 userconf_hist_cmd('q');
814 userconf_hist_eoc();
815 return(-1);
816 case 's':
817 default:
818 printf("Unknown command\n");
819 break;
820 }
821 }
822 return(0);
823 }
824
825 extern void user_config(void);
826
827 void
828 user_config()
829 {
830 char prompt[] = "uc> ";
831
832 userconf_init();
833 printf("userconf: configure system autoconfiguration:\n");
834
835 while (1) {
836 printf(prompt);
837 if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
838 userconf_parse(userconf_cmdbuf))
839 break;
840 }
841 printf("Continuing...\n");
842 }
843
844 /*
845 * XXX shouldn't this be a common function?
846 */
847 static int
848 getsn(cp, size)
849 char *cp;
850 int size;
851 {
852 char *lp;
853 int c, len;
854
855 cnpollc(1);
856
857 lp = cp;
858 len = 0;
859 for (;;) {
860 c = cngetc();
861 switch (c) {
862 case '\n':
863 case '\r':
864 printf("\n");
865 *lp++ = '\0';
866 cnpollc(0);
867 return (len);
868 case '\b':
869 case '\177':
870 case '#':
871 if (len) {
872 --len;
873 --lp;
874 printf("\b \b");
875 }
876 continue;
877 case '@':
878 case 'u'&037:
879 len = 0;
880 lp = cp;
881 printf("\n");
882 continue;
883 default:
884 if (len + 1 >= size || c < ' ') {
885 printf("\007");
886 continue;
887 }
888 printf("%c", c);
889 ++len;
890 *lp++ = c;
891 }
892 }
893 }
Cache object: e174887e8f4b3cb1e6ce39fbe6eb6b32
|