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