xref: /openbsd/usr.sbin/config/ukcutil.c (revision 404b540a)
1 /*	$OpenBSD: ukcutil.c,v 1.17 2008/03/24 21:35:03 maja 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 #ifndef LINT
28 static	char rcsid[] = "$OpenBSD: ukcutil.c,v 1.17 2008/03/24 21:35:03 maja Exp $";
29 #endif
30 
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/device.h>
34 #include <limits.h>
35 #include <nlist.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #include "cmd.h"
41 #include "exec.h"
42 #include "ukc.h"
43 #include "misc.h"
44 
45 extern	int ukc_mod_kernel;
46 
47 struct	cfdata *
48 get_cfdata(int idx)
49 {
50 	return((struct cfdata *)(adjust((caddr_t)nl[P_CFDATA].n_value) +
51 	    idx * sizeof(struct cfdata)));
52 }
53 
54 short *
55 get_locnamp(int idx)
56 {
57 	return((short *)(adjust((caddr_t)nl[S_LOCNAMP].n_value) +
58 	    idx * sizeof(short)));
59 }
60 
61 caddr_t *
62 get_locnames(int idx)
63 {
64 	return((caddr_t *)(adjust((caddr_t)nl[P_LOCNAMES].n_value) +
65 	    idx * sizeof(caddr_t)));
66 }
67 
68 int *
69 get_extraloc(int idx)
70 {
71 	return((int *)(adjust((caddr_t)nl[IA_EXTRALOC].n_value) +
72 	    idx * sizeof(int)));
73 }
74 
75 char *
76 get_pdevnames(int idx)
77 {
78 	caddr_t *p;
79 
80 	p = (caddr_t *)adjust((caddr_t)nl[P_PDEVNAMES].n_value +
81 	    idx * sizeof(caddr_t));
82 	return(char *)adjust((caddr_t)*p);
83 
84 }
85 
86 struct pdevinit *
87 get_pdevinit(int idx)
88 {
89 	return((struct pdevinit *)(adjust((caddr_t)nl[S_PDEVINIT].n_value) +
90 	    idx * sizeof(struct pdevinit)));
91 }
92 
93 int
94 more(void)
95 {
96 	int quit = 0;
97 	cmd_t cmd;
98 
99 	if (cnt != -1) {
100 		if (cnt > 0 && cnt == lines) {
101 			printf("--- more ---");
102 			fflush(stdout);
103 			ask_cmd(&cmd);
104 			cnt = 0;
105 			if (cmd.cmd[0] == 'q' || cmd.cmd[0] == 'Q')
106 				quit = 1;
107 		}
108 		cnt++;
109 	}
110 	return (quit);
111 }
112 
113 void
114 pnum(int val)
115 {
116 	if (val > -2 && val < 16) {
117 		printf("%d", val);
118 		return;
119 	}
120 
121 	switch (base) {
122 	case 8:
123 		printf("0%o", val);
124 		break;
125 	case 10:
126 		printf("%d", val);
127 		break;
128 	case 16:
129 	default:
130 		printf("0x%x", val);
131 		break;
132 	}
133 }
134 
135 void
136 pdevnam(short devno)
137 {
138 	struct cfdata *cd;
139 	struct cfdriver *cdrv;
140 
141 	cd = get_cfdata(devno);
142 
143 	cdrv = (struct cfdriver *)adjust((caddr_t)cd->cf_driver);
144 
145 #if defined(OLDSCSIBUS)
146 	if (strlen(adjust((caddr_t)cdrv->cd_name)) == 0)
147 		printf("oldscsibus");
148 #endif
149 	printf("%s", adjust((caddr_t)cdrv->cd_name));
150 
151 	switch (cd->cf_fstate) {
152 	case FSTATE_NOTFOUND:
153 	case FSTATE_DNOTFOUND:
154 		printf("%d", cd->cf_unit);
155 		break;
156 	case FSTATE_FOUND:
157 		printf("*FOUND*");
158 		break;
159 	case FSTATE_STAR:
160 	case FSTATE_DSTAR:
161 		printf("*");
162 		break;
163 	default:
164 		printf("*UNKNOWN*");
165 		break;
166 	}
167 }
168 
169 void
170 pdev(short devno)
171 {
172 	struct pdevinit *pi;
173 	struct cfdata *cd;
174 	short	*s, *ln;
175 	int	*i;
176 	caddr_t	*p;
177 	char	c;
178 
179 	if (nopdev == 0) {
180 		if (devno > maxdev && devno <= totdev) {
181 			printf("%3d free slot (for add)\n", devno);
182 			return;
183 		}
184 		if (devno > totdev && devno <= totdev + maxpseudo) {
185 			pi = get_pdevinit(devno - totdev -1);
186 			printf("%3d %s count %d", devno,
187 			    get_pdevnames(devno - totdev - 1),
188 			    abs(pi->pdev_count));
189 			if (pi->pdev_count < 0)
190 				printf(" disable");
191 			printf(" (pseudo device)\n");
192 			return;
193 		}
194 	}
195 
196 	if (devno > maxdev) {
197 		printf("Unknown devno (max is %d)\n", maxdev);
198 		return;
199 	}
200 
201 	cd = get_cfdata(devno);
202 
203 	printf("%3d ", devno);
204 	pdevnam(devno);
205 	printf(" at");
206 
207 	c = ' ';
208 	s = (short *)adjust((caddr_t)cd->cf_parents);
209 	if (*s == -1)
210 		printf(" root");
211 	while (*s != -1) {
212 		printf("%c", c);
213 		pdevnam(*s);
214 		c = '|';
215 		s++;
216 	}
217 	switch (cd->cf_fstate) {
218 	case FSTATE_NOTFOUND:
219 	case FSTATE_FOUND:
220 	case FSTATE_STAR:
221 		break;
222 	case FSTATE_DNOTFOUND:
223 	case FSTATE_DSTAR:
224 		printf(" disable");
225 		break;
226 	default:
227 		printf(" ???");
228 		break;
229 	}
230 
231 	i = (int *)adjust((caddr_t)cd->cf_loc);
232 	ln = get_locnamp(cd->cf_locnames);
233 	while (*ln != -1) {
234 		p = get_locnames(*ln);
235 		printf(" %s ", adjust((caddr_t)*p));
236 		ln++;
237 		pnum(*i);
238 		i++;
239 	}
240 	printf(" flags 0x%x\n", cd->cf_flags);
241 }
242 
243 int
244 number(const char *c, int *val)
245 {
246 	int neg = 0, base = 10;
247 	u_int num = 0;
248 
249 	if (*c == '-') {
250 		neg = 1;
251 		c++;
252 	}
253 	if (*c == '0') {
254 		base = 8;
255 		c++;
256 		if (*c == 'x' || *c == 'X') {
257 			base = 16;
258 			c++;
259 		}
260 	}
261 	while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
262 		u_char cc = *c;
263 
264 		if (cc >= '0' && cc <= '9')
265 			cc = cc - '0';
266 		else if (cc >= 'a' && cc <= 'f')
267 			cc = cc - 'a' + 10;
268 		else if (cc >= 'A' && cc <= 'F')
269 			cc = cc - 'A' + 10;
270 		else
271 			return (-1);
272 
273 		if (cc > base)
274 			return (-1);
275 		num = num * base + cc;
276 		c++;
277 	}
278 
279 	if (neg && num > INT_MAX)	/* overflow */
280 		return (1);
281 	*val = neg ? - num : num;
282 	return (0);
283 }
284 
285 int
286 device(char *cmd, int *len, short *unit, short *state)
287 {
288 	short u = 0, s = FSTATE_FOUND;
289 	int l = 0;
290 	char *c;
291 
292 	c = cmd;
293 	while (*c >= 'a' && *c <= 'z') {
294 		l++;
295 		c++;
296 	}
297 
298 	if (*c == '*') {
299 		s = FSTATE_STAR;
300 		c++;
301 	} else {
302 		while (*c >= '0' && *c <= '9') {
303 			s = FSTATE_NOTFOUND;
304 			u = u*10 + *c - '0';
305 			c++;
306 		}
307 	}
308 	while (*c == ' ' || *c == '\t' || *c == '\n')
309 		c++;
310 
311 	if (*c == '\0') {
312 		*len = l;
313 		*unit = u;
314 		*state = s;
315 		return(0);
316 	}
317 	return(-1);
318 }
319 
320 int
321 attr(char *cmd, int *val)
322 {
323 	short attr = -1, i = 0, l = 0;
324 	caddr_t *p;
325 	char *c;
326 
327 	c = cmd;
328 	while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
329 		c++;
330 		l++;
331 	}
332 
333 	p = get_locnames(0);
334 
335 	while (i <= maxlocnames) {
336 		if (strlen((char *)adjust((caddr_t)*p)) == l) {
337 			if (strncasecmp(cmd, adjust((caddr_t)*p), l) == 0)
338 				attr = i;
339 		}
340 		p++;
341 		i++;
342 	}
343 	if (attr == -1)
344 		return (-1);
345 
346 	*val = attr;
347 	return(0);
348 }
349 
350 void
351 modify(char *item, int *val)
352 {
353 	cmd_t cmd;
354 	int a;
355 
356 	ukc_mod_kernel = 1;
357 	while (1) {
358 		printf("%s [", item);
359 		pnum(*val);
360 		printf("] ? ");
361 		fflush(stdout);
362 
363 		ask_cmd(&cmd);
364 
365 		if (strlen(cmd.cmd) != 0) {
366 			if (strlen(cmd.args) == 0) {
367 				if (number(cmd.cmd, &a) == 0) {
368 					*val = a;
369 					break;
370 				} else
371 					printf("Unknown argument\n");
372 			} else
373 				printf("Too many arguments\n");
374 		} else
375 			break;
376 	}
377 }
378 
379 void
380 change(int devno)
381 {
382 	int	i, share = 0, *j = NULL, *k = NULL, *l;
383 	struct cfdata *cd, *c;
384 	struct pdevinit *pi;
385 	short	*ln, *lk;
386 	caddr_t	*p;
387 
388 	ukc_mod_kernel = 1;
389 	if (devno <=  maxdev) {
390 		pdev(devno);
391 		if (!ask_yn("change"))
392 			return;
393 
394 		cd = get_cfdata(devno);
395 
396 		/*
397 		 * Search for some other driver sharing this
398 		 * locator table. if one does, we may need to
399 		 * replace the locators with a new copy.
400 		 */
401 		c = get_cfdata(0);
402 		for (i = 0; c->cf_driver; i++) {
403 			if (i != devno && c->cf_loc == cd->cf_loc)
404 				share = 1;
405 			c++;
406 		}
407 
408 		ln = get_locnamp(cd->cf_locnames);
409 		l = (int *)adjust((caddr_t)cd->cf_loc);
410 
411 		if (share) {
412 			if (oldkernel) {
413 				printf("Can't do that on this kernel\n");
414 				return;
415 			}
416 
417 			lk = ln;
418 			i = 0;
419 			while (*lk != -1) {
420 				lk++;
421 				i++;
422 			}
423 			lk = ln;
424 
425 			j = (int *)adjust((caddr_t)nl[I_NEXTRALOC].n_value);
426 			k = (int *)adjust((caddr_t)nl[I_UEXTRALOC].n_value);
427 			if ((i + *k) > *j) {
428 				printf("Not enough space to change device.\n");
429 				return;
430 			}
431 
432 			j = l = get_extraloc(*k);
433 			bcopy(adjust((caddr_t)cd->cf_loc),
434 			    l, sizeof(int) * i);
435 		}
436 
437 		while (*ln != -1) {
438 			p = get_locnames(*ln);
439 			modify((char *)adjust(*p), l);
440 			ln++;
441 			l++;
442 		}
443 		modify("flags", &cd->cf_flags);
444 
445 		if (share) {
446 			if (bcmp(adjust((caddr_t)cd->cf_loc), j,
447 			    sizeof(int) * i)) {
448 				cd->cf_loc = (int *)readjust((caddr_t)j);
449 				*k = *k + i;
450 			}
451 		}
452 
453 		printf("%3d ", devno);
454 		pdevnam(devno);
455 		printf(" changed\n");
456 		pdev(devno);
457 		return;
458 	}
459 
460 	if (nopdev == 0) {
461 		if (devno > maxdev && devno <= totdev) {
462 			printf("%3d can't change free slot\n", devno);
463 			return;
464 		}
465 
466 		if (devno > totdev && devno <= totdev + maxpseudo) {
467 			pdev(devno);
468 			if (ask_yn("change")) {
469 				pi = get_pdevinit(devno-totdev-1);
470 				modify("count", &pi->pdev_count);
471 				printf("%3d %s changed\n", devno,
472 				    get_pdevnames(devno - totdev - 1));
473 				pdev(devno);
474 			}
475 			return;
476 		}
477 	}
478 
479 	printf("Unknown devno (max is %d)\n", totdev+maxpseudo);
480 }
481 
482 void
483 change_history(int devno, char *str)
484 {
485 	int	i, share = 0, *j = NULL, *k = NULL, *l;
486 	struct cfdata *cd, *c;
487 	struct pdevinit *pi;
488 	short	*ln, *lk;
489 
490 	ukc_mod_kernel = 1;
491 
492 	if (devno <= maxdev) {
493 
494 		pdev(devno);
495 		cd = get_cfdata(devno);
496 
497 		/*
498 		 * Search for some other driver sharing this
499 		 * locator table. if one does, we may need to
500 		 * replace the locators with a new copy.
501 		 */
502 		c = get_cfdata(0);
503 		for (i = 0; c->cf_driver; i++) {
504 			if (i != devno && c->cf_loc == cd->cf_loc)
505 				share = 1;
506 			c++;
507 		}
508 
509 		ln = get_locnamp(cd->cf_locnames);
510 		l = (int *)adjust((caddr_t)cd->cf_loc);
511 
512 		if (share) {
513 			if (oldkernel) {
514 				printf("Can't do that on this kernel\n");
515 				return;
516 			}
517 
518 			lk = ln;
519 			i = 0;
520 			while (*lk != -1) {
521 				lk++;
522 				i++;
523 			}
524 			lk = ln;
525 
526 			j = (int *)adjust((caddr_t)nl[I_NEXTRALOC].n_value);
527 			k = (int *)adjust((caddr_t)nl[I_UEXTRALOC].n_value);
528 			if ((i + *k) > *j) {
529 				printf("Not enough space to change device.\n");
530 				return;
531 			}
532 
533 			j = l = get_extraloc(*k);
534 			bcopy(adjust((caddr_t)cd->cf_loc),
535 			    l, sizeof(int) * i);
536 		}
537 
538 		while (*ln != -1) {
539 			*l = atoi(str);
540 			if (*str == '-')
541 				str++;
542 			while (*str >= '0' && *str <= '9')
543 				str++;
544 			if (*str == ' ')
545 				str++;
546 			ln++;
547 			l++;
548 		}
549 
550 		if (*str) {
551 			cd->cf_flags = atoi(str);
552 			if (*str == '-')
553 				str++;
554 			while (*str >= '0' && *str <= '9')
555 				str++;
556 			if (*str == ' ')
557 				str++;
558 		}
559 
560 		if (share) {
561 			if (bcmp(adjust((caddr_t)cd->cf_loc),
562 			    j, sizeof(int) * i)) {
563 				cd->cf_loc = (int *)readjust((caddr_t)j);
564 				*k = *k + i;
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 	int   *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 = (int *)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(void)
1299 {
1300 	cmd_t cmd;
1301 	int i, st;
1302 
1303 	/* Set up command table pointer */
1304 	cmd.table = cmd_table;
1305 
1306 	printf("Enter 'help' for information\n");
1307 
1308 	/* Edit cycle */
1309 	do {
1310 again:
1311 		printf("ukc> ");
1312 		fflush(stdout);
1313 		ask_cmd(&cmd);
1314 
1315 		if (cmd.cmd[0] == '\0')
1316 			goto again;
1317 		for (i = 0; cmd_table[i].cmd != NULL; i++)
1318 			if (strstr(cmd_table[i].cmd, cmd.cmd) ==
1319 			    cmd_table[i].cmd)
1320 				break;
1321 
1322 		/* Quick hack to put in '?' == 'help' */
1323 		if (!strcmp(cmd.cmd, "?"))
1324 			i = 0;
1325 
1326 		/* Check for valid command */
1327 		if (cmd_table[i].cmd == NULL) {
1328 			printf("Invalid command '%s'.  Try 'help'.\n", cmd.cmd);
1329 			continue;
1330 		} else
1331 			strlcpy(cmd.cmd, cmd_table[i].cmd, sizeof cmd.cmd);
1332 
1333 		/* Call function */
1334 		st = cmd_table[i].fcn(&cmd);
1335 
1336 		/* Update status */
1337 		if (st == CMD_EXIT)
1338 			break;
1339 		if (st == CMD_SAVE)
1340 			break;
1341 	} while (1);
1342 
1343 	return (st == CMD_SAVE);
1344 }
1345 
1346 void
1347 process_history(int len, char *buf)
1348 {
1349 	char *c;
1350 	int devno, newno;
1351 	short unit, state;
1352 	struct timezone *tz;
1353 
1354 	if (len == 0) {
1355 		printf("History is empty\n");
1356 		return;
1357 	}
1358 
1359 	printf("Processing history...\n");
1360 
1361 	buf[len] = 0;
1362 
1363 	c = buf;
1364 
1365 	while (*c != NULL) {
1366 		switch (*c) {
1367 		case 'a':
1368 			c++;
1369 			c++;
1370 			devno = atoi(c);
1371 			while (*c >= '0' && *c <= '9')
1372 				c++;
1373 			c++;
1374 			unit = atoi(c);
1375 			if (*c == '-') c++;
1376 			while (*c >= '0' && *c <= '9')
1377 				c++;
1378 			c++;
1379 			state = atoi(c);
1380 			if (*c == '-')
1381 				c++;
1382 			while (*c >= '0' && *c <= '9')
1383 				c++;
1384 			c++;
1385 			newno = atoi(c);
1386 			while (*c >= '0' && *c <= '9')
1387 				c++;
1388 			add_history(devno, unit, state, newno);
1389 			while (*c != '\n')
1390 				c++;
1391 			c++;
1392 			break;
1393 		case 'c':
1394 			c++;
1395 			c++;
1396 			devno = atoi(c);
1397 			while (*c >= '0' && *c <= '9')
1398 				c++;
1399 			if (*c == ' ')
1400 				c++;
1401 			if (*c != '\n')
1402 				change_history(devno, c);
1403 			while (*c != '\n')
1404 				c++;
1405 			c++;
1406 			break;
1407 		case 'd':
1408 			c++;
1409 			devno = atoi(c);
1410 			disable(devno);
1411 			while (*c != '\n')
1412 				c++;
1413 			c++;
1414 			break;
1415 		case 'e':
1416 			c++;
1417 			devno = atoi(c);
1418 			enable(devno);
1419 			while (*c != '\n')
1420 				c++;
1421 			c++;
1422 			break;
1423 		case 't':
1424 			c++;
1425 			c++;
1426 			tz = (struct timezone *)adjust((caddr_t)nl[TZ_TZ].
1427 			    n_value);
1428 			tz->tz_minuteswest = atoi(c);
1429 			while (*c != ' ')
1430 				c++;
1431 			c++;
1432 			tz->tz_dsttime = atoi(c);
1433 			while (*c != '\n')
1434 				c++;
1435 			c++;
1436 			ukc_mod_kernel = 1;
1437 			break;
1438 		case 'q':
1439 			while (*c != NULL)
1440 				c++;
1441 			break;
1442 		default:
1443 			printf("unknown command %c\n", *c);
1444 			while (*c != NULL && *c != '\n')
1445 				c++;
1446 			break;
1447 		}
1448 	}
1449 }
1450