Home | History | Annotate | Line # | Download | only in kern
subr_userconf.c revision 1.6
      1 /*	$NetBSD: subr_userconf.c,v 1.6 2002/09/23 05:51:11 simonb Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996 Mats O Jansson <moj (at) 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.6 2002/09/23 05:51:11 simonb 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 __P((void));
     67 int userconf_more __P((void));
     68 void userconf_modify __P((const char *, int*));
     69 void userconf_hist_cmd __P((char));
     70 void userconf_hist_int __P((int));
     71 void userconf_hist_eoc __P((void));
     72 void userconf_pnum __P((int));
     73 void userconf_pdevnam __P((short));
     74 void userconf_pdev __P((short));
     75 int userconf_number __P((char *, int *));
     76 int userconf_device __P((char *, int *, short *, short *));
     77 void userconf_change __P((int));
     78 void userconf_disable __P((int));
     79 void userconf_enable __P((int));
     80 void userconf_help __P((void));
     81 void userconf_list __P((void));
     82 void userconf_common_dev __P((char *, int, short, short, char));
     83 void userconf_add_read __P((char *, char, char *, int, int *));
     84 int userconf_parse __P((char *));
     85 
     86 static int getsn __P((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_driver; 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_driver->cd_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 	short *p;
    231 	int   *l;
    232 	const char **ln;
    233 	char c;
    234 
    235 	if (devno > userconf_maxdev) {
    236 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
    237 		return;
    238 	}
    239 
    240 	cd = &cfdata[devno];
    241 
    242 	printf("[%3d] ", devno);
    243 	userconf_pdevnam(devno);
    244 	printf(" at");
    245 	c = ' ';
    246 	p = cd->cf_parents;
    247 	if (*p == -1)
    248 		printf(" root");
    249 	while (*p != -1) {
    250 		printf("%c", c);
    251 		userconf_pdevnam(*p++);
    252 		c = '|';
    253 	}
    254 	switch (cd->cf_fstate) {
    255 	case FSTATE_NOTFOUND:
    256 	case FSTATE_FOUND:
    257 	case FSTATE_STAR:
    258 		break;
    259 	case FSTATE_DNOTFOUND:
    260 	case FSTATE_DSTAR:
    261 		printf(" disable");
    262 		break;
    263 	default:
    264 		printf(" ???");
    265 		break;
    266 	}
    267 	l = cd->cf_loc;
    268 	ln = cd->cf_locnames;
    269 	while (ln && *ln) {
    270 		printf(" %s ", *ln++);
    271 		userconf_pnum(*l++);
    272 	}
    273 	printf("\n");
    274 }
    275 
    276 int
    277 userconf_number(c, val)
    278 	char *c;
    279 	int *val;
    280 {
    281 	u_int num = 0;
    282 	int neg = 0;
    283 	int base = 10;
    284 
    285 	if (*c == '-') {
    286 		neg = 1;
    287 		c++;
    288 	}
    289 	if (*c == '0') {
    290 		base = 8;
    291 		c++;
    292 		if (*c == 'x' || *c == 'X') {
    293 			base = 16;
    294 			c++;
    295 		}
    296 	}
    297 	while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
    298 		u_char cc = *c;
    299 
    300 		if (cc >= '0' && cc <= '9')
    301 			cc = cc - '0';
    302 		else if (cc >= 'a' && cc <= 'f')
    303 			cc = cc - 'a' + 10;
    304 		else if (cc >= 'A' && cc <= 'F')
    305 			cc = cc - 'A' + 10;
    306 		else
    307 			return (-1);
    308 
    309 		if (cc > base)
    310 			return (-1);
    311 		num = num * base + cc;
    312 		c++;
    313 	}
    314 
    315 	if (neg && num > INT_MAX)	/* overflow */
    316 		return (1);
    317 	*val = neg ? - num : num;
    318 	return (0);
    319 }
    320 
    321 int
    322 userconf_device(cmd, len, unit, state)
    323 	char *cmd;
    324 	int *len;
    325 	short *unit, *state;
    326 {
    327 	short u = 0, s = FSTATE_FOUND;
    328 	int l = 0;
    329 	char *c;
    330 
    331 	c = cmd;
    332 	while (*c >= 'a' && *c <= 'z') {
    333 		l++;
    334 		c++;
    335 	}
    336 	if (*c == '*') {
    337 		s = FSTATE_STAR;
    338 		c++;
    339 	} else {
    340 		while (*c >= '0' && *c <= '9') {
    341 			s = FSTATE_NOTFOUND;
    342 			u = u*10 + *c - '0';
    343 			c++;
    344 		}
    345 	}
    346 	while (*c == ' ' || *c == '\t' || *c == '\n')
    347 		c++;
    348 
    349 	if (*c == '\0') {
    350 		*len = l;
    351 		*unit = u;
    352 		*state = s;
    353 		return(0);
    354 	}
    355 
    356 	return(-1);
    357 }
    358 
    359 void
    360 userconf_modify(item, val)
    361 	const char *item;
    362 	int  *val;
    363 {
    364 	int ok = 0;
    365 	int a;
    366 	char *c;
    367 	int i;
    368 
    369 	while (!ok) {
    370 		printf("%s [", item);
    371 		userconf_pnum(*val);
    372 		printf("] ? ");
    373 
    374 		i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
    375 
    376 		c = userconf_argbuf;
    377 		while (*c == ' ' || *c == '\t' || *c == '\n') c++;
    378 
    379 		if (*c != '\0') {
    380 			if (userconf_number(c, &a) == 0) {
    381 				*val = a;
    382 				ok = 1;
    383 			} else {
    384 				printf("Unknown argument\n");
    385 			}
    386 		} else {
    387 			ok = 1;
    388 		}
    389 	}
    390 }
    391 
    392 void
    393 userconf_change(devno)
    394 	int devno;
    395 {
    396 	struct cfdata *cd;
    397 	char c = '\0';
    398 	int   *l;
    399 	int   ln;
    400 	const char **locnames;
    401 
    402 	if (devno <=  userconf_maxdev) {
    403 
    404 		userconf_pdev(devno);
    405 
    406 		while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
    407 			printf("change (y/n) ?");
    408 			c = cngetc();
    409 			printf("\n");
    410 		}
    411 
    412 		if (c == 'y' || c == 'Y') {
    413 
    414 			/* XXX add cmd 'c' <devno> */
    415 			userconf_hist_cmd('c');
    416 			userconf_hist_int(devno);
    417 
    418 			cd = &cfdata[devno];
    419 			l = cd->cf_loc;
    420 			locnames = cd->cf_locnames;
    421 			ln = 0;
    422 
    423 			while (locnames[ln])
    424 			{
    425 				userconf_modify(locnames[ln], l);
    426 
    427 				/* XXX add *l */
    428 				userconf_hist_int(*l);
    429 
    430 				ln++;
    431 				l++;
    432 			}
    433 
    434 			printf("[%3d] ", devno);
    435 			userconf_pdevnam(devno);
    436 			printf(" changed\n");
    437 			userconf_pdev(devno);
    438 
    439 			/* XXX add eoc */
    440 			userconf_hist_eoc();
    441 
    442 		}
    443 	} else {
    444 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
    445 	}
    446 }
    447 
    448 void
    449 userconf_disable(devno)
    450 	int devno;
    451 {
    452 	int done = 0;
    453 
    454 	if (devno <= userconf_maxdev) {
    455 		switch (cfdata[devno].cf_fstate) {
    456 		case FSTATE_NOTFOUND:
    457 			cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
    458 			break;
    459 		case FSTATE_STAR:
    460 			cfdata[devno].cf_fstate = FSTATE_DSTAR;
    461 			break;
    462 		case FSTATE_DNOTFOUND:
    463 		case FSTATE_DSTAR:
    464 			done = 1;
    465 			break;
    466 		default:
    467 			printf("Error unknown state\n");
    468 			break;
    469 		}
    470 
    471 		printf("[%3d] ", devno);
    472 		userconf_pdevnam(devno);
    473 		if (done) {
    474 			printf(" already");
    475 		} else {
    476 			/* XXX add cmd 'd' <devno> eoc */
    477 			userconf_hist_cmd('d');
    478 			userconf_hist_int(devno);
    479 			userconf_hist_eoc();
    480 		}
    481 		printf(" disabled\n");
    482 	} else {
    483 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
    484 	}
    485 }
    486 
    487 void
    488 userconf_enable(devno)
    489 	int devno;
    490 {
    491 	int done = 0;
    492 
    493 	if (devno <= userconf_maxdev) {
    494 		switch (cfdata[devno].cf_fstate) {
    495 		case FSTATE_DNOTFOUND:
    496 			cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
    497 			break;
    498 		case FSTATE_DSTAR:
    499 			cfdata[devno].cf_fstate = FSTATE_STAR;
    500 			break;
    501 		case FSTATE_NOTFOUND:
    502 		case FSTATE_STAR:
    503 			done = 1;
    504 			break;
    505 		default:
    506 			printf("Error unknown state\n");
    507 			break;
    508 		}
    509 
    510 		printf("[%3d] ", devno);
    511 		userconf_pdevnam(devno);
    512 		if (done) {
    513 			printf(" already");
    514 		} else {
    515 			/* XXX add cmd 'e' <devno> eoc */
    516 			userconf_hist_cmd('d');
    517 			userconf_hist_int(devno);
    518 			userconf_hist_eoc();
    519 		}
    520 		printf(" enabled\n");
    521 	} else {
    522 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
    523 	}
    524 }
    525 
    526 void
    527 userconf_help()
    528 {
    529 	int j = 0, k;
    530 
    531 	printf("command   args                description\n");
    532 	while (*userconf_cmds[j] != '\0') {
    533 		printf(userconf_cmds[j]);
    534 		k = strlen(userconf_cmds[j]);
    535 		while (k < 10) {
    536 			printf(" ");
    537 			k++;
    538 		}
    539 		switch (*userconf_cmds[j+1]) {
    540 		case 'L':
    541 			printf("[count]             number of lines before more");
    542 			break;
    543 		case 'b':
    544 			printf("8|10|16             base on large numbers");
    545 			break;
    546 		case 'c':
    547 			printf("devno|dev           change devices");
    548 			break;
    549 		case 'd':
    550 			printf("devno|dev           disable devices");
    551 			break;
    552 		case 'e':
    553 			printf("devno|dev           enable devices");
    554 			break;
    555 		case 'f':
    556 			printf("devno|dev           find devices");
    557 			break;
    558 		case 'h':
    559 			printf("                    this message");
    560 			break;
    561 		case 'l':
    562 			printf("                    list configuration");
    563 			break;
    564 		case 'q':
    565 			printf("                    leave userconf");
    566 			break;
    567 		default:
    568 			printf("                    don't know");
    569 			break;
    570 		}
    571 		printf("\n");
    572 		j += 2;
    573 	}
    574 }
    575 
    576 void
    577 userconf_list()
    578 {
    579 	int i = 0;
    580 
    581 	userconf_cnt = 0;
    582 
    583 	while (cfdata[i].cf_attach != 0) {
    584 		if (userconf_more())
    585 			break;
    586 		userconf_pdev(i++);
    587 	}
    588 
    589 	userconf_cnt = -1;
    590 }
    591 
    592 void
    593 userconf_common_dev(dev, len, unit, state, routine)
    594 	char *dev;
    595 	int len;
    596 	short unit, state;
    597 	char routine;
    598 {
    599 	int i = 0;
    600 
    601 	switch (routine) {
    602 	case UC_CHANGE:
    603 		break;
    604 	default:
    605 		userconf_cnt = 0;
    606 		break;
    607 	}
    608 
    609 	while (cfdata[i].cf_attach != 0) {
    610 		if (strlen(cfdata[i].cf_driver->cd_name) == len) {
    611 
    612 			/*
    613 			 * Ok, if device name is correct
    614 			 *  If state == FSTATE_FOUND, look for "dev"
    615 			 *  If state == FSTATE_STAR, look for "dev*"
    616 			 *  If state == FSTATE_NOTFOUND, look for "dev0"
    617 			 */
    618 			if (strncasecmp(dev, cfdata[i].cf_driver->cd_name,
    619 					len) == 0 &&
    620 			    (state == FSTATE_FOUND ||
    621 			     (state == FSTATE_STAR &&
    622 			      (cfdata[i].cf_fstate == FSTATE_STAR ||
    623 			       cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
    624 			     (state == FSTATE_NOTFOUND &&
    625 			      cfdata[i].cf_unit == unit &&
    626 			      (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
    627 			       cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
    628 				if (userconf_more())
    629 					break;
    630 				switch (routine) {
    631 				case UC_CHANGE:
    632 					userconf_change(i);
    633 					break;
    634 				case UC_ENABLE:
    635 					userconf_enable(i);
    636 					break;
    637 				case UC_DISABLE:
    638 					userconf_disable(i);
    639 					break;
    640 				case UC_FIND:
    641 					userconf_pdev(i);
    642 					break;
    643 				default:
    644 					printf("Unknown routine /%c/\n",
    645 					    routine);
    646 					break;
    647 				}
    648 			}
    649 		}
    650 		i++;
    651 	}
    652 
    653 	switch (routine) {
    654 	case UC_CHANGE:
    655 		break;
    656 	default:
    657 		userconf_cnt = -1;
    658 		break;
    659 	}
    660 }
    661 
    662 void
    663 userconf_add_read(prompt, field, dev, len, val)
    664 	char *prompt;
    665 	char field;
    666 	char *dev;
    667 	int len;
    668 	int *val;
    669 {
    670 	int ok = 0;
    671 	int a;
    672 	char *c;
    673 	int i;
    674 
    675 	*val = -1;
    676 
    677 	while (!ok) {
    678 		printf("%s ? ", prompt);
    679 
    680 		i = getsn(userconf_argbuf, sizeof(userconf_argbuf));
    681 
    682 		c = userconf_argbuf;
    683 		while (*c == ' ' || *c == '\t' || *c == '\n') c++;
    684 
    685 		if (*c != '\0') {
    686 			if (userconf_number(c, &a) == 0) {
    687 				if (a > userconf_maxdev) {
    688 					printf("Unknown devno (max is %d)\n",
    689 					    userconf_maxdev);
    690 				} else if (strncasecmp(dev,
    691 				    cfdata[a].cf_driver->cd_name, len) != 0 &&
    692 					field == 'a') {
    693 					printf("Not same device type\n");
    694 				} else {
    695 					*val = a;
    696 					ok = 1;
    697 				}
    698 			} else if (*c == '?') {
    699 				userconf_common_dev(dev, len, 0,
    700 				    FSTATE_FOUND, UC_FIND);
    701 			} else if (*c == 'q' || *c == 'Q') {
    702 				ok = 1;
    703 			} else {
    704 				printf("Unknown argument\n");
    705 			}
    706 		} else {
    707 			ok = 1;
    708 		}
    709 	}
    710 }
    711 
    712 int
    713 userconf_parse(cmd)
    714 	char *cmd;
    715 {
    716 	char *c, *v;
    717 	int i = 0, j = 0, k, a;
    718 	short unit, state;
    719 
    720 	c = cmd;
    721 	while (*c == ' ' || *c == '\t')
    722 		c++;
    723 	v = c;
    724 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
    725 		c++;
    726 		i++;
    727 	}
    728 
    729 	k = -1;
    730 	while (*userconf_cmds[j] != '\0') {
    731 		if (strlen(userconf_cmds[j]) == i) {
    732 			if (strncasecmp(v, userconf_cmds[j], i) == 0)
    733 				k = j;
    734 		}
    735 		j += 2;
    736 	}
    737 
    738 	while (*c == ' ' || *c == '\t' || *c == '\n')
    739 		c++;
    740 
    741 	if (k == -1) {
    742 		if (*v != '\n')
    743 			printf("Unknown command, try help\n");
    744 	} else {
    745 		switch (*userconf_cmds[k+1]) {
    746 		case 'L':
    747 			if (*c == '\0')
    748 				printf("Argument expected\n");
    749 			else if (userconf_number(c, &a) == 0)
    750 				userconf_lines = a;
    751 			else
    752 				printf("Unknown argument\n");
    753 			break;
    754 		case 'b':
    755 			if (*c == '\0')
    756 				printf("8|10|16 expected\n");
    757 			else if (userconf_number(c, &a) == 0) {
    758 				if (a == 8 || a == 10 || a == 16) {
    759 					userconf_base = a;
    760 				} else {
    761 					printf("8|10|16 expected\n");
    762 				}
    763 			} else
    764 				printf("Unknown argument\n");
    765 			break;
    766 		case 'c':
    767 			if (*c == '\0')
    768 				printf("DevNo or Dev expected\n");
    769 			else if (userconf_number(c, &a) == 0)
    770 				userconf_change(a);
    771 			else if (userconf_device(c, &a, &unit, &state) == 0)
    772 				userconf_common_dev(c, a, unit, state, UC_CHANGE);
    773 			else
    774 				printf("Unknown argument\n");
    775 			break;
    776 		case 'd':
    777 			if (*c == '\0')
    778 				printf("Attr, DevNo or Dev expected\n");
    779 			else if (userconf_number(c, &a) == 0)
    780 				userconf_disable(a);
    781 			else if (userconf_device(c, &a, &unit, &state) == 0)
    782 				userconf_common_dev(c, a, unit, state, UC_DISABLE);
    783 			else
    784 				printf("Unknown argument\n");
    785 			break;
    786 		case 'e':
    787 			if (*c == '\0')
    788 				printf("Attr, DevNo or Dev expected\n");
    789 			else if (userconf_number(c, &a) == 0)
    790 				userconf_enable(a);
    791 			else if (userconf_device(c, &a, &unit, &state) == 0)
    792 				userconf_common_dev(c, a, unit, state, UC_ENABLE);
    793 			else
    794 				printf("Unknown argument\n");
    795 			break;
    796 		case 'f':
    797 			if (*c == '\0')
    798 				printf("DevNo or Dev expected\n");
    799 			else if (userconf_number(c, &a) == 0)
    800 				userconf_pdev(a);
    801 			else if (userconf_device(c, &a, &unit, &state) == 0)
    802 				userconf_common_dev(c, a, unit, state, UC_FIND);
    803 			else
    804 				printf("Unknown argument\n");
    805 			break;
    806 		case 'h':
    807 			userconf_help();
    808 			break;
    809 		case 'l':
    810 			if (*c == '\0')
    811 				userconf_list();
    812 			else
    813 				printf("Unknown argument\n");
    814 			break;
    815 		case 'q':
    816 			/* XXX add cmd 'q' eoc */
    817 			userconf_hist_cmd('q');
    818 			userconf_hist_eoc();
    819 			return(-1);
    820 		case 's':
    821 		default:
    822 			printf("Unknown command\n");
    823 			break;
    824 		}
    825 	}
    826 	return(0);
    827 }
    828 
    829 extern void user_config __P((void));
    830 
    831 void
    832 user_config()
    833 {
    834 	char prompt[] = "uc> ";
    835 
    836 	userconf_init();
    837 	printf("userconf: configure system autoconfiguration:\n");
    838 
    839 	while (1) {
    840 		printf(prompt);
    841 		if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
    842 		    userconf_parse(userconf_cmdbuf))
    843 			break;
    844 	}
    845 	printf("Continuing...\n");
    846 }
    847 
    848 /*
    849  * XXX shouldn't this be a common function?
    850  */
    851 static int
    852 getsn(cp, size)
    853 	char *cp;
    854 	int size;
    855 {
    856 	char *lp;
    857 	int c, len;
    858 
    859 	cnpollc(1);
    860 
    861 	lp = cp;
    862 	len = 0;
    863 	for (;;) {
    864 		c = cngetc();
    865 		switch (c) {
    866 		case '\n':
    867 		case '\r':
    868 			printf("\n");
    869 			*lp++ = '\0';
    870 			cnpollc(0);
    871 			return (len);
    872 		case '\b':
    873 		case '\177':
    874 		case '#':
    875 			if (len) {
    876 				--len;
    877 				--lp;
    878 				printf("\b \b");
    879 			}
    880 			continue;
    881 		case '@':
    882 		case 'u'&037:
    883 			len = 0;
    884 			lp = cp;
    885 			printf("\n");
    886 			continue;
    887 		default:
    888 			if (len + 1 >= size || c < ' ') {
    889 				printf("\007");
    890 				continue;
    891 			}
    892 			printf("%c", c);
    893 			++len;
    894 			*lp++ = c;
    895 		}
    896 	}
    897 }
    898