xref: /openbsd/usr.sbin/config/ukcutil.c (revision 09467b48)
1 /*	$OpenBSD: ukcutil.c,v 1.25 2019/09/06 21:30:31 cheloha Exp $ */
2 
3 /*
4  * Copyright (c) 1999-2001 Mats O Jansson.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/device.h>
29 
30 #include <ctype.h>
31 #include <err.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <nlist.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "cmd.h"
40 #include "exec.h"
41 #include "ukc.h"
42 #include "misc.h"
43 
44 extern	int ukc_mod_kernel;
45 
46 struct	cfdata *
47 get_cfdata(int idx)
48 {
49 	return((struct cfdata *)(adjust((caddr_t)nl[P_CFDATA].n_value) +
50 	    idx * sizeof(struct cfdata)));
51 }
52 
53 short *
54 get_locnamp(int idx)
55 {
56 	return((short *)(adjust((caddr_t)nl[S_LOCNAMP].n_value) +
57 	    idx * sizeof(short)));
58 }
59 
60 static caddr_t *
61 get_locnames(int idx)
62 {
63 	return((caddr_t *)(adjust((caddr_t)nl[P_LOCNAMES].n_value) +
64 	    idx * sizeof(caddr_t)));
65 }
66 
67 static long *
68 get_extraloc(int nslots)
69 {
70 	long *extralocp, *locp;
71 	int *rextralocp, *textralocp;
72 
73 	extralocp = (long *)adjust((caddr_t)nl[IA_EXTRALOC].n_value);
74 	rextralocp = (int *)adjust((caddr_t)nl[I_REXTRALOC].n_value);
75 	textralocp = (int *)adjust((caddr_t)nl[I_TEXTRALOC].n_value);
76 	if (*rextralocp < nslots)
77 		return (NULL);
78 
79 	locp = &extralocp[*textralocp - *rextralocp];
80 	*rextralocp -= nslots;
81 	return locp;
82 }
83 
84 static char *
85 get_pdevnames(int idx)
86 {
87 	caddr_t *p;
88 
89 	p = (caddr_t *)adjust((caddr_t)nl[P_PDEVNAMES].n_value +
90 	    idx * sizeof(caddr_t));
91 	return(char *)adjust((caddr_t)*p);
92 
93 }
94 
95 static struct pdevinit *
96 get_pdevinit(int idx)
97 {
98 	return((struct pdevinit *)(adjust((caddr_t)nl[S_PDEVINIT].n_value) +
99 	    idx * sizeof(struct pdevinit)));
100 }
101 
102 int
103 more(void)
104 {
105 	int quit = 0;
106 	cmd_t cmd;
107 
108 	if (cnt != -1) {
109 		if (cnt > 0 && cnt == lines) {
110 			printf("--- more ---");
111 			fflush(stdout);
112 			ask_cmd(&cmd);
113 			cnt = 0;
114 			if (cmd.cmd[0] == 'q' || cmd.cmd[0] == 'Q')
115 				quit = 1;
116 		}
117 		cnt++;
118 	}
119 	return (quit);
120 }
121 
122 static void
123 pnum(long val)
124 {
125 	if (val > -2 && val < 16) {
126 		printf("%ld", val);
127 		return;
128 	}
129 
130 	switch (base) {
131 	case 8:
132 		printf("0%lo", val);
133 		break;
134 	case 10:
135 		printf("%ld", val);
136 		break;
137 	case 16:
138 	default:
139 		printf("0x%lx", val);
140 		break;
141 	}
142 }
143 
144 static void
145 pdevnam(short devno)
146 {
147 	struct cfdata *cd;
148 	struct cfdriver *cdrv;
149 
150 	cd = get_cfdata(devno);
151 
152 	cdrv = (struct cfdriver *)adjust((caddr_t)cd->cf_driver);
153 	printf("%s", adjust((caddr_t)cdrv->cd_name));
154 
155 	switch (cd->cf_fstate) {
156 	case FSTATE_NOTFOUND:
157 	case FSTATE_DNOTFOUND:
158 		printf("%d", cd->cf_unit);
159 		break;
160 	case FSTATE_FOUND:
161 		printf("*FOUND*");
162 		break;
163 	case FSTATE_STAR:
164 	case FSTATE_DSTAR:
165 		printf("*");
166 		break;
167 	default:
168 		printf("*UNKNOWN*");
169 		break;
170 	}
171 }
172 
173 void
174 pdev(short devno)
175 {
176 	struct pdevinit *pi;
177 	struct cfdata *cd;
178 	short	*s, *ln;
179 	long	*i;
180 	caddr_t	*p;
181 	char	c;
182 
183 	if (nopdev == 0) {
184 		if (devno > maxdev && devno <= totdev) {
185 			printf("%3d free slot (for add)\n", devno);
186 			return;
187 		}
188 		if (devno > totdev && devno <= totdev + maxpseudo) {
189 			pi = get_pdevinit(devno - totdev -1);
190 			printf("%3d %s count %d", devno,
191 			    get_pdevnames(devno - totdev - 1),
192 			    abs(pi->pdev_count));
193 			if (pi->pdev_count < 0)
194 				printf(" disable");
195 			printf(" (pseudo device)\n");
196 			return;
197 		}
198 	}
199 
200 	if (devno > maxdev) {
201 		printf("Unknown devno (max is %d)\n", maxdev);
202 		return;
203 	}
204 
205 	cd = get_cfdata(devno);
206 
207 	printf("%3d ", devno);
208 	pdevnam(devno);
209 	printf(" at");
210 
211 	c = ' ';
212 	s = (short *)adjust((caddr_t)cd->cf_parents);
213 	if (*s == -1)
214 		printf(" root");
215 	while (*s != -1) {
216 		printf("%c", c);
217 		pdevnam(*s);
218 		c = '|';
219 		s++;
220 	}
221 	switch (cd->cf_fstate) {
222 	case FSTATE_NOTFOUND:
223 	case FSTATE_FOUND:
224 	case FSTATE_STAR:
225 		break;
226 	case FSTATE_DNOTFOUND:
227 	case FSTATE_DSTAR:
228 		printf(" disable");
229 		break;
230 	default:
231 		printf(" ???");
232 		break;
233 	}
234 
235 	i = (long *)adjust((caddr_t)cd->cf_loc);
236 	ln = get_locnamp(cd->cf_locnames);
237 	while (*ln != -1) {
238 		p = get_locnames(*ln);
239 		printf(" %s ", adjust((caddr_t)*p));
240 		ln++;
241 		pnum(*i);
242 		i++;
243 	}
244 	printf(" flags 0x%x\n", cd->cf_flags);
245 }
246 
247 static int
248 numberl(const char *c, long *val)
249 {
250 	char *ep;
251 
252 	errno = 0;
253 	*val = strtol(c, &ep, 0);
254 	if (*c == '\0' || (!isspace((unsigned char)*ep) && *ep != '\0') ||
255 	    (errno == ERANGE && (*val == LONG_MAX || *val == LONG_MIN)))
256 		return (-1);
257 	return (0);
258 }
259 
260 int
261 number(const char *c, int *val)
262 {
263 	long v;
264 	int ret = numberl(c, &v);
265 
266 	if (ret == 0) {
267 		if (v <= INT_MAX && v >= INT_MIN)
268 			*val = (int)v;
269 		else
270 			ret = -1;
271 	}
272 	return (ret);
273 }
274 
275 int
276 device(char *cmd, int *len, short *unit, short *state)
277 {
278 	short u = 0, s = FSTATE_FOUND;
279 	int l = 0;
280 	char *c;
281 
282 	c = cmd;
283 	while (*c >= 'a' && *c <= 'z') {
284 		l++;
285 		c++;
286 	}
287 
288 	if (*c == '*') {
289 		s = FSTATE_STAR;
290 		c++;
291 	} else {
292 		while (*c >= '0' && *c <= '9') {
293 			s = FSTATE_NOTFOUND;
294 			u = u*10 + *c - '0';
295 			c++;
296 		}
297 	}
298 	while (*c == ' ' || *c == '\t' || *c == '\n')
299 		c++;
300 
301 	if (*c == '\0') {
302 		*len = l;
303 		*unit = u;
304 		*state = s;
305 		return(0);
306 	}
307 	return(-1);
308 }
309 
310 int
311 attr(char *cmd, int *val)
312 {
313 	short attr = -1, i = 0, l = 0;
314 	caddr_t *p;
315 	char *c;
316 
317 	c = cmd;
318 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
319 		c++;
320 		l++;
321 	}
322 
323 	p = get_locnames(0);
324 
325 	while (i <= maxlocnames) {
326 		if (strlen((char *)adjust((caddr_t)*p)) == l) {
327 			if (strncasecmp(cmd, adjust((caddr_t)*p), l) == 0)
328 				attr = i;
329 		}
330 		p++;
331 		i++;
332 	}
333 	if (attr == -1)
334 		return (-1);
335 
336 	*val = attr;
337 	return(0);
338 }
339 
340 static int
341 modifyl(char *item, long *val)
342 {
343 	cmd_t cmd;
344 	long a;
345 
346 	ukc_mod_kernel = 1;
347 	while (1) {
348 		printf("%s [", item);
349 		pnum(*val);
350 		printf("] ? ");
351 		fflush(stdout);
352 
353 		ask_cmd(&cmd);
354 
355 		if (strlen(cmd.cmd) != 0) {
356 			if (strlen(cmd.args) == 0) {
357 				if (numberl(cmd.cmd, &a) == 0) {
358 					*val = a;
359 					return (1);
360 				} else
361 					printf("Unknown argument\n");
362 			} else
363 				printf("Too many arguments\n");
364 		} else
365 			return (0);
366 	}
367 }
368 
369 void
370 modify(char *item, int *val)
371 {
372 	long a = *val;
373 
374 	while (modifyl(item, &a)) {
375 		if (a <= INT_MAX && a >= INT_MIN) {
376 			*val = (int)a;
377 			break;
378 		}
379 		printf("Out of range argument\n");
380 	}
381 }
382 
383 void
384 change(int devno)
385 {
386 	int	i, share = 0;
387 	long	*j = NULL, *l = NULL;
388 	struct cfdata *cd, *c;
389 	struct pdevinit *pi;
390 	short	*ln, *lk;
391 	caddr_t	*p;
392 
393 	ukc_mod_kernel = 1;
394 	if (devno <=  maxdev) {
395 		pdev(devno);
396 		if (!ask_yn("change"))
397 			return;
398 
399 		cd = get_cfdata(devno);
400 
401 		/*
402 		 * Search for some other driver sharing this
403 		 * locator table. if one does, we may need to
404 		 * replace the locators with a new copy.
405 		 */
406 		c = get_cfdata(0);
407 		for (i = 0; c->cf_driver; i++) {
408 			if (i != devno && c->cf_loc == cd->cf_loc)
409 				share = 1;
410 			c++;
411 		}
412 
413 		ln = get_locnamp(cd->cf_locnames);
414 		l = (long *)adjust((caddr_t)cd->cf_loc);
415 
416 		if (share) {
417 			if (oldkernel) {
418 				printf("Can't do that on this kernel\n");
419 				return;
420 			}
421 
422 			lk = ln;
423 			i = 0;
424 			while (*lk != -1) {
425 				lk++;
426 				i++;
427 			}
428 			lk = ln;
429 
430 			j = l = get_extraloc(i);
431 			if (l == NULL) {
432 				printf("Not enough space to change device.\n");
433 				return;
434 			}
435 			if (i)
436 				bcopy(adjust((caddr_t)cd->cf_loc), l,
437 				    sizeof(long) * i);
438 		}
439 
440 		while (*ln != -1) {
441 			p = get_locnames(*ln);
442 			modifyl((char *)adjust(*p), l);
443 			ln++;
444 			l++;
445 		}
446 		modify("flags", &cd->cf_flags);
447 
448 		if (share) {
449 			if (bcmp(adjust((caddr_t)cd->cf_loc),
450 			    j, sizeof(long) * i)) {
451 				cd->cf_loc = (long *)readjust((caddr_t)j);
452 			}
453 		}
454 
455 		printf("%3d ", devno);
456 		pdevnam(devno);
457 		printf(" changed\n");
458 		pdev(devno);
459 		return;
460 	}
461 
462 	if (nopdev == 0) {
463 		if (devno > maxdev && devno <= totdev) {
464 			printf("%3d can't change free slot\n", devno);
465 			return;
466 		}
467 
468 		if (devno > totdev && devno <= totdev + maxpseudo) {
469 			pdev(devno);
470 			if (ask_yn("change")) {
471 				pi = get_pdevinit(devno-totdev-1);
472 				modify("count", &pi->pdev_count);
473 				printf("%3d %s changed\n", devno,
474 				    get_pdevnames(devno - totdev - 1));
475 				pdev(devno);
476 			}
477 			return;
478 		}
479 	}
480 
481 	printf("Unknown devno (max is %d)\n", totdev+maxpseudo);
482 }
483 
484 void
485 change_history(int devno, char *str)
486 {
487 	int	i, share = 0;
488 	long	*j = NULL, *l = NULL;
489 	struct cfdata *cd, *c;
490 	struct pdevinit *pi;
491 	short	*ln, *lk;
492 
493 	ukc_mod_kernel = 1;
494 
495 	if (devno <= maxdev) {
496 
497 		pdev(devno);
498 		cd = get_cfdata(devno);
499 
500 		/*
501 		 * Search for some other driver sharing this
502 		 * locator table. if one does, we may need to
503 		 * replace the locators with a new copy.
504 		 */
505 		c = get_cfdata(0);
506 		for (i = 0; c->cf_driver; i++) {
507 			if (i != devno && c->cf_loc == cd->cf_loc)
508 				share = 1;
509 			c++;
510 		}
511 
512 		ln = get_locnamp(cd->cf_locnames);
513 		l = (long *)adjust((caddr_t)cd->cf_loc);
514 
515 		if (share) {
516 			if (oldkernel) {
517 				printf("Can't do that on this kernel\n");
518 				return;
519 			}
520 
521 			lk = ln;
522 			i = 0;
523 			while (*lk != -1) {
524 				lk++;
525 				i++;
526 			}
527 			lk = ln;
528 
529 			j = l = get_extraloc(i);
530 			if (l == NULL) {
531 				printf("Not enough space to change device.\n");
532 				return;
533 			}
534 			if (i)
535 				bcopy(adjust((caddr_t)cd->cf_loc), l,
536 				    sizeof(long) * i);
537 		}
538 
539 		while (*ln != -1) {
540 			*l = atoi(str);
541 			if (*str == '-')
542 				str++;
543 			while (*str >= '0' && *str <= '9')
544 				str++;
545 			if (*str == ' ')
546 				str++;
547 			ln++;
548 			l++;
549 		}
550 
551 		if (*str) {
552 			cd->cf_flags = atoi(str);
553 			if (*str == '-')
554 				str++;
555 			while (*str >= '0' && *str <= '9')
556 				str++;
557 			if (*str == ' ')
558 				str++;
559 		}
560 
561 		if (share) {
562 			if (bcmp(adjust((caddr_t)cd->cf_loc),
563 			    j, sizeof(long) * i)) {
564 				cd->cf_loc = (long *)readjust((caddr_t)j);
565 			}
566 		}
567 
568 		printf("%3d ", devno);
569 		pdevnam(devno);
570 		printf(" changed\n");
571 		pdev(devno);
572 		return;
573 	}
574 
575 	if (nopdev == 0) {
576 		if (devno > maxdev && devno <= totdev) {
577 			printf("%3d can't change free slot\n", devno);
578 			return;
579 		}
580 		if (devno > totdev && devno <= totdev + maxpseudo) {
581 			pdev(devno);
582 			pi = get_pdevinit(devno-totdev-1);
583 
584 			if (*str) {
585 				pi->pdev_count = atoi(str);
586 				if (*str == '-')
587 					str++;
588 				while (*str >= '0' && *str <= '9')
589 					str++;
590 				if (*str == ' ')
591 					str++;
592 			}
593 
594 			printf("%3d %s changed\n", devno,
595 			    get_pdevnames(devno - totdev - 1));
596 			pdev(devno);
597 			return;
598 		}
599 	}
600 
601 	printf("Unknown devno (max is %d)\n", totdev + maxpseudo);
602 }
603 
604 void
605 disable(int devno)
606 {
607 	struct cfdata *cd;
608 	struct pdevinit *pi;
609 	int done = 0;
610 
611 	if (devno <= maxdev) {
612 
613 		cd = get_cfdata(devno);
614 
615 		switch (cd->cf_fstate) {
616 		case FSTATE_NOTFOUND:
617 			cd->cf_fstate = FSTATE_DNOTFOUND;
618 			break;
619 		case FSTATE_STAR:
620 			cd->cf_fstate = FSTATE_DSTAR;
621 			break;
622 		case FSTATE_DNOTFOUND:
623 		case FSTATE_DSTAR:
624 			done = 1;
625 			break;
626 		default:
627 			printf("Error unknown state\n");
628 			break;
629 		}
630 
631 		printf("%3d ", devno);
632 		pdevnam(devno);
633 		if (done) {
634 			printf(" already");
635 		} else {
636 			ukc_mod_kernel = 1;
637 		}
638 		printf(" disabled\n");
639 
640 		return;
641 	}
642 
643 	if (nopdev == 0) {
644 		if (devno > maxdev && devno <= totdev) {
645 			printf("%3d can't disable free slot\n", devno);
646 			return;
647 		}
648 		if (devno > totdev && devno <= totdev + maxpseudo) {
649 			pi = get_pdevinit(devno-totdev-1);
650 
651 			printf("%3d %s", devno,
652 				get_pdevnames(devno - totdev - 1));
653 			if (pi->pdev_count < 1) {
654 				printf(" already");
655 			} else {
656 				ukc_mod_kernel = 1;
657 				pi->pdev_count*=-1;
658 			}
659 			printf(" disabled\n");
660 			return;
661 		}
662 	}
663 
664 	printf("Unknown devno (max is %d)\n", totdev+maxpseudo);
665 
666 }
667 
668 void
669 enable(int devno)
670 {
671 	struct cfdata *cd;
672 	struct pdevinit *pi;
673 	int done = 0;
674 
675 	if (devno <= maxdev) {
676 		cd = get_cfdata(devno);
677 
678 		switch (cd->cf_fstate) {
679 		case FSTATE_DNOTFOUND:
680 			cd->cf_fstate = FSTATE_NOTFOUND;
681 			break;
682 		case FSTATE_DSTAR:
683 			cd->cf_fstate = FSTATE_STAR;
684 			break;
685 		case FSTATE_NOTFOUND:
686 		case FSTATE_STAR:
687 			done = 1;
688 			break;
689 		default:
690 			printf("Error unknown state\n");
691 			break;
692 		}
693 
694 		printf("%3d ", devno);
695 		pdevnam(devno);
696 		if (done) {
697 			printf(" already");
698 		} else {
699 			ukc_mod_kernel = 1;
700 		}
701 		printf(" enabled\n");
702 
703 		return;
704 	}
705 
706 	if (nopdev == 0) {
707 		if (devno > maxdev && devno <= totdev) {
708 			printf("%3d can't enable free slot\n", devno);
709 			return;
710 		}
711 		if (devno > totdev && devno <= totdev + maxpseudo) {
712 			pi = get_pdevinit(devno-totdev-1);
713 
714 			printf("%3d %s", devno,
715 				get_pdevnames(devno - totdev - 1));
716 			if (pi->pdev_count > 0) {
717 				printf(" already");
718 			} else {
719 				ukc_mod_kernel = 1;
720 				pi->pdev_count*=-1;
721 			}
722 			printf(" enabled\n");
723 			return;
724 		}
725 	}
726 
727 	printf("Unknown devno (max is %d)\n", totdev+maxpseudo);
728 }
729 
730 void
731 show(void)
732 {
733 	caddr_t *p;
734 	int	i = 0;
735 
736 	cnt = 0;
737 
738 	p = get_locnames(0);
739 
740 	while (i <= maxlocnames) {
741 		if (more())
742 			break;
743 		printf("%s\n", (char *)adjust(*p));
744 		p++;
745 		i++;
746 	}
747 
748 	cnt = -1;
749 }
750 
751 void
752 common_attr_val(short attr, int *val, char routine)
753 {
754 	int	i = 0;
755 	struct cfdata *cd;
756 	long	*l;
757 	short *ln;
758 	int quit = 0;
759 
760 	cnt = 0;
761 
762 	cd = get_cfdata(0);
763 
764 	while (cd->cf_attach != 0) {
765 		l = (long *)adjust((caddr_t)cd->cf_loc);
766 		ln = get_locnamp(cd->cf_locnames);
767 		while (*ln != -1) {
768 			if (*ln == attr) {
769 				if (val == NULL) {
770 					quit = more();
771 					pdev(i);
772 				} else {
773 					if (*val == *l) {
774 						quit = more();
775 						switch (routine) {
776 						case UC_ENABLE:
777 							enable(i);
778 							break;
779 						case UC_DISABLE:
780 							disable(i);
781 							break;
782 						case UC_SHOW:
783 							pdev(i);
784 							break;
785 						default:
786 							printf("Unknown routine /%c/\n",
787 							    routine);
788 							break;
789 						}
790 					}
791 				}
792 			}
793 			if (quit)
794 				break;
795 			ln++;
796 			l++;
797 		}
798 		if (quit)
799 			break;
800 		i++;
801 		cd++;
802 	}
803 
804 	cnt = -1;
805 }
806 
807 void
808 show_attr(char *cmd)
809 {
810 	char *c;
811 	caddr_t *p;
812 	short attr = -1, i = 0, l = 0;
813 	int a;
814 
815 	c = cmd;
816 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
817 		c++;
818 		l++;
819 	}
820 	while (*c == ' ' || *c == '\t' || *c == '\n') {
821 		c++;
822 	}
823 
824 	p = get_locnames(0);
825 
826 	while (i <= maxlocnames) {
827 		if (strlen((char *)adjust(*p)) == l) {
828 			if (strncasecmp(cmd, adjust(*p), l) == 0)
829 				attr = i;
830 		}
831 		p++;
832 		i++;
833 	}
834 
835 	if (attr == -1) {
836 		printf("Unknown attribute\n");
837 		return;
838 	}
839 
840 	if (*c == '\0') {
841 		common_attr_val(attr, NULL, UC_SHOW);
842 	} else {
843 		if (number(c, &a) == 0) {
844 			common_attr_val(attr, &a, UC_SHOW);
845 		} else {
846 			printf("Unknown argument\n");
847 		}
848 	}
849 }
850 
851 void
852 common_dev(char *dev, int len, short unit, short state, char routine)
853 {
854 	struct cfdata *cd;
855 	struct cfdriver *cdrv;
856 	int i = 0;
857 
858 	switch (routine) {
859 	case UC_CHANGE:
860 		break;
861 	default:
862 		cnt = 0;
863 		break;
864 	}
865 
866 	cnt = 0;
867 
868 	cd = get_cfdata(0);
869 
870 	while (cd->cf_attach != 0) {
871 		cdrv = (struct cfdriver *)adjust((caddr_t)cd->cf_driver);
872 
873 		if (strlen((char *)adjust(cdrv->cd_name)) == len) {
874 			/*
875 			 * Ok, if device name is correct
876 			 *  If state == FSTATE_FOUND, look for "dev"
877 			 *  If state == FSTATE_STAR, look for "dev*"
878 			 *  If state == FSTATE_NOTFOUND, look for "dev0"
879 			 */
880 			if (!strncasecmp(dev,(char *)adjust(cdrv->cd_name), len) &&
881 			    (state == FSTATE_FOUND ||
882 			    (state == FSTATE_STAR &&
883 			    (cd->cf_fstate == FSTATE_STAR ||
884 			    cd->cf_fstate == FSTATE_DSTAR)) ||
885 			    (state == FSTATE_NOTFOUND &&
886 			    cd->cf_unit == unit &&
887 			    (cd->cf_fstate == FSTATE_NOTFOUND ||
888 			    cd->cf_fstate == FSTATE_DNOTFOUND)))) {
889 				if (more())
890 					break;
891 				switch (routine) {
892 				case UC_CHANGE:
893 					change(i);
894 					break;
895 				case UC_ENABLE:
896 					enable(i);
897 					break;
898 				case UC_DISABLE:
899 					disable(i);
900 					break;
901 				case UC_FIND:
902 					pdev(i);
903 					break;
904 				default:
905 					printf("Unknown routine /%c/\n",
906 					    routine);
907 					break;
908 				}
909 			}
910 		}
911 		i++;
912 		cd++;
913 	}
914 
915 	if (nopdev == 0) {
916 		for (i = 0; i < maxpseudo; i++) {
917 			if (!strncasecmp(dev, (char *)get_pdevnames(i), len) &&
918 			    state == FSTATE_FOUND) {
919 				switch (routine) {
920 				case UC_CHANGE:
921 					change(totdev+1+i);
922 					break;
923 				case UC_ENABLE:
924 					enable(totdev+1+i);
925 					break;
926 				case UC_DISABLE:
927 					disable(totdev+1+i);
928 					break;
929 				case UC_FIND:
930 					pdev(totdev+1+i);
931 					break;
932 				default:
933 					printf("Unknown pseudo routine /%c/\n",
934 					    routine);
935 					break;
936 				}
937 			}
938 		}
939 	}
940 
941 	switch (routine) {
942 	case UC_CHANGE:
943 		break;
944 	default:
945 		cnt = -1;
946 		break;
947 	}
948 }
949 
950 void
951 common_attr(char *cmd, int attr, char routine)
952 {
953 	char *c;
954 	short l = 0;
955 	int a;
956 
957 	c = cmd;
958 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
959 		c++;
960 		l++;
961 	}
962 	while (*c == ' ' || *c == '\t' || *c == '\n') {
963 		c++;
964 	}
965 	if (*c == '\0') {
966 		printf("Value missing for attribute\n");
967 		return;
968 	}
969 
970 	if (number(c, &a) == 0) {
971 		common_attr_val(attr, &a, routine);
972 	} else {
973 		printf("Unknown argument\n");
974 	}
975 }
976 
977 void
978 add_read(char *prompt, char field, char *dev, int len, int *val)
979 {
980 	int ok = 0;
981 	int a;
982 	cmd_t cmd;
983 	struct cfdata *cd;
984 	struct cfdriver *cdrv;
985 
986 	*val = -1;
987 
988 	while (!ok) {
989 		printf("%s ? ", prompt);
990 		fflush(stdout);
991 
992 		ask_cmd(&cmd);
993 
994 		if (strlen(cmd.cmd) != 0) {
995 			if (number(cmd.cmd, &a) == 0) {
996 				if (a > maxdev) {
997 					printf("Unknown devno (max is %d)\n",
998 					    maxdev);
999 				} else {
1000 					cd = get_cfdata(a);
1001 					cdrv = (struct cfdriver *)
1002 					  adjust((caddr_t)cd->cf_driver);
1003 					if (strncasecmp(dev,
1004 							(char *)adjust(cdrv->cd_name),
1005 							len) != 0 &&
1006 					    field == 'a') {
1007 						printf("Not same device type\n");
1008 					} else {
1009 						*val = a;
1010 						ok = 1;
1011 					}
1012 				}
1013 			} else if (cmd.cmd[0] == '?') {
1014 				common_dev(dev, len, 0,
1015 				    FSTATE_FOUND, UC_FIND);
1016 			} else if (cmd.cmd[0] == 'q' ||
1017 				   cmd.cmd[0] == 'Q') {
1018 				ok = 1;
1019 			} else {
1020 				printf("Unknown argument\n");
1021 			}
1022 		} else {
1023 			ok = 1;
1024 		}
1025 	}
1026 
1027 }
1028 
1029 void
1030 add(char *dev, int len, short unit, short state)
1031 {
1032 	int i = 0, found = 0, *p;
1033 	short *pv;
1034 	struct cfdata new, *cd, *cdp;
1035 	struct cfdriver *cdrv;
1036 	int  val, max_unit, star_unit;
1037 
1038 	ukc_mod_kernel = 1;
1039 
1040 	bzero(&new, sizeof(struct cfdata));
1041 
1042 	if (maxdev == totdev) {
1043 		printf("No more space for new devices.\n");
1044 		return;
1045 	}
1046 
1047 	if (state == FSTATE_FOUND) {
1048 		printf("Device not complete number or * is missing\n");
1049 		return;
1050 	}
1051 
1052 	cd = get_cfdata(0);
1053 
1054 	while (cd->cf_attach != 0) {
1055 		cdrv = (struct cfdriver *)adjust((caddr_t)cd->cf_driver);
1056 
1057 		if (strlen((char *)adjust(cdrv->cd_name)) == len &&
1058 		    strncasecmp(dev, (char *)adjust(cdrv->cd_name), len) == 0)
1059 			found = 1;
1060 		cd++;
1061 	}
1062 
1063 	if (!found) {
1064 		printf("No device of this type exists.\n");
1065 		return;
1066 	}
1067 
1068 	add_read("Clone Device (DevNo, 'q' or '?')", 'a', dev, len, &val);
1069 
1070 	if (val != -1) {
1071 		cd = get_cfdata(val);
1072 		new = *cd;
1073 		new.cf_unit = unit;
1074 		new.cf_fstate = state;
1075 		add_read("Insert before Device (DevNo, 'q' or '?')",
1076 		    'i', dev, len, &val);
1077 	}
1078 
1079 	if (val != -1) {
1080 
1081 		/* Insert the new record */
1082 		cdp = cd = get_cfdata(maxdev+1);
1083 		cdp--;
1084 		for (i = maxdev; val <= i; i--) {
1085 			*cd-- = *cdp--;
1086 		}
1087 		cd = get_cfdata(val);
1088 		*cd = new;
1089 
1090 		/* Fix indexs in pv */
1091 		p = (int *)adjust((caddr_t)nl[I_PV_SIZE].n_value);
1092 		pv = (short *)adjust((caddr_t)nl[SA_PV].n_value);
1093 		for (i = 0; i < *p; i++) {
1094 			if (*pv != 1 && *pv >= val)
1095 				*pv = *pv + 1;
1096 			pv++;
1097 		}
1098 
1099 		/* Fix indexs in cfroots */
1100 		p = (int *)adjust((caddr_t)nl[I_CFROOTS_SIZE].n_value);
1101 		pv = (short *)adjust((caddr_t)nl[SA_CFROOTS].n_value);
1102 		for (i = 0; i < *p; i++) {
1103 			if (*pv != 1 && *pv >= val)
1104 				*pv = *pv + 1;
1105 			pv++;
1106 		}
1107 
1108 		maxdev++;
1109 
1110 		max_unit = -1;
1111 
1112 		/* Find max unit number of the device type */
1113 
1114 		cd = get_cfdata(0);
1115 
1116 		while (cd->cf_attach != 0) {
1117 			cdrv = (struct cfdriver *)
1118 			  adjust((caddr_t)cd->cf_driver);
1119 
1120 			if (strlen((char *)adjust(cdrv->cd_name)) == len &&
1121 			    strncasecmp(dev, (char *)adjust(cdrv->cd_name),
1122 			    len) == 0) {
1123 				switch (cd->cf_fstate) {
1124 				case FSTATE_NOTFOUND:
1125 				case FSTATE_DNOTFOUND:
1126 					if (cd->cf_unit > max_unit)
1127 						max_unit = cd->cf_unit;
1128 					break;
1129 				default:
1130 					break;
1131 				}
1132 			}
1133 			cd++;
1134 		}
1135 
1136 		/*
1137 		 * For all * entries set unit number to max+1, and update
1138 		 * cf_starunit1 if necessary.
1139 		 */
1140 		max_unit++;
1141 		star_unit = -1;
1142 		cd = get_cfdata(0);
1143 		while (cd->cf_attach != 0) {
1144 			cdrv = (struct cfdriver *)
1145 			    adjust((caddr_t)cd->cf_driver);
1146 
1147 			if (strlen((char *)adjust(cdrv->cd_name)) == len &&
1148 			    strncasecmp(dev, (char *)adjust(cdrv->cd_name),
1149 			    len) == 0) {
1150 				switch (cd->cf_fstate) {
1151 				case FSTATE_NOTFOUND:
1152 				case FSTATE_DNOTFOUND:
1153 					if (cd->cf_unit > star_unit)
1154 						star_unit = cd->cf_unit;
1155 					break;
1156 				default:
1157 					break;
1158 				}
1159 			}
1160 			cd++;
1161 		}
1162 		star_unit++;
1163 
1164 		cd = get_cfdata(0);
1165 		while (cd->cf_attach != 0) {
1166 			cdrv = (struct cfdriver *)
1167 			    adjust((caddr_t)cd->cf_driver);
1168 
1169 			if (strlen((char *)adjust(cdrv->cd_name)) == len &&
1170 			    strncasecmp(dev, (char *)adjust(cdrv->cd_name),
1171 			    len) == 0) {
1172 				switch (cd->cf_fstate) {
1173 				case FSTATE_STAR:
1174 				case FSTATE_DSTAR:
1175 					cd->cf_unit = max_unit;
1176 					if (cd->cf_starunit1 < star_unit)
1177 						cd->cf_starunit1 = star_unit;
1178 					break;
1179 				default:
1180 					break;
1181 				}
1182 			}
1183 			cd++;
1184 		}
1185 
1186 		pdev(val);
1187 	}
1188 
1189 	/* cf_attach, cf_driver, cf_unit, cf_fstate, cf_loc, cf_flags,
1190 	   cf_parents, cf_locnames, cf_locnames and cf_ivstubs */
1191 }
1192 
1193 void
1194 add_history(int devno, short unit, short state, int newno)
1195 {
1196 	int i = 0, *p;
1197 	short *pv;
1198 	struct cfdata new, *cd, *cdp;
1199 	struct cfdriver *cdrv;
1200 	int  val, max_unit;
1201 	int  len;
1202 	char *dev;
1203 
1204 	ukc_mod_kernel = 1;
1205 
1206 	bzero(&new, sizeof(struct cfdata));
1207 	cd = get_cfdata(devno);
1208 	new = *cd;
1209 	new.cf_unit = unit;
1210 	new.cf_fstate = state;
1211 
1212 	val = newno;
1213 
1214 	cdrv = (struct cfdriver *) adjust((caddr_t)cd->cf_driver);
1215 	dev = adjust((caddr_t)cdrv->cd_name);
1216 	len = strlen(dev);
1217 
1218 	/* Insert the new record */
1219 	cdp = cd = get_cfdata(maxdev+1);
1220 	cdp--;
1221 	for (i = maxdev; val <= i; i--)
1222 		*cd-- = *cdp--;
1223 	cd = get_cfdata(val);
1224 	*cd = new;
1225 
1226 	/* Fix indexs in pv */
1227 	p = (int *)adjust((caddr_t)nl[I_PV_SIZE].n_value);
1228 	pv = (short *)adjust((caddr_t)nl[SA_PV].n_value);
1229 	for (i = 0; i < *p; i++) {
1230 		if (*pv != 1 && *pv >= val)
1231 			*pv = *pv + 1;
1232 		pv++;
1233 	}
1234 
1235 	/* Fix indexs in cfroots */
1236 	p = (int *)adjust((caddr_t)nl[I_CFROOTS_SIZE].n_value);
1237 	pv = (short *)adjust((caddr_t)nl[SA_CFROOTS].n_value);
1238 	for (i = 0; i < *p; i++) {
1239 		if (*pv != 1 && *pv >= val)
1240 			*pv = *pv + 1;
1241 		pv++;
1242 	}
1243 
1244 	maxdev++;
1245 	max_unit = -1;
1246 
1247 	/* Find max unit number of the device type */
1248 	cd = get_cfdata(0);
1249 	while (cd->cf_attach != 0) {
1250 		cdrv = (struct cfdriver *)
1251 		    adjust((caddr_t)cd->cf_driver);
1252 
1253 		if (strlen((char *)adjust(cdrv->cd_name)) == len &&
1254 		    strncasecmp(dev, (char *)adjust(cdrv->cd_name),
1255 		    len) == 0) {
1256 			switch (cd->cf_fstate) {
1257 			case FSTATE_NOTFOUND:
1258 			case FSTATE_DNOTFOUND:
1259 				if (cd->cf_unit > max_unit)
1260 					max_unit = cd->cf_unit;
1261 				break;
1262 			default:
1263 				break;
1264 			}
1265 		}
1266 		cd++;
1267 	}
1268 
1269 	/* For all * entries set unit number to max+1 */
1270 	max_unit++;
1271 	cd = get_cfdata(0);
1272 	while (cd->cf_attach != 0) {
1273 		cdrv = (struct cfdriver *)
1274 		    adjust((caddr_t)cd->cf_driver);
1275 
1276 		if (strlen((char *)adjust(cdrv->cd_name)) == len &&
1277 		    strncasecmp(dev, (char *)adjust(cdrv->cd_name),
1278 		    len) == 0) {
1279 			switch (cd->cf_fstate) {
1280 			case FSTATE_STAR:
1281 			case FSTATE_DSTAR:
1282 				cd->cf_unit = max_unit;
1283 				break;
1284 			default:
1285 				break;
1286 			}
1287 		}
1288 		cd++;
1289 	}
1290 
1291 	printf("%3d ", newno);
1292 	pdevnam(newno);
1293 	printf(" added\n");
1294 	pdev(val);
1295 }
1296 
1297 int
1298 config_fromfile(const char *cmdfile) {
1299 	FILE *fp;
1300 	cmd_t cmd;
1301 	int i;
1302 
1303 	fp = fopen(cmdfile, "r");
1304 	if (fp == NULL)
1305 		err(1, "open %s", cmdfile);
1306 
1307 	/* Set up command table pointer */
1308 	cmd.table = cmd_table;
1309 
1310 	/* Edit cycle */
1311 	do {
1312 		char lbuf[100];
1313 
1314 		/* Get input */
1315 		if (fgets(lbuf, sizeof lbuf, fp) == NULL)
1316 			break;
1317 		parse_cmd(&cmd, lbuf);
1318 
1319 		if (cmd.cmd[0] == '\0')
1320 			continue;
1321 		for (i = 0; cmd_table[i].cmd != NULL; i++)
1322 			if (strstr(cmd_table[i].cmd, cmd.cmd) ==
1323 			    cmd_table[i].cmd)
1324 				break;
1325 
1326 		/* Check for valid command */
1327 		if (cmd_table[i].cmd == NULL) {
1328 			printf("Invalid command '%s'\n", cmd.cmd);
1329 			exit(1);
1330 		}
1331 		strlcpy(cmd.cmd, cmd_table[i].cmd, sizeof cmd.cmd);
1332 
1333 		/* Call function */
1334 		cmd_table[i].fcn(&cmd);
1335 
1336 	} while (1);
1337 	return 1;
1338 }
1339 
1340 int
1341 config(void)
1342 {
1343 	extern char *cmdfile;
1344 	cmd_t cmd;
1345 	int i, st;
1346 
1347 	/* Set up command table pointer */
1348 	cmd.table = cmd_table;
1349 
1350 	if (cmdfile != NULL) {
1351 		return config_fromfile(cmdfile);
1352 	}
1353 
1354 	printf("Enter 'help' for information\n");
1355 
1356 	/* Edit cycle */
1357 	do {
1358 again:
1359 		printf("ukc> ");
1360 		fflush(stdout);
1361 		ask_cmd(&cmd);
1362 
1363 		if (cmd.cmd[0] == '\0')
1364 			goto again;
1365 		for (i = 0; cmd_table[i].cmd != NULL; i++)
1366 			if (strstr(cmd_table[i].cmd, cmd.cmd) ==
1367 			    cmd_table[i].cmd)
1368 				break;
1369 
1370 		/* Quick hack to put in '?' == 'help' */
1371 		if (!strcmp(cmd.cmd, "?"))
1372 			i = 0;
1373 
1374 		/* Check for valid command */
1375 		if (cmd_table[i].cmd == NULL) {
1376 			printf("Invalid command '%s'.  Try 'help'.\n", cmd.cmd);
1377 			continue;
1378 		} else
1379 			strlcpy(cmd.cmd, cmd_table[i].cmd, sizeof cmd.cmd);
1380 
1381 		/* Call function */
1382 		st = cmd_table[i].fcn(&cmd);
1383 
1384 		/* Update status */
1385 		if (st == CMD_EXIT)
1386 			break;
1387 		if (st == CMD_SAVE)
1388 			break;
1389 	} while (1);
1390 
1391 	return (st == CMD_SAVE);
1392 }
1393 
1394 void
1395 process_history(int len, char *buf)
1396 {
1397 	char *c;
1398 	int devno, newno;
1399 	short unit, state;
1400 
1401 	if (len == 0) {
1402 		printf("History is empty\n");
1403 		return;
1404 	}
1405 
1406 	printf("Processing history...\n");
1407 
1408 	buf[len] = 0;
1409 
1410 	c = buf;
1411 
1412 	while (*c != '\0') {
1413 		switch (*c) {
1414 		case 'a':
1415 			c++;
1416 			c++;
1417 			devno = atoi(c);
1418 			while (*c >= '0' && *c <= '9')
1419 				c++;
1420 			c++;
1421 			unit = atoi(c);
1422 			if (*c == '-') c++;
1423 			while (*c >= '0' && *c <= '9')
1424 				c++;
1425 			c++;
1426 			state = atoi(c);
1427 			if (*c == '-')
1428 				c++;
1429 			while (*c >= '0' && *c <= '9')
1430 				c++;
1431 			c++;
1432 			newno = atoi(c);
1433 			while (*c >= '0' && *c <= '9')
1434 				c++;
1435 			add_history(devno, unit, state, newno);
1436 			while (*c != '\n')
1437 				c++;
1438 			c++;
1439 			break;
1440 		case 'c':
1441 			c++;
1442 			c++;
1443 			devno = atoi(c);
1444 			while (*c >= '0' && *c <= '9')
1445 				c++;
1446 			if (*c == ' ')
1447 				c++;
1448 			if (*c != '\n')
1449 				change_history(devno, c);
1450 			while (*c != '\n')
1451 				c++;
1452 			c++;
1453 			break;
1454 		case 'd':
1455 			c++;
1456 			devno = atoi(c);
1457 			disable(devno);
1458 			while (*c != '\n')
1459 				c++;
1460 			c++;
1461 			break;
1462 		case 'e':
1463 			c++;
1464 			devno = atoi(c);
1465 			enable(devno);
1466 			while (*c != '\n')
1467 				c++;
1468 			c++;
1469 			break;
1470 		case 'q':
1471 			while (*c != '\0')
1472 				c++;
1473 			break;
1474 		default:
1475 			printf("unknown command %c\n", *c);
1476 			while (*c != '\0' && *c != '\n')
1477 				c++;
1478 			break;
1479 		}
1480 	}
1481 }
1482