xref: /netbsd-src/sys/kern/subr_userconf.c (revision c2d6cd62e84a8d5c4769f7c5d9bfe51c2a30e897)
1 /*	$NetBSD: subr_userconf.c,v 1.27 2018/09/16 23:18:55 mrg Exp $	*/
2 
3 /*
4  * Copyright (c) 1996 Mats O Jansson <moj@stacken.kth.se>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *	OpenBSD: subr_userconf.c,v 1.19 2000/01/08 23:23:37 d Exp
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: subr_userconf.c,v 1.27 2018/09/16 23:18:55 mrg Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/time.h>
38 #include <sys/userconf.h>
39 
40 #include <dev/cons.h>
41 
42 extern struct cfdata cfdata[];
43 
44 static int userconf_base = 16;			/* Base for "large" numbers */
45 static int userconf_maxdev = -1;		/* # of used device slots   */
46 static int userconf_totdev = -1;		/* # of device slots        */
47 #if 0
48 static int userconf_maxlocnames = -1;		/* # of locnames            */
49 #endif
50 static int userconf_cnt = -1;			/* Line counter for ...     */
51 static int userconf_lines = 12;			/* ... # of lines per page  */
52 static int userconf_histlen = 0;
53 static int userconf_histcur = 0;
54 static char userconf_history[1024];
55 static int userconf_histsz = sizeof(userconf_history);
56 static char userconf_argbuf[40];		/* Additional input         */
57 static char userconf_cmdbuf[40];		/* Command line             */
58 static char userconf_histbuf[40];
59 
60 #define UC_CHANGE 'c'
61 #define UC_DISABLE 'd'
62 #define UC_ENABLE 'e'
63 #define UC_FIND 'f'
64 #define UC_SHOW 's'
65 
66 static const char *userconf_cmds[] = {
67 	"base",		"b",
68 	"change",	"c",
69 	"disable",	"d",
70 	"enable",	"e",
71 	"exit",		"q",
72 	"find",		"f",
73 	"help",		"h",
74 	"list",		"l",
75 	"lines",	"L",
76 	"quit",		"q",
77 	"?",		"h",
78 	"",		 "",
79 };
80 
81 void
userconf_init(void)82 userconf_init(void)
83 {
84 	int i;
85 	struct cfdata *cf;
86 
87 	i = 0;
88 	for (cf = cfdata; cf->cf_name; cf++)
89 		i++;
90 
91 	userconf_maxdev = i - 1;
92 	userconf_totdev = i - 1;
93 
94 	userconf_bootinfo();
95 }
96 
97 static int
userconf_more(void)98 userconf_more(void)
99 {
100 	int quit = 0;
101 	char c = '\0';
102 
103 	if (userconf_cnt != -1) {
104 		if (userconf_cnt == userconf_lines) {
105 			printf("-- more --");
106 			cnpollc(1);
107 			c = cngetc();
108 			cnpollc(0);
109 			userconf_cnt = 0;
110 			printf("\r            \r");
111 		}
112 		userconf_cnt++;
113 		if (c == 'q' || c == 'Q')
114 			quit = 1;
115 	}
116 	return (quit);
117 }
118 
119 static void
userconf_hist_cmd(char cmd)120 userconf_hist_cmd(char cmd)
121 {
122 	userconf_histcur = userconf_histlen;
123 	if (userconf_histcur < userconf_histsz) {
124 		userconf_history[userconf_histcur] = cmd;
125 		userconf_histcur++;
126 	}
127 }
128 
129 static void
userconf_hist_int(int val)130 userconf_hist_int(int val)
131 {
132 	snprintf(userconf_histbuf, sizeof(userconf_histbuf), " %d", val);
133 	if ((userconf_histcur + strlen(userconf_histbuf)) < userconf_histsz) {
134 		memcpy(&userconf_history[userconf_histcur],
135 		      userconf_histbuf,
136 		      strlen(userconf_histbuf));
137 		userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
138 	}
139 }
140 
141 static void
userconf_hist_eoc(void)142 userconf_hist_eoc(void)
143 {
144 	if (userconf_histcur < userconf_histsz) {
145 		userconf_history[userconf_histcur] = '\n';
146 		userconf_histcur++;
147 		userconf_histlen = userconf_histcur;
148 	}
149 }
150 
151 static void
userconf_pnum(int val)152 userconf_pnum(int val)
153 {
154 	if (val > -2 && val < 16) {
155 		printf("%d",val);
156 	} else {
157 		switch (userconf_base) {
158 		case 8:
159 			printf("0%o",val);
160 			break;
161 		case 10:
162 			printf("%d",val);
163 			break;
164 		case 16:
165 		default:
166 			printf("0x%x",val);
167 			break;
168 		}
169 	}
170 }
171 
172 static void
userconf_pdevnam(short dev)173 userconf_pdevnam(short dev)
174 {
175 	struct cfdata *cd;
176 
177 	cd = &cfdata[dev];
178 	printf("%s", cd->cf_name);
179 	switch (cd->cf_fstate) {
180 	case FSTATE_NOTFOUND:
181 	case FSTATE_DNOTFOUND:
182 		printf("%d", cd->cf_unit);
183 		break;
184 	case FSTATE_FOUND:
185 		printf("*FOUND*");
186 		break;
187 	case FSTATE_STAR:
188 	case FSTATE_DSTAR:
189 		printf("*");
190 		break;
191 	default:
192 		printf("*UNKNOWN*");
193 		break;
194 	}
195 }
196 
197 static void
userconf_pdev(short devno)198 userconf_pdev(short devno)
199 {
200 	struct cfdata *cd;
201 	const struct cfparent *cfp;
202 	int   *l;
203 	const struct cfiattrdata *ia;
204 	const struct cflocdesc *ld;
205 	int nld, i;
206 
207 	if (devno > userconf_maxdev) {
208 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
209 		return;
210 	}
211 
212 	cd = &cfdata[devno];
213 
214 	printf("[%3d] ", devno);
215 	userconf_pdevnam(devno);
216 	printf(" at");
217 	cfp = cd->cf_pspec;
218 	if (cfp == NULL)
219 		printf(" root");
220 	else if (cfp->cfp_parent != NULL && cfp->cfp_unit != -1)
221 		printf(" %s%d", cfp->cfp_parent, cfp->cfp_unit);
222 	else
223 		printf(" %s?", cfp->cfp_parent != NULL ? cfp->cfp_parent
224 						       : cfp->cfp_iattr);
225 	switch (cd->cf_fstate) {
226 	case FSTATE_NOTFOUND:
227 	case FSTATE_FOUND:
228 	case FSTATE_STAR:
229 		break;
230 	case FSTATE_DNOTFOUND:
231 	case FSTATE_DSTAR:
232 		printf(" disable");
233 		break;
234 	default:
235 		printf(" ???");
236 		break;
237 	}
238 	if (cfp) {
239 		l = cd->cf_loc;
240 		ia = cfiattr_lookup(cfp->cfp_iattr, 0);
241 		KASSERT(ia);
242 		ld = ia->ci_locdesc;
243 		nld = ia->ci_loclen;
244 		for (i = 0; i < nld; i++) {
245 			printf(" %s ", ld[i].cld_name);
246 			if (!ld[i].cld_defaultstr
247 			    || (l[i] != ld[i].cld_default))
248 				userconf_pnum(l[i]);
249 			else
250 				printf("?");
251 		}
252 	}
253 	printf("\n");
254 }
255 
256 static int
userconf_number(char * c,int * val)257 userconf_number(char *c, int *val)
258 {
259 	u_int num = 0;
260 	int neg = 0;
261 	int base = 10;
262 
263 	if (*c == '-') {
264 		neg = 1;
265 		c++;
266 	}
267 	if (*c == '0') {
268 		base = 8;
269 		c++;
270 		if (*c == 'x' || *c == 'X') {
271 			base = 16;
272 			c++;
273 		}
274 	}
275 	while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
276 		u_char cc = *c;
277 
278 		if (cc >= '0' && cc <= '9')
279 			cc = cc - '0';
280 		else if (cc >= 'a' && cc <= 'f')
281 			cc = cc - 'a' + 10;
282 		else if (cc >= 'A' && cc <= 'F')
283 			cc = cc - 'A' + 10;
284 		else
285 			return (-1);
286 
287 		if (cc > base)
288 			return (-1);
289 		num = num * base + cc;
290 		c++;
291 	}
292 
293 	if (neg && num > INT_MAX)	/* overflow */
294 		return (1);
295 	*val = neg ? - num : num;
296 	return (0);
297 }
298 
299 static int
userconf_device(char * cmd,int * len,short * unit,short * state)300 userconf_device(char *cmd, int *len, short *unit, short *state)
301 {
302 	short u = 0, s = FSTATE_FOUND;
303 	int l = 0;
304 	char *c;
305 
306 	c = cmd;
307 	while (!(!*c || *c == ' ' || *c == '\t' || *c == '\n'))
308 		c++;
309 	while (c > cmd) {
310 		c--;
311 		if (!((*c >= '0' && *c <= '9') || *c == '*')) {
312 			c++;
313 			break;
314 		}
315 	}
316 	l = c - cmd;
317 	if (*c == '*') {
318 		s = FSTATE_STAR;
319 		c++;
320 	} else {
321 		while (*c >= '0' && *c <= '9') {
322 			s = FSTATE_NOTFOUND;
323 			u = u*10 + *c - '0';
324 			c++;
325 		}
326 	}
327 	while (*c == ' ' || *c == '\t' || *c == '\n')
328 		c++;
329 
330 	if (*c == '\0') {
331 		*len = l;
332 		*unit = u;
333 		*state = s;
334 		return(0);
335 	}
336 
337 	return(-1);
338 }
339 
340 static void
userconf_modify(const struct cflocdesc * item,int * val)341 userconf_modify(const struct cflocdesc *item, int *val)
342 {
343 	int ok = 0;
344 	int a;
345 	char *c;
346 
347 	while (!ok) {
348 		printf("%s [", item->cld_name);
349 		if (item->cld_defaultstr && (*val == item->cld_default))
350 			printf("?");
351 		else
352 			userconf_pnum(*val);
353 		printf("] ? ");
354 
355 		cngetsn(userconf_argbuf, sizeof(userconf_argbuf));
356 
357 		c = userconf_argbuf;
358 		while (*c == ' ' || *c == '\t' || *c == '\n') c++;
359 
360 		if (*c != '\0') {
361 			if (*c == '?') {
362 				if (item->cld_defaultstr) {
363 					*val = item->cld_default;
364 					ok = 1;
365 				} else
366 					printf("No default\n");
367 			} else if (userconf_number(c, &a) == 0) {
368 				*val = a;
369 				ok = 1;
370 			} else {
371 				printf("Unknown argument\n");
372 			}
373 		} else {
374 			ok = 1;
375 		}
376 	}
377 }
378 
379 static void
userconf_change(int devno)380 userconf_change(int devno)
381 {
382 	struct cfdata *cd;
383 	char c = '\0';
384 	int   *l;
385 	int   ln;
386 	const struct cfiattrdata *ia;
387 	const struct cflocdesc *ld;
388 	int nld;
389 
390 	if (devno <=  userconf_maxdev) {
391 
392 		userconf_pdev(devno);
393 
394 		while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
395 			printf("change (y/n) ?");
396 			cnpollc(1);
397 			c = cngetc();
398 			cnpollc(0);
399 			printf("\n");
400 		}
401 
402 		if (c == 'y' || c == 'Y') {
403 
404 			/* XXX add cmd 'c' <devno> */
405 			userconf_hist_cmd('c');
406 			userconf_hist_int(devno);
407 
408 			cd = &cfdata[devno];
409 			l = cd->cf_loc;
410 			ia = cfiattr_lookup(cd->cf_pspec->cfp_iattr, 0);
411 			KASSERT(ia);
412 			ld = ia->ci_locdesc;
413 			nld = ia->ci_loclen;
414 
415 			for (ln = 0; ln < nld; ln++)
416 			{
417 				userconf_modify(&ld[ln], l);
418 
419 				/* XXX add *l */
420 				userconf_hist_int(*l);
421 
422 				l++;
423 			}
424 
425 			printf("[%3d] ", devno);
426 			userconf_pdevnam(devno);
427 			printf(" changed\n");
428 			userconf_pdev(devno);
429 
430 			/* XXX add eoc */
431 			userconf_hist_eoc();
432 
433 		}
434 	} else {
435 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
436 	}
437 }
438 
439 static void
userconf_disable(int devno)440 userconf_disable(int devno)
441 {
442 	int done = 0;
443 
444 	if (devno <= userconf_maxdev) {
445 		switch (cfdata[devno].cf_fstate) {
446 		case FSTATE_NOTFOUND:
447 			cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
448 			break;
449 		case FSTATE_STAR:
450 			cfdata[devno].cf_fstate = FSTATE_DSTAR;
451 			break;
452 		case FSTATE_DNOTFOUND:
453 		case FSTATE_DSTAR:
454 			done = 1;
455 			break;
456 		default:
457 			printf("Error unknown state\n");
458 			break;
459 		}
460 
461 		printf("[%3d] ", devno);
462 		userconf_pdevnam(devno);
463 		if (done) {
464 			printf(" already");
465 		} else {
466 			/* XXX add cmd 'd' <devno> eoc */
467 			userconf_hist_cmd('d');
468 			userconf_hist_int(devno);
469 			userconf_hist_eoc();
470 		}
471 		printf(" disabled\n");
472 	} else {
473 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
474 	}
475 }
476 
477 static void
userconf_enable(int devno)478 userconf_enable(int devno)
479 {
480 	int done = 0;
481 
482 	if (devno <= userconf_maxdev) {
483 		switch (cfdata[devno].cf_fstate) {
484 		case FSTATE_DNOTFOUND:
485 			cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
486 			break;
487 		case FSTATE_DSTAR:
488 			cfdata[devno].cf_fstate = FSTATE_STAR;
489 			break;
490 		case FSTATE_NOTFOUND:
491 		case FSTATE_STAR:
492 			done = 1;
493 			break;
494 		default:
495 			printf("Error unknown state\n");
496 			break;
497 		}
498 
499 		printf("[%3d] ", devno);
500 		userconf_pdevnam(devno);
501 		if (done) {
502 			printf(" already");
503 		} else {
504 			/* XXX add cmd 'e' <devno> eoc */
505 			userconf_hist_cmd('d');
506 			userconf_hist_int(devno);
507 			userconf_hist_eoc();
508 		}
509 		printf(" enabled\n");
510 	} else {
511 		printf("Unknown devno (max is %d)\n", userconf_maxdev);
512 	}
513 }
514 
515 static void
userconf_help(void)516 userconf_help(void)
517 {
518 	int j = 0, k;
519 
520 	printf("command   args                description\n");
521 	while (*userconf_cmds[j] != '\0') {
522 		printf("%s", userconf_cmds[j]);
523 		k = strlen(userconf_cmds[j]);
524 		while (k < 10) {
525 			printf(" ");
526 			k++;
527 		}
528 		switch (*userconf_cmds[j+1]) {
529 		case 'L':
530 			printf("[count]             number of lines before more");
531 			break;
532 		case 'b':
533 			printf("8|10|16             base on large numbers");
534 			break;
535 		case 'c':
536 			printf("devno|dev           change devices");
537 			break;
538 		case 'd':
539 			printf("devno|dev           disable devices");
540 			break;
541 		case 'e':
542 			printf("devno|dev           enable devices");
543 			break;
544 		case 'f':
545 			printf("devno|dev           find devices");
546 			break;
547 		case 'h':
548 			printf("                    this message");
549 			break;
550 		case 'l':
551 			printf("                    list configuration");
552 			break;
553 		case 'q':
554 			printf("                    leave userconf");
555 			break;
556 		default:
557 			printf("                    don't know");
558 			break;
559 		}
560 		printf("\n");
561 		j += 2;
562 	}
563 }
564 
565 static void
userconf_list(void)566 userconf_list(void)
567 {
568 	int i = 0;
569 
570 	userconf_cnt = 0;
571 
572 	while (cfdata[i].cf_name != NULL) {
573 		if (userconf_more())
574 			break;
575 		userconf_pdev(i++);
576 	}
577 
578 	userconf_cnt = -1;
579 }
580 
581 static void
userconf_common_dev(char * dev,int len,short unit,short state,char routine)582 userconf_common_dev(char *dev, int len, short unit, short state, char routine)
583 {
584 	int i = 0;
585 
586 	switch (routine) {
587 	case UC_CHANGE:
588 		break;
589 	default:
590 		userconf_cnt = 0;
591 		break;
592 	}
593 
594 	while (cfdata[i].cf_name != NULL) {
595 		if (strlen(cfdata[i].cf_name) == len) {
596 
597 			/*
598 			 * Ok, if device name is correct
599 			 *  If state == FSTATE_FOUND, look for "dev"
600 			 *  If state == FSTATE_STAR, look for "dev*"
601 			 *  If state == FSTATE_NOTFOUND, look for "dev0"
602 			 */
603 			if (strncasecmp(dev, cfdata[i].cf_name,
604 					len) == 0 &&
605 			    (state == FSTATE_FOUND ||
606 			     (state == FSTATE_STAR &&
607 			      (cfdata[i].cf_fstate == FSTATE_STAR ||
608 			       cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
609 			     (state == FSTATE_NOTFOUND &&
610 			      cfdata[i].cf_unit == unit &&
611 			      (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
612 			       cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
613 				if (userconf_more())
614 					break;
615 				switch (routine) {
616 				case UC_CHANGE:
617 					userconf_change(i);
618 					break;
619 				case UC_ENABLE:
620 					userconf_enable(i);
621 					break;
622 				case UC_DISABLE:
623 					userconf_disable(i);
624 					break;
625 				case UC_FIND:
626 					userconf_pdev(i);
627 					break;
628 				default:
629 					printf("Unknown routine /%c/\n",
630 					    routine);
631 					break;
632 				}
633 			}
634 		}
635 		i++;
636 	}
637 
638 	switch (routine) {
639 	case UC_CHANGE:
640 		break;
641 	default:
642 		userconf_cnt = -1;
643 		break;
644 	}
645 }
646 
647 #if 0
648 static void
649 userconf_add_read(char *prompt, char field, char *dev, int len, int *val)
650 {
651 	int ok = 0;
652 	int a;
653 	char *c;
654 
655 	*val = -1;
656 
657 	while (!ok) {
658 		printf("%s ? ", prompt);
659 
660 		getsn(userconf_argbuf, sizeof(userconf_argbuf));
661 
662 		c = userconf_argbuf;
663 		while (*c == ' ' || *c == '\t' || *c == '\n') c++;
664 
665 		if (*c != '\0') {
666 			if (userconf_number(c, &a) == 0) {
667 				if (a > userconf_maxdev) {
668 					printf("Unknown devno (max is %d)\n",
669 					    userconf_maxdev);
670 				} else if (strncasecmp(dev,
671 				    cfdata[a].cf_name, len) != 0 &&
672 					field == 'a') {
673 					printf("Not same device type\n");
674 				} else {
675 					*val = a;
676 					ok = 1;
677 				}
678 			} else if (*c == '?') {
679 				userconf_common_dev(dev, len, 0,
680 				    FSTATE_FOUND, UC_FIND);
681 			} else if (*c == 'q' || *c == 'Q') {
682 				ok = 1;
683 			} else {
684 				printf("Unknown argument\n");
685 			}
686 		} else {
687 			ok = 1;
688 		}
689 	}
690 }
691 #endif /* 0 */
692 
693 int
userconf_parse(char * cmd)694 userconf_parse(char *cmd)
695 {
696 	char *c, *v;
697 	int i = 0, j = 0, k, a;
698 	short unit, state;
699 
700 	c = cmd;
701 	while (*c == ' ' || *c == '\t')
702 		c++;
703 	v = c;
704 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
705 		c++;
706 		i++;
707 	}
708 
709 	k = -1;
710 	while (*userconf_cmds[j] != '\0') {
711 		if (strlen(userconf_cmds[j]) == i) {
712 			if (strncasecmp(v, userconf_cmds[j], i) == 0)
713 				k = j;
714 		}
715 		j += 2;
716 	}
717 
718 	while (*c == ' ' || *c == '\t' || *c == '\n')
719 		c++;
720 
721 	if (k == -1) {
722 		if (*v != '\n')
723 			printf("Unknown command, try help\n");
724 	} else {
725 		switch (*userconf_cmds[k+1]) {
726 		case 'L':
727 			if (*c == '\0')
728 				printf("Argument expected\n");
729 			else if (userconf_number(c, &a) == 0)
730 				userconf_lines = a;
731 			else
732 				printf("Unknown argument\n");
733 			break;
734 		case 'b':
735 			if (*c == '\0')
736 				printf("8|10|16 expected\n");
737 			else if (userconf_number(c, &a) == 0) {
738 				if (a == 8 || a == 10 || a == 16) {
739 					userconf_base = a;
740 				} else {
741 					printf("8|10|16 expected\n");
742 				}
743 			} else
744 				printf("Unknown argument\n");
745 			break;
746 		case 'c':
747 			if (*c == '\0')
748 				printf("DevNo or Dev expected\n");
749 			else if (userconf_number(c, &a) == 0)
750 				userconf_change(a);
751 			else if (userconf_device(c, &a, &unit, &state) == 0)
752 				userconf_common_dev(c, a, unit, state, UC_CHANGE);
753 			else
754 				printf("Unknown argument\n");
755 			break;
756 		case 'd':
757 			if (*c == '\0')
758 				printf("Attr, DevNo or Dev expected\n");
759 			else if (userconf_number(c, &a) == 0)
760 				userconf_disable(a);
761 			else if (userconf_device(c, &a, &unit, &state) == 0)
762 				userconf_common_dev(c, a, unit, state, UC_DISABLE);
763 			else
764 				printf("Unknown argument\n");
765 			break;
766 		case 'e':
767 			if (*c == '\0')
768 				printf("Attr, DevNo or Dev expected\n");
769 			else if (userconf_number(c, &a) == 0)
770 				userconf_enable(a);
771 			else if (userconf_device(c, &a, &unit, &state) == 0)
772 				userconf_common_dev(c, a, unit, state, UC_ENABLE);
773 			else
774 				printf("Unknown argument\n");
775 			break;
776 		case 'f':
777 			if (*c == '\0')
778 				printf("DevNo or Dev expected\n");
779 			else if (userconf_number(c, &a) == 0)
780 				userconf_pdev(a);
781 			else if (userconf_device(c, &a, &unit, &state) == 0)
782 				userconf_common_dev(c, a, unit, state, UC_FIND);
783 			else
784 				printf("Unknown argument\n");
785 			break;
786 		case 'h':
787 			userconf_help();
788 			break;
789 		case 'l':
790 			if (*c == '\0')
791 				userconf_list();
792 			else
793 				printf("Unknown argument\n");
794 			break;
795 		case 'q':
796 			/* XXX add cmd 'q' eoc */
797 			userconf_hist_cmd('q');
798 			userconf_hist_eoc();
799 			return(-1);
800 		case 's':
801 		default:
802 			printf("Unknown command\n");
803 			break;
804 		}
805 	}
806 	return(0);
807 }
808 
809 void
userconf_prompt(void)810 userconf_prompt(void)
811 {
812 	const char prompt[] = "uc> ";
813 
814 	printf("userconf: configure system autoconfiguration:\n");
815 
816 	while (1) {
817 		printf(prompt);
818 		if (cngetsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
819 		    userconf_parse(userconf_cmdbuf))
820 			break;
821 	}
822 	printf("Continuing...\n");
823 }
824