1 /* $OpenBSD: subr_userconf.c,v 1.48 2022/08/14 01:58:28 jsg Exp $ */
2
3 /*
4 * Copyright (c) 1996-2001 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
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/malloc.h>
33
34 #include <dev/cons.h>
35
36 extern char *locnames[];
37 extern short locnamp[];
38 extern short cfroots[];
39 extern int cfroots_size;
40 extern int pv_size;
41 extern short pv[];
42 extern char *pdevnames[];
43 extern int pdevnames_size;
44 extern struct pdevinit pdevinit[];
45
46 int userconf_base = 16; /* Base for "large" numbers */
47 int userconf_maxdev = -1; /* # of used device slots */
48 int userconf_totdev = -1; /* # of device slots */
49 int userconf_maxlocnames = -1; /* # of locnames */
50 int userconf_cnt = -1; /* Line counter for ... */
51 int userconf_lines = 12; /* ... # of lines per page */
52 int userconf_histlen = 0;
53 int userconf_histcur = 0;
54 char userconf_history[1024];
55 int userconf_histsz = sizeof(userconf_history);
56 char userconf_argbuf[40]; /* Additional input */
57 char userconf_cmdbuf[40]; /* Command line */
58 char userconf_histbuf[40];
59
60 void userconf_init(void);
61 int userconf_more(void);
62 void userconf_modify(char *, long *, long);
63 void userconf_hist_cmd(char);
64 void userconf_hist_int(long);
65 void userconf_hist_eoc(void);
66 void userconf_pnum(long);
67 void userconf_pdevnam(short);
68 void userconf_pdev(short);
69 int userconf_number(char *, long *, long);
70 int userconf_device(char *, long *, short *, short *);
71 int userconf_attr(char *, long *);
72 void userconf_change(int);
73 void userconf_disable(int);
74 void userconf_enable(int);
75 void userconf_help(void);
76 void userconf_list(void);
77 void userconf_show(void);
78 void userconf_common_attr_val(short, long *, char);
79 void userconf_show_attr(char *);
80 void userconf_common_dev(char *, int, short, short, char);
81 void userconf_common_attr(char *, int, char);
82 void userconf_add_read(char *, char, char *, int, long *);
83 void userconf_add(char *, int, short, short);
84 int userconf_parse(char *);
85
86 #define UC_CHANGE 'c'
87 #define UC_DISABLE 'd'
88 #define UC_ENABLE 'e'
89 #define UC_FIND 'f'
90 #define UC_SHOW 's'
91
92 char *userconf_cmds[] = {
93 "add", "a",
94 "base", "b",
95 "change", "c",
96 #if defined(DDB)
97 "ddb", "D",
98 #endif
99 "disable", "d",
100 "enable", "e",
101 "exit", "q",
102 "find", "f",
103 "help", "h",
104 "list", "l",
105 "lines", "L",
106 "quit", "q",
107 "show", "s",
108 "verbose", "v",
109 "?", "h",
110 "", "",
111 };
112
113 void
userconf_init(void)114 userconf_init(void)
115 {
116 int i = 0;
117 struct cfdata *cd;
118 int ln;
119
120 while (cfdata[i].cf_attach != NULL) {
121 userconf_maxdev = i;
122 userconf_totdev = i;
123
124 cd = &cfdata[i];
125 ln = cd->cf_locnames;
126 while (locnamp[ln] != -1) {
127 if (locnamp[ln] > userconf_maxlocnames)
128 userconf_maxlocnames = locnamp[ln];
129 ln++;
130 }
131 i++;
132 }
133
134 while (cfdata[i].cf_attach == NULL) {
135 userconf_totdev = i;
136 i++;
137 }
138 userconf_totdev = userconf_totdev - 1;
139 }
140
141 int
userconf_more(void)142 userconf_more(void)
143 {
144 int quit = 0;
145 char c = '\0';
146
147 if (userconf_cnt != -1) {
148 if (userconf_cnt == userconf_lines) {
149 printf("--- more ---");
150 c = cngetc();
151 userconf_cnt = 0;
152 printf("\r \r");
153 }
154 userconf_cnt++;
155 if (c == 'q' || c == 'Q')
156 quit = 1;
157 }
158 return (quit);
159 }
160
161 void
userconf_hist_cmd(char cmd)162 userconf_hist_cmd(char cmd)
163 {
164 userconf_histcur = userconf_histlen;
165 if (userconf_histcur < userconf_histsz) {
166 userconf_history[userconf_histcur] = cmd;
167 userconf_histcur++;
168 }
169 }
170
171 void
userconf_hist_int(long val)172 userconf_hist_int(long val)
173 {
174 snprintf(userconf_histbuf, sizeof userconf_histbuf, " %ld", val);
175 if (userconf_histcur + strlen(userconf_histbuf) < userconf_histsz) {
176 bcopy(userconf_histbuf,
177 &userconf_history[userconf_histcur],
178 strlen(userconf_histbuf));
179 userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
180 }
181 }
182
183 void
userconf_hist_eoc(void)184 userconf_hist_eoc(void)
185 {
186 if (userconf_histcur < userconf_histsz) {
187 userconf_history[userconf_histcur] = '\n';
188 userconf_histcur++;
189 userconf_histlen = userconf_histcur;
190 }
191 }
192
193 void
userconf_pnum(long val)194 userconf_pnum(long val)
195 {
196 if (val > -2 && val < 16) {
197 printf("%ld",val);
198 return;
199 }
200
201 switch (userconf_base) {
202 case 8:
203 printf("0%lo",val);
204 break;
205 case 10:
206 printf("%ld",val);
207 break;
208 case 16:
209 default:
210 printf("0x%lx",val);
211 break;
212 }
213 }
214
215 void
userconf_pdevnam(short dev)216 userconf_pdevnam(short dev)
217 {
218 struct cfdata *cd;
219
220 cd = &cfdata[dev];
221 printf("%s", cd->cf_driver->cd_name);
222 switch (cd->cf_fstate) {
223 case FSTATE_NOTFOUND:
224 case FSTATE_DNOTFOUND:
225 printf("%d", cd->cf_unit);
226 break;
227 case FSTATE_FOUND:
228 printf("*FOUND*");
229 break;
230 case FSTATE_STAR:
231 case FSTATE_DSTAR:
232 printf("*");
233 break;
234 default:
235 printf("*UNKNOWN*");
236 break;
237 }
238 }
239
240 void
userconf_pdev(short devno)241 userconf_pdev(short devno)
242 {
243 struct cfdata *cd;
244 short *p;
245 long *l;
246 int ln;
247 char c;
248
249 if (devno > userconf_maxdev && devno <= userconf_totdev) {
250 printf("%3d free slot (for add)\n", devno);
251 return;
252 }
253
254 if (devno > userconf_totdev &&
255 devno <= userconf_totdev+pdevnames_size) {
256 printf("%3d %s count %d", devno,
257 pdevnames[devno-userconf_totdev-1],
258 abs(pdevinit[devno-userconf_totdev-1].pdev_count));
259 if (pdevinit[devno-userconf_totdev-1].pdev_count < 1)
260 printf(" disable");
261 printf(" (pseudo device)\n");
262 return;
263 }
264
265 if (devno > userconf_maxdev) {
266 printf("Unknown devno (max is %d)\n", userconf_maxdev);
267 return;
268 }
269
270 cd = &cfdata[devno];
271
272 printf("%3d ", devno);
273 userconf_pdevnam(devno);
274 printf(" at");
275 c = ' ';
276 p = cd->cf_parents;
277 if (*p == -1)
278 printf(" root");
279 while (*p != -1) {
280 printf("%c", c);
281 userconf_pdevnam(*p++);
282 c = '|';
283 }
284 switch (cd->cf_fstate) {
285 case FSTATE_NOTFOUND:
286 case FSTATE_FOUND:
287 case FSTATE_STAR:
288 break;
289 case FSTATE_DNOTFOUND:
290 case FSTATE_DSTAR:
291 printf(" disable");
292 break;
293 default:
294 printf(" ???");
295 break;
296 }
297 l = cd->cf_loc;
298 ln = cd->cf_locnames;
299 while (locnamp[ln] != -1) {
300 printf(" %s ", locnames[locnamp[ln]]);
301 ln++;
302 userconf_pnum(*l++);
303 }
304 printf(" flags 0x%x\n", cd->cf_flags);
305 }
306
307 int
userconf_number(char * c,long * val,long limit)308 userconf_number(char *c, long *val, long limit)
309 {
310 u_long num = 0;
311 int neg = 0;
312 int base = 10;
313
314 if (*c == '-') {
315 neg = 1;
316 c++;
317 }
318 if (*c == '0') {
319 base = 8;
320 c++;
321 if (*c == 'x' || *c == 'X') {
322 base = 16;
323 c++;
324 }
325 }
326 while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
327 u_char cc = *c;
328
329 if (cc >= '0' && cc <= '9')
330 cc = cc - '0';
331 else if (cc >= 'a' && cc <= 'f')
332 cc = cc - 'a' + 10;
333 else if (cc >= 'A' && cc <= 'F')
334 cc = cc - 'A' + 10;
335 else
336 return (-1);
337
338 if (cc > base)
339 return (-1);
340 num = num * base + cc;
341 c++;
342 }
343
344 if (neg && num > limit) /* overflow */
345 return (1);
346 *val = neg ? - num : num;
347 return (0);
348 }
349
350 int
userconf_device(char * cmd,long * len,short * unit,short * state)351 userconf_device(char *cmd, long *len, short *unit, short *state)
352 {
353 short u = 0, s = FSTATE_FOUND;
354 int l = 0;
355 char *c;
356
357 c = cmd;
358 while (*c >= 'a' && *c <= 'z') {
359 l++;
360 c++;
361 }
362 if (*c == '*') {
363 s = FSTATE_STAR;
364 c++;
365 } else {
366 while (*c >= '0' && *c <= '9') {
367 s = FSTATE_NOTFOUND;
368 u = u*10 + *c - '0';
369 c++;
370 }
371 }
372 while (*c == ' ' || *c == '\t' || *c == '\n')
373 c++;
374
375 if (*c == '\0') {
376 *len = l;
377 *unit = u;
378 *state = s;
379 return(0);
380 }
381
382 return(-1);
383 }
384
385 int
userconf_attr(char * cmd,long * val)386 userconf_attr(char *cmd, long *val)
387 {
388 char *c;
389 short attr = -1, i = 0, l = 0;
390
391 c = cmd;
392 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
393 c++;
394 l++;
395 }
396
397 while (i <= userconf_maxlocnames) {
398 if (strlen(locnames[i]) == l) {
399 if (strncasecmp(cmd, locnames[i], l) == 0)
400 attr = i;
401 }
402 i++;
403 }
404
405 if (attr == -1) {
406 return (-1);
407 }
408
409 *val = attr;
410
411 return(0);
412 }
413
414 void
userconf_modify(char * item,long * val,long limit)415 userconf_modify(char *item, long *val, long limit)
416 {
417 int ok = 0;
418 long a;
419 char *c;
420 int i;
421
422 while (!ok) {
423 printf("%s [", item);
424 userconf_pnum(*val);
425 printf("] ? ");
426
427 i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
428
429 c = userconf_argbuf;
430 while (*c == ' ' || *c == '\t' || *c == '\n') c++;
431
432 if (*c != '\0') {
433 if (userconf_number(c, &a, limit) == 0) {
434 *val = a;
435 ok = 1;
436 } else {
437 printf("Unknown argument\n");
438 }
439 } else {
440 ok = 1;
441 }
442 }
443 }
444
445 void
userconf_change(int devno)446 userconf_change(int devno)
447 {
448 struct cfdata *cd;
449 char c = '\0';
450 long *l, tmp;
451 int ln;
452
453 if (devno <= userconf_maxdev) {
454 userconf_pdev(devno);
455
456 while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
457 printf("change (y/n) ?");
458 c = cngetc();
459 printf("\n");
460 }
461
462 if (c == 'y' || c == 'Y') {
463 int share = 0, i, lklen;
464 long *lk;
465
466 /* XXX add cmd 'c' <devno> */
467 userconf_hist_cmd('c');
468 userconf_hist_int(devno);
469
470 cd = &cfdata[devno];
471 l = cd->cf_loc;
472 ln = cd->cf_locnames;
473
474 /*
475 * Search for some other driver sharing this
476 * locator table. if one does, we may need to
477 * replace the locators with a malloc'd copy.
478 */
479 for (i = 0; cfdata[i].cf_driver; i++)
480 if (i != devno && cfdata[i].cf_loc == l)
481 share = 1;
482 if (share) {
483 for (i = 0; locnamp[ln+i] != -1 ; i++)
484 ;
485 lk = l = mallocarray(i, sizeof(long),
486 M_TEMP, M_NOWAIT);
487 if (lk == NULL) {
488 printf("out of memory.\n");
489 return;
490 }
491 lklen = i * sizeof(long);
492 bcopy(cd->cf_loc, l, lklen);
493 }
494
495 while (locnamp[ln] != -1) {
496 userconf_modify(locnames[locnamp[ln]], l,
497 LONG_MAX);
498
499 /* XXX add *l */
500 userconf_hist_int(*l);
501
502 ln++;
503 l++;
504 }
505 tmp = cd->cf_flags;
506 userconf_modify("flags", &tmp, INT_MAX);
507 userconf_hist_int(tmp);
508 cd->cf_flags = tmp;
509
510 if (share) {
511 if (memcmp(cd->cf_loc, lk, lklen))
512 cd->cf_loc = lk;
513 else
514 free(lk, M_TEMP, lklen);
515 }
516
517 printf("%3d ", devno);
518 userconf_pdevnam(devno);
519 printf(" changed\n");
520 userconf_pdev(devno);
521 }
522 return;
523 }
524
525 if (devno > userconf_maxdev && devno <= userconf_totdev) {
526 printf("%3d can't change free slot\n", devno);
527 return;
528 }
529
530 if (devno > userconf_totdev &&
531 devno <= userconf_totdev+pdevnames_size) {
532 userconf_pdev(devno);
533 while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
534 printf("change (y/n) ?");
535 c = cngetc();
536 printf("\n");
537 }
538
539 if (c == 'y' || c == 'Y') {
540 /* XXX add cmd 'c' <devno> */
541 userconf_hist_cmd('c');
542 userconf_hist_int(devno);
543
544 tmp = pdevinit[devno-userconf_totdev-1].pdev_count;
545 userconf_modify("count", &tmp, INT_MAX);
546 userconf_hist_int(tmp);
547 pdevinit[devno-userconf_totdev-1].pdev_count = tmp;
548
549 printf("%3d %s changed\n", devno,
550 pdevnames[devno-userconf_totdev-1]);
551 userconf_pdev(devno);
552
553 /* XXX add eoc */
554 userconf_hist_eoc();
555 }
556 return;
557 }
558
559 printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size);
560 }
561
562 void
userconf_disable(int devno)563 userconf_disable(int devno)
564 {
565 int done = 0;
566
567 if (devno <= userconf_maxdev) {
568 switch (cfdata[devno].cf_fstate) {
569 case FSTATE_NOTFOUND:
570 cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
571 break;
572 case FSTATE_STAR:
573 cfdata[devno].cf_fstate = FSTATE_DSTAR;
574 break;
575 case FSTATE_DNOTFOUND:
576 case FSTATE_DSTAR:
577 done = 1;
578 break;
579 default:
580 printf("Error unknown state\n");
581 break;
582 }
583
584 printf("%3d ", devno);
585 userconf_pdevnam(devno);
586 if (done) {
587 printf(" already");
588 } else {
589 /* XXX add cmd 'd' <devno> eoc */
590 userconf_hist_cmd('d');
591 userconf_hist_int(devno);
592 userconf_hist_eoc();
593 }
594 printf(" disabled\n");
595
596 return;
597 }
598
599 if (devno > userconf_maxdev && devno <= userconf_totdev) {
600 printf("%3d can't disable free slot\n", devno);
601 return;
602 }
603
604 if (devno > userconf_totdev &&
605 devno <= userconf_totdev+pdevnames_size) {
606 printf("%3d %s", devno, pdevnames[devno-userconf_totdev-1]);
607 if (pdevinit[devno-userconf_totdev-1].pdev_count < 1) {
608 printf(" already ");
609 } else {
610 pdevinit[devno-userconf_totdev-1].pdev_count *= -1;
611 /* XXX add cmd 'd' <devno> eoc */
612 userconf_hist_cmd('d');
613 userconf_hist_int(devno);
614 userconf_hist_eoc();
615 }
616 printf(" disabled\n");
617 return;
618 }
619
620 printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size);
621 }
622
623 void
userconf_enable(int devno)624 userconf_enable(int devno)
625 {
626 int done = 0;
627
628 if (devno <= userconf_maxdev) {
629 switch (cfdata[devno].cf_fstate) {
630 case FSTATE_DNOTFOUND:
631 cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
632 break;
633 case FSTATE_DSTAR:
634 cfdata[devno].cf_fstate = FSTATE_STAR;
635 break;
636 case FSTATE_NOTFOUND:
637 case FSTATE_STAR:
638 done = 1;
639 break;
640 default:
641 printf("Error unknown state\n");
642 break;
643 }
644
645 printf("%3d ", devno);
646 userconf_pdevnam(devno);
647 if (done) {
648 printf(" already");
649 } else {
650 /* XXX add cmd 'e' <devno> eoc */
651 userconf_hist_cmd('e');
652 userconf_hist_int(devno);
653 userconf_hist_eoc();
654 }
655 printf(" enabled\n");
656 return;
657 }
658
659 if (devno > userconf_maxdev && devno <= userconf_totdev) {
660 printf("%3d can't enable free slot\n", devno);
661 return;
662 }
663
664 if (devno > userconf_totdev &&
665 devno <= userconf_totdev+pdevnames_size) {
666 printf("%3d %s", devno, pdevnames[devno-userconf_totdev-1]);
667 if (pdevinit[devno-userconf_totdev-1].pdev_count > 0) {
668 printf(" already");
669 } else {
670 pdevinit[devno-userconf_totdev-1].pdev_count *= -1;
671 /* XXX add cmd 'e' <devno> eoc */
672 userconf_hist_cmd('e');
673 userconf_hist_int(devno);
674 userconf_hist_eoc();
675 }
676 printf(" enabled\n");
677 return;
678 }
679
680 printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size);
681 }
682
683 void
userconf_help(void)684 userconf_help(void)
685 {
686 int j = 0, k;
687
688 printf("command args description\n");
689 while (*userconf_cmds[j] != '\0') {
690 printf("%s", userconf_cmds[j]);
691 k = strlen(userconf_cmds[j]);
692 while (k < 10) {
693 printf(" ");
694 k++;
695 }
696 switch (*userconf_cmds[j+1]) {
697 case 'L':
698 printf("[count] number of lines before more");
699 break;
700 case 'a':
701 printf("dev add a device");
702 break;
703 case 'b':
704 printf("8|10|16 base on large numbers");
705 break;
706 case 'c':
707 printf("devno|dev change devices");
708 break;
709 #if defined(DDB)
710 case 'D':
711 printf(" enter ddb");
712 break;
713 #endif
714 case 'd':
715 printf("attr val|devno|dev disable devices");
716 break;
717 case 'e':
718 printf("attr val|devno|dev enable devices");
719 break;
720 case 'f':
721 printf("devno|dev find devices");
722 break;
723 case 'h':
724 printf(" this message");
725 break;
726 case 'l':
727 printf(" list configuration");
728 break;
729 case 'q':
730 printf(" leave UKC");
731 break;
732 case 's':
733 printf("[attr [val]] "
734 "show attributes (or devices with an attribute)");
735 break;
736 case 'v':
737 printf(" toggle verbose booting");
738 break;
739 default:
740 printf(" don't know");
741 break;
742 }
743 printf("\n");
744 j += 2;
745 }
746 }
747
748 void
userconf_list(void)749 userconf_list(void)
750 {
751 int i = 0;
752
753 userconf_cnt = 0;
754
755 while (i <= (userconf_totdev+pdevnames_size)) {
756 if (userconf_more())
757 break;
758 userconf_pdev(i++);
759 }
760
761 userconf_cnt = -1;
762 }
763
764 void
userconf_show(void)765 userconf_show(void)
766 {
767 int i = 0;
768
769 userconf_cnt = 0;
770
771 while (i <= userconf_maxlocnames) {
772 if (userconf_more())
773 break;
774 printf("%s\n", locnames[i++]);
775 }
776
777 userconf_cnt = -1;
778 }
779
780 void
userconf_common_attr_val(short attr,long * val,char routine)781 userconf_common_attr_val(short attr, long *val, char routine)
782 {
783 struct cfdata *cd;
784 long *l;
785 int ln;
786 int i = 0, quit = 0;
787
788 userconf_cnt = 0;
789
790 while (i <= userconf_maxdev) {
791 cd = &cfdata[i];
792 l = cd->cf_loc;
793 ln = cd->cf_locnames;
794 while (locnamp[ln] != -1) {
795 if (locnamp[ln] == attr) {
796 if (val == NULL) {
797 quit = userconf_more();
798 userconf_pdev(i);
799 } else {
800 if (*val == *l) {
801 quit = userconf_more();
802 switch (routine) {
803 case UC_ENABLE:
804 userconf_enable(i);
805 break;
806 case UC_DISABLE:
807 userconf_disable(i);
808 break;
809 case UC_SHOW:
810 userconf_pdev(i);
811 break;
812 default:
813 printf("Unknown routine /%c/\n",
814 routine);
815 break;
816 }
817 }
818 }
819 }
820 if (quit)
821 break;
822 ln++;
823 l++;
824 }
825 if (quit)
826 break;
827 i++;
828 }
829
830 userconf_cnt = -1;
831 }
832
833 void
userconf_show_attr(char * cmd)834 userconf_show_attr(char *cmd)
835 {
836 char *c;
837 short attr = -1, i = 0, l = 0;
838 long a;
839
840 c = cmd;
841 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
842 c++;
843 l++;
844 }
845 while (*c == ' ' || *c == '\t' || *c == '\n') {
846 c++;
847 }
848 while (i <= userconf_maxlocnames) {
849 if (strlen(locnames[i]) == l) {
850 if (strncasecmp(cmd, locnames[i], l) == 0) {
851 attr = i;
852 }
853 }
854 i++;
855 }
856
857 if (attr == -1) {
858 printf("Unknown attribute\n");
859 return;
860 }
861
862 if (*c == '\0') {
863 userconf_common_attr_val(attr, NULL, UC_SHOW);
864 } else {
865 if (userconf_number(c, &a, INT_MAX) == 0) {
866 userconf_common_attr_val(attr, &a, UC_SHOW);
867 } else {
868 printf("Unknown argument\n");
869 }
870 }
871 }
872
873 void
userconf_common_dev(char * dev,int len,short unit,short state,char routine)874 userconf_common_dev(char *dev, int len, short unit, short state, char routine)
875 {
876 int i = 0;
877
878 switch (routine) {
879 case UC_CHANGE:
880 break;
881 default:
882 userconf_cnt = 0;
883 break;
884 }
885
886 while (cfdata[i].cf_attach != NULL) {
887 if (strlen(cfdata[i].cf_driver->cd_name) == len) {
888
889 /*
890 * Ok, if device name is correct
891 * If state == FSTATE_FOUND, look for "dev"
892 * If state == FSTATE_STAR, look for "dev*"
893 * If state == FSTATE_NOTFOUND, look for "dev0"
894 */
895 if (strncasecmp(dev, cfdata[i].cf_driver->cd_name,
896 len) == 0 &&
897 (state == FSTATE_FOUND ||
898 (state == FSTATE_STAR &&
899 (cfdata[i].cf_fstate == FSTATE_STAR ||
900 cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
901 (state == FSTATE_NOTFOUND &&
902 cfdata[i].cf_unit == unit &&
903 (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
904 cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
905 if (userconf_more())
906 break;
907 switch (routine) {
908 case UC_CHANGE:
909 userconf_change(i);
910 break;
911 case UC_ENABLE:
912 userconf_enable(i);
913 break;
914 case UC_DISABLE:
915 userconf_disable(i);
916 break;
917 case UC_FIND:
918 userconf_pdev(i);
919 break;
920 default:
921 printf("Unknown routine /%c/\n",
922 routine);
923 break;
924 }
925 }
926 }
927 i++;
928 }
929
930 for (i = 0; i < pdevnames_size; i++) {
931 if (strncasecmp(dev, pdevnames[i], len) == 0 &&
932 state == FSTATE_FOUND) {
933 switch(routine) {
934 case UC_CHANGE:
935 userconf_change(userconf_totdev+1+i);
936 break;
937 case UC_ENABLE:
938 userconf_enable(userconf_totdev+1+i);
939 break;
940 case UC_DISABLE:
941 userconf_disable(userconf_totdev+1+i);
942 break;
943 case UC_FIND:
944 userconf_pdev(userconf_totdev+1+i);
945 break;
946 default:
947 printf("Unknown pseudo routine /%c/\n",routine);
948 break;
949 }
950 }
951 }
952
953 switch (routine) {
954 case UC_CHANGE:
955 break;
956 default:
957 userconf_cnt = -1;
958 break;
959 }
960 }
961
962 void
userconf_common_attr(char * cmd,int attr,char routine)963 userconf_common_attr(char *cmd, int attr, char routine)
964 {
965 char *c;
966 short l = 0;
967 long a;
968
969 c = cmd;
970 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
971 c++;
972 l++;
973 }
974 while (*c == ' ' || *c == '\t' || *c == '\n')
975 c++;
976
977 if (*c == '\0') {
978 printf("Value missing for attribute\n");
979 return;
980 }
981
982 if (userconf_number(c, &a, INT_MAX) == 0) {
983 userconf_common_attr_val(attr, &a, routine);
984 } else {
985 printf("Unknown argument\n");
986 }
987 }
988
989 void
userconf_add_read(char * prompt,char field,char * dev,int len,long * val)990 userconf_add_read(char *prompt, char field, char *dev, int len, long *val)
991 {
992 int ok = 0;
993 long a;
994 char *c;
995 int i;
996
997 *val = -1;
998
999 while (!ok) {
1000 printf("%s ? ", prompt);
1001
1002 i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
1003
1004 c = userconf_argbuf;
1005 while (*c == ' ' || *c == '\t' || *c == '\n')
1006 c++;
1007
1008 if (*c != '\0') {
1009 if (userconf_number(c, &a, INT_MAX) == 0) {
1010 if (a > userconf_maxdev) {
1011 printf("Unknown devno (max is %d)\n",
1012 userconf_maxdev);
1013 } else if (strncasecmp(dev,
1014 cfdata[a].cf_driver->cd_name, len) != 0 &&
1015 field == 'a') {
1016 printf("Not same device type\n");
1017 } else {
1018 *val = a;
1019 ok = 1;
1020 }
1021 } else if (*c == '?') {
1022 userconf_common_dev(dev, len, 0,
1023 FSTATE_FOUND, UC_FIND);
1024 } else if (*c == 'q' || *c == 'Q') {
1025 ok = 1;
1026 } else {
1027 printf("Unknown argument\n");
1028 }
1029 } else {
1030 ok = 1;
1031 }
1032 }
1033 }
1034
1035 void
userconf_add(char * dev,int len,short unit,short state)1036 userconf_add(char *dev, int len, short unit, short state)
1037 {
1038 int found = 0;
1039 struct cfdata new;
1040 int max_unit, star_unit;
1041 long i = 0, val, orig;
1042
1043 memset(&new, 0, sizeof(struct cfdata));
1044
1045 if (userconf_maxdev == userconf_totdev) {
1046 printf("No more space for new devices.\n");
1047 return;
1048 }
1049
1050 if (state == FSTATE_FOUND) {
1051 printf("Device not complete number or * is missing\n");
1052 return;
1053 }
1054
1055 for (i = 0; cfdata[i].cf_driver; i++)
1056 if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1057 strncasecmp(dev, cfdata[i].cf_driver->cd_name, len) == 0)
1058 found = 1;
1059
1060 if (!found) {
1061 printf("No device of this type exists.\n");
1062 return;
1063 }
1064
1065 userconf_add_read("Clone Device (DevNo, 'q' or '?')",
1066 'a', dev, len, &val);
1067
1068 if (val != -1) {
1069 orig = val;
1070 new = cfdata[val];
1071 new.cf_unit = unit;
1072 new.cf_fstate = state;
1073 userconf_add_read("Insert before Device (DevNo, 'q' or '?')",
1074 'i', dev, len, &val);
1075 }
1076
1077 if (val != -1) {
1078 /* XXX add cmd 'a' <orig> <val> eoc */
1079 userconf_hist_cmd('a');
1080 userconf_hist_int(orig);
1081 userconf_hist_int(unit);
1082 userconf_hist_int(state);
1083 userconf_hist_int(val);
1084 userconf_hist_eoc();
1085
1086 /* Insert the new record */
1087 for (i = userconf_maxdev; val <= i; i--)
1088 cfdata[i+1] = cfdata[i];
1089 cfdata[val] = new;
1090
1091 /* Fix indexs in pv */
1092 for (i = 0; i < pv_size; i++) {
1093 if (pv[i] != -1 && pv[i] >= val)
1094 pv[i]++;
1095 }
1096
1097 /* Fix indexs in cfroots */
1098 for (i = 0; i < cfroots_size; i++) {
1099 if (cfroots[i] != -1 && cfroots[i] >= val)
1100 cfroots[i]++;
1101 }
1102
1103 userconf_maxdev++;
1104
1105 max_unit = -1;
1106
1107 /* Find max unit number of the device type */
1108
1109 i = 0;
1110 while (cfdata[i].cf_attach != NULL) {
1111 if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1112 strncasecmp(dev, cfdata[i].cf_driver->cd_name,
1113 len) == 0) {
1114 switch (cfdata[i].cf_fstate) {
1115 case FSTATE_NOTFOUND:
1116 case FSTATE_DNOTFOUND:
1117 if (cfdata[i].cf_unit > max_unit)
1118 max_unit = cfdata[i].cf_unit;
1119 break;
1120 default:
1121 break;
1122 }
1123 }
1124 i++;
1125 }
1126
1127 /*
1128 * For all * entries set unit number to max+1, and update
1129 * cf_starunit1 if necessary.
1130 */
1131 max_unit++;
1132 star_unit = -1;
1133
1134 i = 0;
1135 while (cfdata[i].cf_attach != NULL) {
1136 if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1137 strncasecmp(dev, cfdata[i].cf_driver->cd_name,
1138 len) == 0) {
1139 switch (cfdata[i].cf_fstate) {
1140 case FSTATE_NOTFOUND:
1141 case FSTATE_DNOTFOUND:
1142 if (cfdata[i].cf_unit > star_unit)
1143 star_unit = cfdata[i].cf_unit;
1144 break;
1145 default:
1146 break;
1147 }
1148 }
1149 i++;
1150 }
1151 star_unit++;
1152
1153 i = 0;
1154 while (cfdata[i].cf_attach != NULL) {
1155 if (strlen(cfdata[i].cf_driver->cd_name) == len &&
1156 strncasecmp(dev, cfdata[i].cf_driver->cd_name,
1157 len) == 0) {
1158 switch (cfdata[i].cf_fstate) {
1159 case FSTATE_STAR:
1160 case FSTATE_DSTAR:
1161 cfdata[i].cf_unit = max_unit;
1162 if (cfdata[i].cf_starunit1 < star_unit)
1163 cfdata[i].cf_starunit1 =
1164 star_unit;
1165 break;
1166 default:
1167 break;
1168 }
1169 }
1170 i++;
1171 }
1172 userconf_pdev(val);
1173 }
1174
1175 /* cf_attach, cf_driver, cf_unit, cf_fstate, cf_loc, cf_flags,
1176 cf_parents, cf_locnames, and cf_locnames */
1177 }
1178
1179 int
userconf_parse(char * cmd)1180 userconf_parse(char *cmd)
1181 {
1182 char *c, *v;
1183 int i = 0, j = 0, k;
1184 long a;
1185 short unit, state;
1186
1187 c = cmd;
1188 while (*c == ' ' || *c == '\t')
1189 c++;
1190 v = c;
1191 while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
1192 c++;
1193 i++;
1194 }
1195
1196 k = -1;
1197 while (*userconf_cmds[j] != '\0') {
1198 if (strlen(userconf_cmds[j]) == i) {
1199 if (strncasecmp(v, userconf_cmds[j], i) == 0)
1200 k = j;
1201 }
1202 j += 2;
1203 }
1204
1205 while (*c == ' ' || *c == '\t' || *c == '\n')
1206 c++;
1207
1208 if (k == -1) {
1209 if (*v != '\n')
1210 printf("Unknown command, try help\n");
1211 } else {
1212 switch (*userconf_cmds[k+1]) {
1213 case 'L':
1214 if (*c == '\0')
1215 printf("Argument expected\n");
1216 else if (userconf_number(c, &a, INT_MAX) == 0)
1217 userconf_lines = a;
1218 else
1219 printf("Unknown argument\n");
1220 break;
1221 case 'a':
1222 if (*c == '\0')
1223 printf("Dev expected\n");
1224 else if (userconf_device(c, &a, &unit, &state) == 0)
1225 userconf_add(c, a, unit, state);
1226 else
1227 printf("Unknown argument\n");
1228 break;
1229 case 'b':
1230 if (*c == '\0')
1231 printf("8|10|16 expected\n");
1232 else if (userconf_number(c, &a, INT_MAX) == 0) {
1233 if (a == 8 || a == 10 || a == 16) {
1234 userconf_base = a;
1235 } else {
1236 printf("8|10|16 expected\n");
1237 }
1238 } else
1239 printf("Unknown argument\n");
1240 break;
1241 case 'c':
1242 if (*c == '\0')
1243 printf("DevNo or Dev expected\n");
1244 else if (userconf_number(c, &a, INT_MAX) == 0)
1245 userconf_change(a);
1246 else if (userconf_device(c, &a, &unit, &state) == 0)
1247 userconf_common_dev(c, a, unit, state, UC_CHANGE);
1248 else
1249 printf("Unknown argument\n");
1250 break;
1251 #if defined(DDB)
1252 case 'D':
1253 db_enter();
1254 break;
1255 #endif
1256 case 'd':
1257 if (*c == '\0')
1258 printf("Attr, DevNo or Dev expected\n");
1259 else if (userconf_attr(c, &a) == 0)
1260 userconf_common_attr(c, a, UC_DISABLE);
1261 else if (userconf_number(c, &a, INT_MAX) == 0)
1262 userconf_disable(a);
1263 else if (userconf_device(c, &a, &unit, &state) == 0)
1264 userconf_common_dev(c, a, unit, state, UC_DISABLE);
1265 else
1266 printf("Unknown argument\n");
1267 break;
1268 case 'e':
1269 if (*c == '\0')
1270 printf("Attr, DevNo or Dev expected\n");
1271 else if (userconf_attr(c, &a) == 0)
1272 userconf_common_attr(c, a, UC_ENABLE);
1273 else if (userconf_number(c, &a, INT_MAX) == 0)
1274 userconf_enable(a);
1275 else if (userconf_device(c, &a, &unit, &state) == 0)
1276 userconf_common_dev(c, a, unit, state, UC_ENABLE);
1277 else
1278 printf("Unknown argument\n");
1279 break;
1280 case 'f':
1281 if (*c == '\0')
1282 printf("DevNo or Dev expected\n");
1283 else if (userconf_number(c, &a, INT_MAX) == 0)
1284 userconf_pdev(a);
1285 else if (userconf_device(c, &a, &unit, &state) == 0)
1286 userconf_common_dev(c, a, unit, state, UC_FIND);
1287 else
1288 printf("Unknown argument\n");
1289 break;
1290 case 'h':
1291 userconf_help();
1292 break;
1293 case 'l':
1294 if (*c == '\0')
1295 userconf_list();
1296 else
1297 printf("Unknown argument\n");
1298 break;
1299 case 'q':
1300 /* XXX add cmd 'q' eoc */
1301 userconf_hist_cmd('q');
1302 userconf_hist_eoc();
1303 return(-1);
1304 break;
1305 case 's':
1306 if (*c == '\0')
1307 userconf_show();
1308 else
1309 userconf_show_attr(c);
1310 break;
1311 case 'v':
1312 autoconf_verbose = !autoconf_verbose;
1313 printf("autoconf verbose %sabled\n",
1314 autoconf_verbose ? "en" : "dis");
1315 break;
1316 default:
1317 printf("Unknown command\n");
1318 break;
1319 }
1320 }
1321 return(0);
1322 }
1323
1324 void
user_config(void)1325 user_config(void)
1326 {
1327 userconf_init();
1328 printf("User Kernel Config\n");
1329
1330 cnpollc(1);
1331 while (1) {
1332 printf("UKC> ");
1333 if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
1334 userconf_parse(userconf_cmdbuf))
1335 break;
1336 }
1337 cnpollc(0);
1338
1339 printf("Continuing...\n");
1340 }
1341