Home | History | Annotate | Line # | Download | only in kern
subr_userconf.c revision 1.3.2.1
      1 /*	$NetBSD: subr_userconf.c,v 1.3.2.1 2001/08/03 04:13:42 lukem 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 "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