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