xref: /netbsd-src/sys/kern/kern_subr.c (revision 1394f01b4a9e99092957ca5d824d67219565d9b5)
1 /*	$NetBSD: kern_subr.c,v 1.27 1997/06/16 00:25:05 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Jason R. Thorpe.  All rights reserved.
5  * Copyright (c) 1982, 1986, 1991, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  * (c) UNIX System Laboratories, Inc.
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Copyright (c) 1992, 1993
14  *	The Regents of the University of California.  All rights reserved.
15  *
16  * This software was developed by the Computer Systems Engineering group
17  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
18  * contributed to Berkeley.
19  *
20  * All advertising materials mentioning features or use of this software
21  * must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Lawrence Berkeley Laboratory.
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  * 1. Redistributions of source code must retain the above copyright
29  *    notice, this list of conditions and the following disclaimer.
30  * 2. Redistributions in binary form must reproduce the above copyright
31  *    notice, this list of conditions and the following disclaimer in the
32  *    documentation and/or other materials provided with the distribution.
33  * 3. All advertising materials mentioning features or use of this software
34  *    must display the following acknowledgement:
35  *	This product includes software developed by the University of
36  *	California, Berkeley and its contributors.
37  * 4. Neither the name of the University nor the names of its contributors
38  *    may be used to endorse or promote products derived from this software
39  *    without specific prior written permission.
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  *	@(#)kern_subr.c	8.3 (Berkeley) 1/21/94
54  */
55 
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/proc.h>
59 #include <sys/malloc.h>
60 #include <sys/mount.h>
61 #include <sys/device.h>
62 #include <sys/reboot.h>
63 #include <sys/conf.h>
64 #include <sys/disklabel.h>
65 #include <sys/queue.h>
66 
67 #include <dev/cons.h>
68 
69 #include <net/if.h>
70 
71 /* XXX these should eventually move to subr_autoconf.c */
72 static int findblkmajor __P((const char *, struct devnametobdevmaj *));
73 static const char *findblkname __P((int, struct devnametobdevmaj *));
74 static struct device *getdisk __P((char *, int, int,
75 	struct devnametobdevmaj *, dev_t *, int));
76 static struct device *parsedisk __P((char *, int, int,
77 	struct devnametobdevmaj *, dev_t *));
78 static int getstr __P((char *, int));
79 
80 int
81 uiomove(buf, n, uio)
82 	register void *buf;
83 	register int n;
84 	register struct uio *uio;
85 {
86 	register struct iovec *iov;
87 	u_int cnt;
88 	int error = 0;
89 	char *cp = buf;
90 
91 #ifdef DIAGNOSTIC
92 	if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
93 		panic("uiomove: mode");
94 	if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
95 		panic("uiomove proc");
96 #endif
97 	while (n > 0 && uio->uio_resid) {
98 		iov = uio->uio_iov;
99 		cnt = iov->iov_len;
100 		if (cnt == 0) {
101 			uio->uio_iov++;
102 			uio->uio_iovcnt--;
103 			continue;
104 		}
105 		if (cnt > n)
106 			cnt = n;
107 		switch (uio->uio_segflg) {
108 
109 		case UIO_USERSPACE:
110 			if (uio->uio_rw == UIO_READ)
111 				error = copyout(cp, iov->iov_base, cnt);
112 			else
113 				error = copyin(iov->iov_base, cp, cnt);
114 			if (error)
115 				return (error);
116 			break;
117 
118 		case UIO_SYSSPACE:
119 			if (uio->uio_rw == UIO_READ)
120 				bcopy(cp, iov->iov_base, cnt);
121 			else
122 				bcopy(iov->iov_base, cp, cnt);
123 			break;
124 		}
125 		iov->iov_base += cnt;
126 		iov->iov_len -= cnt;
127 		uio->uio_resid -= cnt;
128 		uio->uio_offset += cnt;
129 		cp += cnt;
130 		n -= cnt;
131 	}
132 	return (error);
133 }
134 
135 /*
136  * Give next character to user as result of read.
137  */
138 int
139 ureadc(c, uio)
140 	register int c;
141 	register struct uio *uio;
142 {
143 	register struct iovec *iov;
144 
145 	if (uio->uio_resid <= 0)
146 		panic("ureadc: non-positive resid");
147 again:
148 	if (uio->uio_iovcnt <= 0)
149 		panic("ureadc: non-positive iovcnt");
150 	iov = uio->uio_iov;
151 	if (iov->iov_len <= 0) {
152 		uio->uio_iovcnt--;
153 		uio->uio_iov++;
154 		goto again;
155 	}
156 	switch (uio->uio_segflg) {
157 
158 	case UIO_USERSPACE:
159 		if (subyte(iov->iov_base, c) < 0)
160 			return (EFAULT);
161 		break;
162 
163 	case UIO_SYSSPACE:
164 		*iov->iov_base = c;
165 		break;
166 	}
167 	iov->iov_base++;
168 	iov->iov_len--;
169 	uio->uio_resid--;
170 	uio->uio_offset++;
171 	return (0);
172 }
173 
174 /*
175  * General routine to allocate a hash table.
176  */
177 void *
178 hashinit(elements, type, hashmask)
179 	int elements, type;
180 	u_long *hashmask;
181 {
182 	long hashsize;
183 	LIST_HEAD(generic, generic) *hashtbl;
184 	int i;
185 
186 	if (elements <= 0)
187 		panic("hashinit: bad cnt");
188 	for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
189 		continue;
190 	hashsize >>= 1;
191 	hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK);
192 	for (i = 0; i < hashsize; i++)
193 		LIST_INIT(&hashtbl[i]);
194 	*hashmask = hashsize - 1;
195 	return (hashtbl);
196 }
197 
198 /*
199  * "Shutdown hook" types, functions, and variables.
200  */
201 
202 struct shutdownhook_desc {
203 	LIST_ENTRY(shutdownhook_desc) sfd_list;
204 	void	(*sfd_fn) __P((void *));
205 	void	*sfd_arg;
206 };
207 
208 LIST_HEAD(, shutdownhook_desc) shutdownhook_list;
209 
210 void *
211 shutdownhook_establish(fn, arg)
212 	void (*fn) __P((void *));
213 	void *arg;
214 {
215 	struct shutdownhook_desc *ndp;
216 
217 	ndp = (struct shutdownhook_desc *)
218 	    malloc(sizeof (*ndp), M_DEVBUF, M_NOWAIT);
219 	if (ndp == NULL)
220 		return NULL;
221 
222 	ndp->sfd_fn = fn;
223 	ndp->sfd_arg = arg;
224 	LIST_INSERT_HEAD(&shutdownhook_list, ndp, sfd_list);
225 
226 	return (ndp);
227 }
228 
229 void
230 shutdownhook_disestablish(vhook)
231 	void *vhook;
232 {
233 #ifdef DIAGNOSTIC
234 	struct shutdownhook_desc *dp;
235 
236 	for (dp = shutdownhook_list.lh_first; dp != NULL;
237 	    dp = dp->sfd_list.le_next)
238                 if (dp == vhook)
239 			break;
240 	if (dp == NULL)
241 		panic("shutdownhook_disestablish: hook not established");
242 #endif
243 
244 	LIST_REMOVE((struct shutdownhook_desc *)vhook, sfd_list);
245 	free(vhook, M_DEVBUF);
246 }
247 
248 /*
249  * Run shutdown hooks.  Should be invoked immediately before the
250  * system is halted or rebooted, i.e. after file systems unmounted,
251  * after crash dump done, etc.
252  *
253  * Each shutdown hook is removed from the list before it's run, so that
254  * it won't be run again.
255  */
256 void
257 doshutdownhooks()
258 {
259 	struct shutdownhook_desc *dp;
260 
261 	while ((dp = shutdownhook_list.lh_first) != NULL) {
262 		LIST_REMOVE(dp, sfd_list);
263 		(*dp->sfd_fn)(dp->sfd_arg);
264 #if 0
265 		/*
266 		 * Don't bother freeing the hook structure,, since we may
267 		 * be rebooting because of a memory corruption problem,
268 		 * and this might only make things worse.  It doesn't
269 		 * matter, anyway, since the system is just about to
270 		 * reboot.
271 		 */
272 		free(dp, M_DEVBUF);
273 #endif
274 	}
275 }
276 
277 /*
278  * "Mountroot hook" types, functions, and variables.
279  */
280 
281 struct mountroothook_desc {
282 	LIST_ENTRY(mountroothook_desc) mrd_list;
283 	struct	device *mrd_device;
284 	void 	(*mrd_func) __P((struct device *));
285 };
286 
287 LIST_HEAD(, mountroothook_desc) mountroothook_list;
288 
289 void *
290 mountroothook_establish(func, dev)
291 	void (*func) __P((struct device *));
292 	struct device *dev;
293 {
294 	struct mountroothook_desc *mrd;
295 
296 	mrd = (struct mountroothook_desc *)
297 	    malloc(sizeof(*mrd), M_DEVBUF, M_NOWAIT);
298 	if (mrd == NULL)
299 		return (NULL);
300 
301 	mrd->mrd_device = dev;
302 	mrd->mrd_func = func;
303 	LIST_INSERT_HEAD(&mountroothook_list, mrd, mrd_list);
304 
305 	return (mrd);
306 }
307 
308 void
309 mountroothook_disestablish(vhook)
310 	void *vhook;
311 {
312 #ifdef DIAGNOSTIC
313 	struct mountroothook_desc *mrd;
314 
315 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
316 	    mrd = mrd->mrd_list.le_next)
317                 if (mrd == vhook)
318 			break;
319 	if (mrd == NULL)
320 		panic("mountroothook_disestablish: hook not established");
321 #endif
322 
323 	LIST_REMOVE((struct mountroothook_desc *)vhook, mrd_list);
324 	free(vhook, M_DEVBUF);
325 }
326 
327 void
328 mountroothook_destroy()
329 {
330 	struct mountroothook_desc *mrd;
331 
332 	while ((mrd = mountroothook_list.lh_first) != NULL) {
333 		LIST_REMOVE(mrd, mrd_list);
334 		free(mrd, M_DEVBUF);
335 	}
336 }
337 
338 void
339 domountroothook()
340 {
341 	struct mountroothook_desc *mrd;
342 
343 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
344 	    mrd = mrd->mrd_list.le_next) {
345 		if (mrd->mrd_device == root_device) {
346 			(*mrd->mrd_func)(root_device);
347 			return;
348 		}
349 	}
350 }
351 
352 /*
353  * Determine the root device and, if instructed to, the root file system.
354  */
355 
356 #include "md.h"
357 #if NMD == 0
358 #undef MEMORY_DISK_HOOKS
359 #endif
360 
361 #ifdef MEMORY_DISK_HOOKS
362 static struct device fakemdrootdev = { DV_DISK, {}, NULL, 0, "md0", NULL };
363 #endif
364 
365 void
366 setroot(bootdv, bootpartition, nam2blk)
367 	struct device *bootdv;
368 	int bootpartition;
369 	struct devnametobdevmaj *nam2blk;
370 {
371 	struct device *dv;
372 	register int len, i;
373 	dev_t nrootdev;
374 	dev_t ndumpdev = NODEV;
375 	char buf[128];
376 	const char *rootdevname;
377 	const char *dumpdevname;
378 	struct device *rootdv = NULL;		/* XXX gcc -Wuninitialized */
379 	struct device *dumpdv = NULL;
380 	struct ifnet *ifp;
381 	const char *deffsname;
382 	struct vfsops *vops;
383 	extern int (*mountroot) __P((void));
384 	static struct devnametobdevmaj *last_nam2blk;
385 
386 	if (nam2blk == NULL) {
387 		if (last_nam2blk == NULL)
388 			panic("setroot: no name to bdev major map");
389 		nam2blk = last_nam2blk;
390 	}
391 	last_nam2blk = nam2blk;
392 
393 #ifdef MEMORY_DISK_IS_ROOT
394 	bootdv = &fakemdrootdev;
395 	bootpartition = 0;
396 #endif
397 
398 	/*
399 	 * If NFS is specified as the file system, and we found
400 	 * a DV_DISK boot device (or no boot device at all), then
401 	 * find a reasonable network interface for "rootspec".
402 	 */
403 	vops = vfs_getopsbyname("nfs");
404 	if (vops != NULL && vops->vfs_mountroot == mountroot &&
405 	    rootspec == NULL &&
406 	    (bootdv == NULL || bootdv->dv_class != DV_IFNET)) {
407 		for (ifp = ifnet.tqh_first; ifp != NULL;
408 		    ifp = ifp->if_list.tqe_next)
409 			if ((ifp->if_flags &
410 			     (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
411 				break;
412 		if (ifp == NULL) {
413 			/*
414 			 * Can't find a suitable interface; ask the
415 			 * user.
416 			 */
417 			boothowto |= RB_ASKNAME;
418 		} else {
419 			/*
420 			 * Have a suitable interface; behave as if
421 			 * the user specified this interface.
422 			 */
423 			rootspec = (const char *)ifp->if_xname;
424 		}
425 	}
426 
427 	/*
428 	 * If wildcarded root and we the boot device wasn't determined,
429 	 * ask the user.
430 	 */
431 	if (rootspec == NULL && bootdv == NULL)
432 		boothowto |= RB_ASKNAME;
433 
434  top:
435 	if (boothowto & RB_ASKNAME) {
436 		struct device *defdumpdv;
437 
438 		for (;;) {
439 			printf("root device");
440 			if (bootdv != NULL) {
441 				printf(" (default %s", bootdv->dv_xname);
442 				if (bootdv->dv_class == DV_DISK)
443 					printf("%c", bootpartition + 'a');
444 				printf(")");
445 			}
446 			printf(": ");
447 			len = getstr(buf, sizeof(buf));
448 			if (len == 0 && bootdv != NULL) {
449 				strcpy(buf, bootdv->dv_xname);
450 				len = strlen(buf);
451 			}
452 			if (len > 0 && buf[len - 1] == '*') {
453 				buf[--len] = '\0';
454 				dv = getdisk(buf, len, 1, nam2blk,
455 				    &nrootdev, 0);
456 				if (dv != NULL) {
457 					rootdv = dv;
458 					break;
459 				}
460 			}
461 			dv = getdisk(buf, len, bootpartition, nam2blk,
462 			    &nrootdev, 0);
463 			if (dv != NULL) {
464 				rootdv = dv;
465 				break;
466 			}
467 		}
468 
469 		/*
470 		 * Set up the default dump device.  If root is on
471 		 * a network device, there is no default dump
472 		 * device, since we don't support dumps to the
473 		 * network.
474 		 */
475 		if (rootdv->dv_class == DV_IFNET)
476 			defdumpdv = NULL;
477 		else
478 			defdumpdv = rootdv;
479 
480 		for (;;) {
481 			printf("dump device");
482 			if (defdumpdv != NULL) {
483 				/*
484 				 * Note, we know it's a disk if we get here.
485 				 */
486 				printf(" (default %sb)", defdumpdv->dv_xname);
487 			}
488 			printf(": ");
489 			len = getstr(buf, sizeof(buf));
490 			if (len == 0) {
491 				if (defdumpdv != NULL) {
492 					ndumpdev = MAKEDISKDEV(major(nrootdev),
493 					    DISKUNIT(nrootdev), 1);
494 				}
495 				if (rootdv->dv_class == DV_IFNET)
496 					dumpdv = NULL;
497 				else
498 					dumpdv = rootdv;
499 				break;
500 			}
501 			if (len == 4 && strcmp(buf, "none") == 0) {
502 				dumpspec = "none";
503 				goto havedump;
504 			}
505 			dv = getdisk(buf, len, 1, nam2blk, &ndumpdev, 1);
506 			if (dv) {
507 				dumpdv = dv;
508 				break;
509 			}
510 		}
511 
512  havedump:
513 		rootdev = nrootdev;
514 		dumpdev = ndumpdev;
515 
516 		for (i = 0; i < nvfssw; i++) {
517 			if (vfssw[i] != NULL &&
518 			    vfssw[i]->vfs_mountroot != NULL &&
519 			    vfssw[i]->vfs_mountroot == mountroot)
520 				break;
521 		}
522 		if (i >= nvfssw) {
523 			mountroot = NULL;
524 			deffsname = "generic";
525 		} else
526 			deffsname = vfssw[i]->vfs_name;
527 		for (;;) {
528 			printf("file system (default %s): ", deffsname);
529 			len = getstr(buf, sizeof(buf));
530 			if (len == 0)
531 				break;
532 			if (len == 4 && strcmp(buf, "halt") == 0)
533 				cpu_reboot(RB_HALT, NULL);
534 			else if (len == 7 && strcmp(buf, "generic") == 0) {
535 				mountroot = NULL;
536 				break;
537 			}
538 			vops = vfs_getopsbyname(buf);
539 			if (vops == NULL || vops->vfs_mountroot == NULL) {
540 				printf("use one of: generic");
541 				for (i = 0; i < nvfssw; i++)
542 					if (vfssw[i] != NULL &&
543 					    vfssw[i]->vfs_mountroot != NULL)
544 						printf(" %s",
545 						    vfssw[i]->vfs_name);
546 				printf(" halt\n");
547 			} else {
548 				mountroot = vops->vfs_mountroot;
549 				break;
550 			}
551 		}
552 
553 	} else if (rootspec == NULL) {
554 		int majdev;
555 
556 		/*
557 		 * Wildcarded root; use the boot device.
558 		 */
559 		rootdv = bootdv;
560 
561 		majdev = findblkmajor(bootdv->dv_xname, nam2blk);
562 		if (majdev >= 0) {
563 			/*
564 			 * Root is on a disk.  `bootpartition' is root.
565 			 */
566 			rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
567 			    bootpartition);
568 		}
569 	} else {
570 
571 		/*
572 		 * `root on <dev> ...'
573 		 */
574 
575 		/*
576 		 * If it's a network interface, we can bail out
577 		 * early.
578 		 */
579 		for (dv = alldevs.tqh_first; dv != NULL;
580 		    dv = dv->dv_list.tqe_next)
581 			if (strcmp(dv->dv_xname, rootspec) == 0)
582 				break;
583 		if (dv != NULL && dv->dv_class == DV_IFNET) {
584 			rootdv = dv;
585 			goto haveroot;
586 		}
587 
588 		rootdevname = findblkname(major(rootdev), nam2blk);
589 		if (rootdevname == NULL) {
590 			printf("unknown device major 0x%x\n", rootdev);
591 			boothowto |= RB_ASKNAME;
592 			goto top;
593 		}
594 		bzero(buf, sizeof(buf));
595 		sprintf(buf, "%s%d", rootdevname, DISKUNIT(rootdev));
596 
597 		for (dv = alldevs.tqh_first; dv != NULL;
598 		    dv = dv->dv_list.tqe_next) {
599 			if (strcmp(buf, dv->dv_xname) == 0) {
600 				rootdv = dv;
601 				break;
602 			}
603 		}
604 		if (rootdv == NULL) {
605 			printf("device %s (0x%x) not configured\n",
606 			    buf, rootdev);
607 			boothowto |= RB_ASKNAME;
608 			goto top;
609 		}
610 	}
611 
612  haveroot:
613 
614 	root_device = rootdv;
615 
616 	switch (rootdv->dv_class) {
617 	case DV_IFNET:
618 		/* Nothing. */
619 		break;
620 
621 	case DV_DISK:
622 		printf("root on %s%c", rootdv->dv_xname,
623 		    DISKPART(rootdev) + 'a');
624 		break;
625 
626 	default:
627 		printf("can't determine root device\n");
628 		boothowto |= RB_ASKNAME;
629 		goto top;
630 	}
631 
632 	/*
633 	 * Now configure the dump device.
634 	 */
635 
636 	if (dumpspec != NULL && strcmp(dumpspec, "none") == 0) {
637 		/*
638 		 * Operator doesn't want a dump device.
639 		 */
640 		goto nodumpdev;
641 	}
642 
643 	/*
644 	 * If we haven't figured out the dump device, do so, with
645 	 * the following rules:
646 	 *
647 	 *	(a) We already know dumpdv in the RB_ASKNAME case.
648 	 *
649 	 *	(b) If dumpspec is set, try to use it.  If the device
650 	 *	    is not available, punt.
651 	 *
652 	 *	(c) If dumpspec is not set, the dump device is
653 	 *	    wildcarded or unspecified.  If the root device
654 	 *	    is DV_IFNET, punt.  Otherwise, use partition b
655 	 *	    of the root device.
656 	 */
657 
658 	if (boothowto & RB_ASKNAME) {
659 		if (dumpdv == NULL) {
660 			/*
661 			 * Just return; dumpdev is already set to NODEV
662 			 * and we don't want to print a newline in this
663 			 * case.
664 			 */
665 			return;
666 		}
667 		goto out;
668 	}
669 
670 	if (dumpspec != NULL) {
671 		if (dumpdev == NODEV) {
672 			/*
673 			 * Looks like they tried to pick a network
674 			 * device.  Oops.
675 			 */
676 			goto nodumpdev;
677 		}
678 
679 		dumpdevname = findblkname(major(dumpdev), nam2blk);
680 		if (dumpdevname == NULL)
681 			goto nodumpdev;
682 		bzero(buf, sizeof(buf));
683 		sprintf(buf, "%s%d", dumpdevname, DISKUNIT(dumpdev));
684 
685 		for (dv = alldevs.tqh_first; dv != NULL;
686 		    dv = dv->dv_list.tqe_next) {
687 			if (strcmp(buf, dv->dv_xname) == 0) {
688 				dumpdv = dv;
689 				break;
690 			}
691 		}
692 		if (dv == NULL) {
693 			/*
694 			 * Device not configured.
695 			 */
696 			goto nodumpdev;
697 		}
698 	} else if (rootdv->dv_class == DV_IFNET)
699 		goto nodumpdev;
700 	else {
701 		dumpdv = rootdv;
702 		dumpdev = MAKEDISKDEV(major(rootdev), dumpdv->dv_unit, 1);
703 	}
704 
705  out:
706 	printf(" dumps on %s%c\n", dumpdv->dv_xname, DISKPART(dumpdev) + 'a');
707 	return;
708 
709  nodumpdev:
710 	dumpdev = NODEV;
711 	printf("\n");
712 }
713 
714 static int
715 findblkmajor(name, nam2blk)
716 	const char *name;
717 	struct devnametobdevmaj *nam2blk;
718 {
719 	int i;
720 
721 	if (nam2blk == NULL)
722 		return (-1);
723 
724 	for (i = 0; nam2blk[i].d_name != NULL; i++)
725 		if (strncmp(name, nam2blk[i].d_name,
726 		    strlen(nam2blk[i].d_name)) == 0)
727 			return (nam2blk[i].d_maj);
728 	return (-1);
729 }
730 
731 const char *
732 findblkname(maj, nam2blk)
733 	int maj;
734 	struct devnametobdevmaj *nam2blk;
735 {
736 	int i;
737 
738 	if (nam2blk == NULL)
739 		return (NULL);
740 
741 	for (i = 0; nam2blk[i].d_name != NULL; i++)
742 		if (nam2blk[i].d_maj == maj)
743 			return (nam2blk[i].d_name);
744 	return (NULL);
745 }
746 
747 static struct device *
748 getdisk(str, len, defpart, nam2blk, devp, isdump)
749 	char *str;
750 	int len, defpart;
751 	struct devnametobdevmaj *nam2blk;
752 	dev_t *devp;
753 	int isdump;
754 {
755 	struct device *dv;
756 
757 	if ((dv = parsedisk(str, len, defpart, nam2blk, devp)) == NULL) {
758 		printf("use one of:");
759 #ifdef MEMORY_DISK_HOOKS
760 		if (isdump == 0)
761 			printf(" %s[a-%c]", fakemdrootdev.dv_xname,
762 			    'a' + MAXPARTITIONS - 1);
763 #endif
764 		for (dv = alldevs.tqh_first; dv != NULL;
765 		    dv = dv->dv_list.tqe_next) {
766 			if (dv->dv_class == DV_DISK)
767 				printf(" %s[a-%c]", dv->dv_xname,
768 				    'a' + MAXPARTITIONS - 1);
769 			if (isdump == 0 && dv->dv_class == DV_IFNET)
770 				printf(" %s", dv->dv_xname);
771 		}
772 		if (isdump)
773 			printf(" none");
774 		printf(" halt\n");
775 	}
776 	return (dv);
777 }
778 
779 static struct device *
780 parsedisk(str, len, defpart, nam2blk, devp)
781 	char *str;
782 	int len, defpart;
783 	struct devnametobdevmaj *nam2blk;
784 	dev_t *devp;
785 {
786 	struct device *dv;
787 	char *cp, c;
788 	int majdev, part;
789 
790 	if (len == 0)
791 		return (NULL);
792 
793 	if (len == 4 && strcmp(str, "halt") == 0)
794 		cpu_reboot(RB_HALT, NULL);
795 
796 	cp = str + len - 1;
797 	c = *cp;
798 	if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
799 		part = c - 'a';
800 		*cp = '\0';
801 	} else
802 		part = defpart;
803 
804 #ifdef MEMORY_DISK_HOOKS
805 	if (strcmp(str, fakemdrootdev.dv_xname) == 0) {
806 		dv = &fakemdrootdev;
807 		goto gotdisk;
808 	}
809 #endif
810 
811 	for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
812 		if (dv->dv_class == DV_DISK &&
813 		    strcmp(str, dv->dv_xname) == 0) {
814 #ifdef MEMORY_DISK_HOOKS
815  gotdisk:
816 #endif
817 			majdev = findblkmajor(dv->dv_xname, nam2blk);
818 			if (majdev < 0)
819 				panic("parsedisk");
820 			*devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
821 			break;
822 		}
823 
824 		if (dv->dv_class == DV_IFNET &&
825 		    strcmp(str, dv->dv_xname) == 0) {
826 			*devp = NODEV;
827 			break;
828 		}
829 	}
830 
831 	*cp = c;
832 	return (dv);
833 }
834 
835 /*
836  * XXX shouldn't this be a common function?
837  */
838 static int
839 getstr(cp, size)
840 	char *cp;
841 	int size;
842 {
843 	char *lp;
844 	int c, len;
845 
846 	cnpollc(1);
847 
848 	lp = cp;
849 	len = 0;
850 	for (;;) {
851 		c = cngetc();
852 		switch (c) {
853 		case '\n':
854 		case '\r':
855 			printf("\n");
856 			*lp++ = '\0';
857 			cnpollc(0);
858 			return (len);
859 		case '\b':
860 		case '\177':
861 		case '#':
862 			if (len) {
863 				--len;
864 				--lp;
865 				printf("\b \b");
866 			}
867 			continue;
868 		case '@':
869 		case 'u'&037:
870 			len = 0;
871 			lp = cp;
872 			printf("\n");
873 			continue;
874 		default:
875 			if (len + 1 >= size || c < ' ') {
876 				printf("\007");
877 				continue;
878 			}
879 			printf("%c", c);
880 			++len;
881 			*lp++ = c;
882 		}
883 	}
884 }
885