Home | History | Annotate | Line # | Download | only in kern
kern_subr.c revision 1.62
      1 /*	$NetBSD: kern_subr.c,v 1.62 2000/03/23 20:39:58 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center, and by Luke Mewburn.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the NetBSD
     22  *	Foundation, Inc. and its contributors.
     23  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  *    contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 /*
     41  * Copyright (c) 1982, 1986, 1991, 1993
     42  *	The Regents of the University of California.  All rights reserved.
     43  * (c) UNIX System Laboratories, Inc.
     44  * All or some portions of this file are derived from material licensed
     45  * to the University of California by American Telephone and Telegraph
     46  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     47  * the permission of UNIX System Laboratories, Inc.
     48  *
     49  * Copyright (c) 1992, 1993
     50  *	The Regents of the University of California.  All rights reserved.
     51  *
     52  * This software was developed by the Computer Systems Engineering group
     53  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     54  * contributed to Berkeley.
     55  *
     56  * All advertising materials mentioning features or use of this software
     57  * must display the following acknowledgement:
     58  *	This product includes software developed by the University of
     59  *	California, Lawrence Berkeley Laboratory.
     60  *
     61  * Redistribution and use in source and binary forms, with or without
     62  * modification, are permitted provided that the following conditions
     63  * are met:
     64  * 1. Redistributions of source code must retain the above copyright
     65  *    notice, this list of conditions and the following disclaimer.
     66  * 2. Redistributions in binary form must reproduce the above copyright
     67  *    notice, this list of conditions and the following disclaimer in the
     68  *    documentation and/or other materials provided with the distribution.
     69  * 3. All advertising materials mentioning features or use of this software
     70  *    must display the following acknowledgement:
     71  *	This product includes software developed by the University of
     72  *	California, Berkeley and its contributors.
     73  * 4. Neither the name of the University nor the names of its contributors
     74  *    may be used to endorse or promote products derived from this software
     75  *    without specific prior written permission.
     76  *
     77  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     78  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     79  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     80  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     81  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     82  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     83  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     84  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     85  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     86  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     87  * SUCH DAMAGE.
     88  *
     89  *	@(#)kern_subr.c	8.4 (Berkeley) 2/14/95
     90  */
     91 
     92 #include "opt_md.h"
     93 
     94 #include <sys/param.h>
     95 #include <sys/systm.h>
     96 #include <sys/proc.h>
     97 #include <sys/malloc.h>
     98 #include <sys/mount.h>
     99 #include <sys/device.h>
    100 #include <sys/reboot.h>
    101 #include <sys/conf.h>
    102 #include <sys/disklabel.h>
    103 #include <sys/queue.h>
    104 
    105 #include <dev/cons.h>
    106 
    107 #include <net/if.h>
    108 
    109 /* XXX these should eventually move to subr_autoconf.c */
    110 static int findblkmajor __P((const char *));
    111 static const char *findblkname __P((int));
    112 static struct device *finddevice __P((const char *));
    113 static struct device *getdisk __P((char *, int, int, dev_t *, int));
    114 static struct device *parsedisk __P((char *, int, int, dev_t *));
    115 static int getstr __P((char *, int));
    116 
    117 int
    118 uiomove(buf, n, uio)
    119 	register void *buf;
    120 	register int n;
    121 	register struct uio *uio;
    122 {
    123 	register struct iovec *iov;
    124 	u_int cnt;
    125 	int error = 0;
    126 	char *cp = buf;
    127 	struct proc *p = uio->uio_procp;
    128 
    129 #ifdef DIAGNOSTIC
    130 	if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
    131 		panic("uiomove: mode");
    132 	if (uio->uio_segflg == UIO_USERSPACE && p != curproc)
    133 		panic("uiomove proc");
    134 #endif
    135 	while (n > 0 && uio->uio_resid) {
    136 		iov = uio->uio_iov;
    137 		cnt = iov->iov_len;
    138 		if (cnt == 0) {
    139 			uio->uio_iov++;
    140 			uio->uio_iovcnt--;
    141 			continue;
    142 		}
    143 		if (cnt > n)
    144 			cnt = n;
    145 		switch (uio->uio_segflg) {
    146 
    147 		case UIO_USERSPACE:
    148 			if (p->p_schedflags & PSCHED_SHOULDYIELD)
    149 				preempt(NULL);
    150 			if (uio->uio_rw == UIO_READ)
    151 				error = copyout(cp, iov->iov_base, cnt);
    152 			else
    153 				error = copyin(iov->iov_base, cp, cnt);
    154 			if (error)
    155 				return (error);
    156 			break;
    157 
    158 		case UIO_SYSSPACE:
    159 			if (uio->uio_rw == UIO_READ)
    160 				error = kcopy(cp, iov->iov_base, cnt);
    161 			else
    162 				error = kcopy(iov->iov_base, cp, cnt);
    163 			if (error)
    164 				return (error);
    165 			break;
    166 		}
    167 		iov->iov_base = (caddr_t)iov->iov_base + cnt;
    168 		iov->iov_len -= cnt;
    169 		uio->uio_resid -= cnt;
    170 		uio->uio_offset += cnt;
    171 		cp += cnt;
    172 		n -= cnt;
    173 	}
    174 	return (error);
    175 }
    176 
    177 /*
    178  * Give next character to user as result of read.
    179  */
    180 int
    181 ureadc(c, uio)
    182 	register int c;
    183 	register struct uio *uio;
    184 {
    185 	register struct iovec *iov;
    186 
    187 	if (uio->uio_resid <= 0)
    188 		panic("ureadc: non-positive resid");
    189 again:
    190 	if (uio->uio_iovcnt <= 0)
    191 		panic("ureadc: non-positive iovcnt");
    192 	iov = uio->uio_iov;
    193 	if (iov->iov_len <= 0) {
    194 		uio->uio_iovcnt--;
    195 		uio->uio_iov++;
    196 		goto again;
    197 	}
    198 	switch (uio->uio_segflg) {
    199 
    200 	case UIO_USERSPACE:
    201 		if (subyte(iov->iov_base, c) < 0)
    202 			return (EFAULT);
    203 		break;
    204 
    205 	case UIO_SYSSPACE:
    206 		*(char *)iov->iov_base = c;
    207 		break;
    208 	}
    209 	iov->iov_base = (caddr_t)iov->iov_base + 1;
    210 	iov->iov_len--;
    211 	uio->uio_resid--;
    212 	uio->uio_offset++;
    213 	return (0);
    214 }
    215 
    216 /*
    217  * General routine to allocate a hash table.
    218  * Allocate enough memory to hold at least `elements' list-head pointers.
    219  * Return a pointer to the allocated space and set *hashmask to a pattern
    220  * suitable for masking a value to use as an index into the returned array.
    221  */
    222 void *
    223 hashinit(elements, type, flags, hashmask)
    224 	int elements, type, flags;
    225 	u_long *hashmask;
    226 {
    227 	long hashsize;
    228 	LIST_HEAD(generic, generic) *hashtbl;
    229 	int i;
    230 
    231 	if (elements <= 0)
    232 		panic("hashinit: bad cnt");
    233 	for (hashsize = 1; hashsize < elements; hashsize <<= 1)
    234 		continue;
    235 	hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, flags);
    236 	for (i = 0; i < hashsize; i++)
    237 		LIST_INIT(&hashtbl[i]);
    238 	*hashmask = hashsize - 1;
    239 	return (hashtbl);
    240 }
    241 
    242 /*
    243  * Free memory from hash table previosly allocated via hashinit().
    244  */
    245 void
    246 hashdone(hashtbl, type)
    247 	void *hashtbl;
    248 	int type;
    249 {
    250 	free(hashtbl, type);
    251 }
    252 
    253 /*
    254  * "Shutdown hook" types, functions, and variables.
    255  */
    256 
    257 struct shutdownhook_desc {
    258 	LIST_ENTRY(shutdownhook_desc) sfd_list;
    259 	void	(*sfd_fn) __P((void *));
    260 	void	*sfd_arg;
    261 };
    262 
    263 LIST_HEAD(, shutdownhook_desc) shutdownhook_list;
    264 
    265 void *
    266 shutdownhook_establish(fn, arg)
    267 	void (*fn) __P((void *));
    268 	void *arg;
    269 {
    270 	struct shutdownhook_desc *ndp;
    271 
    272 	ndp = (struct shutdownhook_desc *)
    273 	    malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
    274 	if (ndp == NULL)
    275 		return (NULL);
    276 
    277 	ndp->sfd_fn = fn;
    278 	ndp->sfd_arg = arg;
    279 	LIST_INSERT_HEAD(&shutdownhook_list, ndp, sfd_list);
    280 
    281 	return (ndp);
    282 }
    283 
    284 void
    285 shutdownhook_disestablish(vhook)
    286 	void *vhook;
    287 {
    288 #ifdef DIAGNOSTIC
    289 	struct shutdownhook_desc *dp;
    290 
    291 	for (dp = shutdownhook_list.lh_first; dp != NULL;
    292 	    dp = dp->sfd_list.le_next)
    293                 if (dp == vhook)
    294 			break;
    295 	if (dp == NULL)
    296 		panic("shutdownhook_disestablish: hook not established");
    297 #endif
    298 
    299 	LIST_REMOVE((struct shutdownhook_desc *)vhook, sfd_list);
    300 	free(vhook, M_DEVBUF);
    301 }
    302 
    303 /*
    304  * Run shutdown hooks.  Should be invoked immediately before the
    305  * system is halted or rebooted, i.e. after file systems unmounted,
    306  * after crash dump done, etc.
    307  *
    308  * Each shutdown hook is removed from the list before it's run, so that
    309  * it won't be run again.
    310  */
    311 void
    312 doshutdownhooks()
    313 {
    314 	struct shutdownhook_desc *dp;
    315 
    316 	while ((dp = shutdownhook_list.lh_first) != NULL) {
    317 		LIST_REMOVE(dp, sfd_list);
    318 		(*dp->sfd_fn)(dp->sfd_arg);
    319 #if 0
    320 		/*
    321 		 * Don't bother freeing the hook structure,, since we may
    322 		 * be rebooting because of a memory corruption problem,
    323 		 * and this might only make things worse.  It doesn't
    324 		 * matter, anyway, since the system is just about to
    325 		 * reboot.
    326 		 */
    327 		free(dp, M_DEVBUF);
    328 #endif
    329 	}
    330 }
    331 
    332 /*
    333  * "Power hook" types, functions, and variables.
    334  */
    335 
    336 struct powerhook_desc {
    337 	LIST_ENTRY(powerhook_desc) sfd_list;
    338 	void	(*sfd_fn) __P((int, void *));
    339 	void	*sfd_arg;
    340 };
    341 
    342 LIST_HEAD(, powerhook_desc) powerhook_list;
    343 
    344 void *
    345 powerhook_establish(fn, arg)
    346 	void (*fn) __P((int, void *));
    347 	void *arg;
    348 {
    349 	struct powerhook_desc *ndp;
    350 
    351 	ndp = (struct powerhook_desc *)
    352 	    malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
    353 	if (ndp == NULL)
    354 		return (NULL);
    355 
    356 	ndp->sfd_fn = fn;
    357 	ndp->sfd_arg = arg;
    358 	LIST_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
    359 
    360 	return (ndp);
    361 }
    362 
    363 void
    364 powerhook_disestablish(vhook)
    365 	void *vhook;
    366 {
    367 #ifdef DIAGNOSTIC
    368 	struct powerhook_desc *dp;
    369 
    370 	for (dp = powerhook_list.lh_first; dp != NULL;
    371 	    dp = dp->sfd_list.le_next)
    372                 if (dp == vhook)
    373 			break;
    374 	if (dp == NULL)
    375 		panic("powerhook_disestablish: hook not established");
    376 #endif
    377 
    378 	LIST_REMOVE((struct powerhook_desc *)vhook, sfd_list);
    379 	free(vhook, M_DEVBUF);
    380 }
    381 
    382 /*
    383  * Run power hooks.
    384  */
    385 void
    386 dopowerhooks(why)
    387 	int why;
    388 {
    389 	struct powerhook_desc *dp;
    390 
    391 	for (dp = LIST_FIRST(&powerhook_list);
    392 	     dp != NULL;
    393 	     dp = LIST_NEXT(dp, sfd_list)) {
    394 		(*dp->sfd_fn)(why, dp->sfd_arg);
    395 	}
    396 }
    397 
    398 /*
    399  * "Mountroot hook" types, functions, and variables.
    400  */
    401 
    402 struct mountroothook_desc {
    403 	LIST_ENTRY(mountroothook_desc) mrd_list;
    404 	struct	device *mrd_device;
    405 	void 	(*mrd_func) __P((struct device *));
    406 };
    407 
    408 LIST_HEAD(, mountroothook_desc) mountroothook_list;
    409 
    410 void *
    411 mountroothook_establish(func, dev)
    412 	void (*func) __P((struct device *));
    413 	struct device *dev;
    414 {
    415 	struct mountroothook_desc *mrd;
    416 
    417 	mrd = (struct mountroothook_desc *)
    418 	    malloc(sizeof(*mrd), M_DEVBUF, M_NOWAIT);
    419 	if (mrd == NULL)
    420 		return (NULL);
    421 
    422 	mrd->mrd_device = dev;
    423 	mrd->mrd_func = func;
    424 	LIST_INSERT_HEAD(&mountroothook_list, mrd, mrd_list);
    425 
    426 	return (mrd);
    427 }
    428 
    429 void
    430 mountroothook_disestablish(vhook)
    431 	void *vhook;
    432 {
    433 #ifdef DIAGNOSTIC
    434 	struct mountroothook_desc *mrd;
    435 
    436 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
    437 	    mrd = mrd->mrd_list.le_next)
    438                 if (mrd == vhook)
    439 			break;
    440 	if (mrd == NULL)
    441 		panic("mountroothook_disestablish: hook not established");
    442 #endif
    443 
    444 	LIST_REMOVE((struct mountroothook_desc *)vhook, mrd_list);
    445 	free(vhook, M_DEVBUF);
    446 }
    447 
    448 void
    449 mountroothook_destroy()
    450 {
    451 	struct mountroothook_desc *mrd;
    452 
    453 	while ((mrd = mountroothook_list.lh_first) != NULL) {
    454 		LIST_REMOVE(mrd, mrd_list);
    455 		free(mrd, M_DEVBUF);
    456 	}
    457 }
    458 
    459 void
    460 domountroothook()
    461 {
    462 	struct mountroothook_desc *mrd;
    463 
    464 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
    465 	    mrd = mrd->mrd_list.le_next) {
    466 		if (mrd->mrd_device == root_device) {
    467 			(*mrd->mrd_func)(root_device);
    468 			return;
    469 		}
    470 	}
    471 }
    472 
    473 /*
    474  * Exec hook code.
    475  */
    476 
    477 struct exechook_desc {
    478 	LIST_ENTRY(exechook_desc) ehk_list;
    479 	void	(*ehk_fn) __P((struct proc *, void *));
    480 	void	*ehk_arg;
    481 };
    482 
    483 LIST_HEAD(, exechook_desc) exechook_list;
    484 
    485 void *
    486 exechook_establish(fn, arg)
    487 	void (*fn) __P((struct proc *, void *));
    488 	void *arg;
    489 {
    490 	struct exechook_desc *edp;
    491 
    492 	edp = (struct exechook_desc *)
    493 	    malloc(sizeof(*edp), M_DEVBUF, M_NOWAIT);
    494 	if (edp == NULL)
    495 		return (NULL);
    496 
    497 	edp->ehk_fn = fn;
    498 	edp->ehk_arg = arg;
    499 	LIST_INSERT_HEAD(&exechook_list, edp, ehk_list);
    500 
    501 	return (edp);
    502 }
    503 
    504 void
    505 exechook_disestablish(vhook)
    506 	void *vhook;
    507 {
    508 #ifdef DIAGNOSTIC
    509 	struct exechook_desc *edp;
    510 
    511 	for (edp = exechook_list.lh_first; edp != NULL;
    512 	    edp = edp->ehk_list.le_next)
    513                 if (edp == vhook)
    514 			break;
    515 	if (edp == NULL)
    516 		panic("exechook_disestablish: hook not established");
    517 #endif
    518 
    519 	LIST_REMOVE((struct exechook_desc *)vhook, ehk_list);
    520 	free(vhook, M_DEVBUF);
    521 }
    522 
    523 /*
    524  * Run exec hooks.
    525  */
    526 void
    527 doexechooks(p)
    528 	struct proc *p;
    529 {
    530 	struct exechook_desc *edp;
    531 
    532 	for (edp = LIST_FIRST(&exechook_list);
    533 	     edp != NULL;
    534 	     edp = LIST_NEXT(edp, ehk_list)) {
    535 		(*edp->ehk_fn)(p, edp->ehk_arg);
    536 	}
    537 }
    538 
    539 /*
    540  * Determine the root device and, if instructed to, the root file system.
    541  */
    542 
    543 #include "md.h"
    544 #if NMD == 0
    545 #undef MEMORY_DISK_HOOKS
    546 #endif
    547 
    548 #ifdef MEMORY_DISK_HOOKS
    549 static struct device fakemdrootdev[NMD];
    550 #endif
    551 
    552 #include "raid.h"
    553 #if NRAID == 1
    554 #define BOOT_FROM_RAID_HOOKS 1
    555 #endif
    556 
    557 #ifdef BOOT_FROM_RAID_HOOKS
    558 extern int numraid;
    559 extern struct device *raidrootdev;
    560 #endif
    561 
    562 void
    563 setroot(bootdv, bootpartition)
    564 	struct device *bootdv;
    565 	int bootpartition;
    566 {
    567 	struct device *dv;
    568 	int len;
    569 #ifdef MEMORY_DISK_HOOKS
    570 	int i;
    571 #endif
    572 	dev_t nrootdev;
    573 	dev_t ndumpdev = NODEV;
    574 	char buf[128];
    575 	const char *rootdevname;
    576 	const char *dumpdevname;
    577 	struct device *rootdv = NULL;		/* XXX gcc -Wuninitialized */
    578 	struct device *dumpdv = NULL;
    579 	struct ifnet *ifp;
    580 	const char *deffsname;
    581 	struct vfsops *vops;
    582 	extern int (*mountroot) __P((void));
    583 
    584 #ifdef MEMORY_DISK_HOOKS
    585 	for (i = 0; i < NMD; i++) {
    586 		fakemdrootdev[i].dv_class  = DV_DISK;
    587 		fakemdrootdev[i].dv_cfdata = NULL;
    588 		fakemdrootdev[i].dv_unit   = i;
    589 		fakemdrootdev[i].dv_parent = NULL;
    590 		sprintf(fakemdrootdev[i].dv_xname, "md%d", i);
    591 	}
    592 #endif /* MEMORY_DISK_HOOKS */
    593 
    594 #ifdef MEMORY_DISK_IS_ROOT
    595 	bootdv = &fakemdrootdev[0];
    596 	bootpartition = 0;
    597 #endif
    598 
    599 	/*
    600 	 * If NFS is specified as the file system, and we found
    601 	 * a DV_DISK boot device (or no boot device at all), then
    602 	 * find a reasonable network interface for "rootspec".
    603 	 */
    604 	vops = vfs_getopsbyname("nfs");
    605 	if (vops != NULL && vops->vfs_mountroot == mountroot &&
    606 	    rootspec == NULL &&
    607 	    (bootdv == NULL || bootdv->dv_class != DV_IFNET)) {
    608 		for (ifp = ifnet.tqh_first; ifp != NULL;
    609 		    ifp = ifp->if_list.tqe_next)
    610 			if ((ifp->if_flags &
    611 			     (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
    612 				break;
    613 		if (ifp == NULL) {
    614 			/*
    615 			 * Can't find a suitable interface; ask the
    616 			 * user.
    617 			 */
    618 			boothowto |= RB_ASKNAME;
    619 		} else {
    620 			/*
    621 			 * Have a suitable interface; behave as if
    622 			 * the user specified this interface.
    623 			 */
    624 			rootspec = (const char *)ifp->if_xname;
    625 		}
    626 	}
    627 
    628 	/*
    629 	 * If wildcarded root and we the boot device wasn't determined,
    630 	 * ask the user.
    631 	 */
    632 	if (rootspec == NULL && bootdv == NULL)
    633 		boothowto |= RB_ASKNAME;
    634 
    635  top:
    636 	if (boothowto & RB_ASKNAME) {
    637 		struct device *defdumpdv;
    638 
    639 		for (;;) {
    640 			printf("root device");
    641 			if (bootdv != NULL) {
    642 				printf(" (default %s", bootdv->dv_xname);
    643 				if (bootdv->dv_class == DV_DISK)
    644 					printf("%c", bootpartition + 'a');
    645 				printf(")");
    646 			}
    647 			printf(": ");
    648 			len = getstr(buf, sizeof(buf));
    649 			if (len == 0 && bootdv != NULL) {
    650 				strcpy(buf, bootdv->dv_xname);
    651 				len = strlen(buf);
    652 			}
    653 			if (len > 0 && buf[len - 1] == '*') {
    654 				buf[--len] = '\0';
    655 				dv = getdisk(buf, len, 1, &nrootdev, 0);
    656 				if (dv != NULL) {
    657 					rootdv = dv;
    658 					break;
    659 				}
    660 			}
    661 			dv = getdisk(buf, len, bootpartition, &nrootdev, 0);
    662 			if (dv != NULL) {
    663 				rootdv = dv;
    664 				break;
    665 			}
    666 		}
    667 
    668 		/*
    669 		 * Set up the default dump device.  If root is on
    670 		 * a network device, there is no default dump
    671 		 * device, since we don't support dumps to the
    672 		 * network.
    673 		 */
    674 		if (rootdv->dv_class == DV_IFNET)
    675 			defdumpdv = NULL;
    676 		else
    677 			defdumpdv = rootdv;
    678 
    679 		for (;;) {
    680 			printf("dump device");
    681 			if (defdumpdv != NULL) {
    682 				/*
    683 				 * Note, we know it's a disk if we get here.
    684 				 */
    685 				printf(" (default %sb)", defdumpdv->dv_xname);
    686 			}
    687 			printf(": ");
    688 			len = getstr(buf, sizeof(buf));
    689 			if (len == 0) {
    690 				if (defdumpdv != NULL) {
    691 					ndumpdev = MAKEDISKDEV(major(nrootdev),
    692 					    DISKUNIT(nrootdev), 1);
    693 				}
    694 				dumpdv = defdumpdv;
    695 				break;
    696 			}
    697 			if (len == 4 && strcmp(buf, "none") == 0) {
    698 				dumpdv = NULL;
    699 				break;
    700 			}
    701 			dv = getdisk(buf, len, 1, &ndumpdev, 1);
    702 			if (dv != NULL) {
    703 				dumpdv = dv;
    704 				break;
    705 			}
    706 		}
    707 
    708 		rootdev = nrootdev;
    709 		dumpdev = ndumpdev;
    710 
    711 		for (vops = LIST_FIRST(&vfs_list); vops != NULL;
    712 		     vops = LIST_NEXT(vops, vfs_list)) {
    713 			if (vops->vfs_mountroot != NULL &&
    714 			    vops->vfs_mountroot == mountroot)
    715 			break;
    716 		}
    717 
    718 		if (vops == NULL) {
    719 			mountroot = NULL;
    720 			deffsname = "generic";
    721 		} else
    722 			deffsname = vops->vfs_name;
    723 
    724 		for (;;) {
    725 			printf("file system (default %s): ", deffsname);
    726 			len = getstr(buf, sizeof(buf));
    727 			if (len == 0)
    728 				break;
    729 			if (len == 4 && strcmp(buf, "halt") == 0)
    730 				cpu_reboot(RB_HALT, NULL);
    731 			else if (len == 7 && strcmp(buf, "generic") == 0) {
    732 				mountroot = NULL;
    733 				break;
    734 			}
    735 			vops = vfs_getopsbyname(buf);
    736 			if (vops == NULL || vops->vfs_mountroot == NULL) {
    737 				printf("use one of: generic");
    738 				for (vops = LIST_FIRST(&vfs_list);
    739 				     vops != NULL;
    740 				     vops = LIST_NEXT(vops, vfs_list)) {
    741 					if (vops->vfs_mountroot != NULL)
    742 						printf(" %s", vops->vfs_name);
    743 				}
    744 				printf(" halt\n");
    745 			} else {
    746 				mountroot = vops->vfs_mountroot;
    747 				break;
    748 			}
    749 		}
    750 
    751 	} else if (rootspec == NULL) {
    752 		int majdev;
    753 
    754 		/*
    755 		 * Wildcarded root; use the boot device.
    756 		 */
    757 		rootdv = bootdv;
    758 
    759 		majdev = findblkmajor(bootdv->dv_xname);
    760 		if (majdev >= 0) {
    761 			/*
    762 			 * Root is on a disk.  `bootpartition' is root.
    763 			 */
    764 			rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
    765 			    bootpartition);
    766 		}
    767 	} else {
    768 
    769 		/*
    770 		 * `root on <dev> ...'
    771 		 */
    772 
    773 		/*
    774 		 * If it's a network interface, we can bail out
    775 		 * early.
    776 		 */
    777 		dv = finddevice(rootspec);
    778 		if (dv != NULL && dv->dv_class == DV_IFNET) {
    779 			rootdv = dv;
    780 			goto haveroot;
    781 		}
    782 
    783 		rootdevname = findblkname(major(rootdev));
    784 		if (rootdevname == NULL) {
    785 			printf("unknown device major 0x%x\n", rootdev);
    786 			boothowto |= RB_ASKNAME;
    787 			goto top;
    788 		}
    789 		memset(buf, 0, sizeof(buf));
    790 		sprintf(buf, "%s%d", rootdevname, DISKUNIT(rootdev));
    791 
    792 		rootdv = finddevice(buf);
    793 		if (rootdv == NULL) {
    794 			printf("device %s (0x%x) not configured\n",
    795 			    buf, rootdev);
    796 			boothowto |= RB_ASKNAME;
    797 			goto top;
    798 		}
    799 	}
    800 
    801  haveroot:
    802 
    803 	root_device = rootdv;
    804 
    805 	switch (rootdv->dv_class) {
    806 	case DV_IFNET:
    807 		printf("root on %s", rootdv->dv_xname);
    808 		break;
    809 
    810 	case DV_DISK:
    811 		printf("root on %s%c", rootdv->dv_xname,
    812 		    DISKPART(rootdev) + 'a');
    813 		break;
    814 
    815 	default:
    816 		printf("can't determine root device\n");
    817 		boothowto |= RB_ASKNAME;
    818 		goto top;
    819 	}
    820 
    821 	/*
    822 	 * Now configure the dump device.
    823 	 *
    824 	 * If we haven't figured out the dump device, do so, with
    825 	 * the following rules:
    826 	 *
    827 	 *	(a) We already know dumpdv in the RB_ASKNAME case.
    828 	 *
    829 	 *	(b) If dumpspec is set, try to use it.  If the device
    830 	 *	    is not available, punt.
    831 	 *
    832 	 *	(c) If dumpspec is not set, the dump device is
    833 	 *	    wildcarded or unspecified.  If the root device
    834 	 *	    is DV_IFNET, punt.  Otherwise, use partition b
    835 	 *	    of the root device.
    836 	 */
    837 
    838 	if (boothowto & RB_ASKNAME) {		/* (a) */
    839 		if (dumpdv == NULL)
    840 			goto nodumpdev;
    841 	} else if (dumpspec != NULL) {		/* (b) */
    842 		if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) {
    843 			/*
    844 			 * Operator doesn't want a dump device.
    845 			 * Or looks like they tried to pick a network
    846 			 * device.  Oops.
    847 			 */
    848 			goto nodumpdev;
    849 		}
    850 
    851 		dumpdevname = findblkname(major(dumpdev));
    852 		if (dumpdevname == NULL)
    853 			goto nodumpdev;
    854 		memset(buf, 0, sizeof(buf));
    855 		sprintf(buf, "%s%d", dumpdevname, DISKUNIT(dumpdev));
    856 
    857 		dumpdv = finddevice(buf);
    858 		if (dumpdv == NULL) {
    859 			/*
    860 			 * Device not configured.
    861 			 */
    862 			goto nodumpdev;
    863 		}
    864 	} else {				/* (c) */
    865 		if (rootdv->dv_class == DV_IFNET)
    866 			goto nodumpdev;
    867 		else {
    868 			dumpdv = rootdv;
    869 			dumpdev = MAKEDISKDEV(major(rootdev),
    870 			    dumpdv->dv_unit, 1);
    871 		}
    872 	}
    873 
    874 	printf(" dumps on %s%c\n", dumpdv->dv_xname, DISKPART(dumpdev) + 'a');
    875 	return;
    876 
    877  nodumpdev:
    878 	dumpdev = NODEV;
    879 	printf("\n");
    880 }
    881 
    882 static int
    883 findblkmajor(name)
    884 	const char *name;
    885 {
    886 	int i;
    887 
    888 	for (i = 0; dev_name2blk[i].d_name != NULL; i++)
    889 		if (strncmp(name, dev_name2blk[i].d_name,
    890 		    strlen(dev_name2blk[i].d_name)) == 0)
    891 			return (dev_name2blk[i].d_maj);
    892 	return (-1);
    893 }
    894 
    895 const char *
    896 findblkname(maj)
    897 	int maj;
    898 {
    899 	int i;
    900 
    901 	for (i = 0; dev_name2blk[i].d_name != NULL; i++)
    902 		if (dev_name2blk[i].d_maj == maj)
    903 			return (dev_name2blk[i].d_name);
    904 	return (NULL);
    905 }
    906 
    907 static struct device *
    908 finddevice(name)
    909 	const char *name;
    910 {
    911 	struct device *dv;
    912 #ifdef BOOT_FROM_RAID_HOOKS
    913 	int j;
    914 
    915 	for (j = 0; j < numraid; j++) {
    916 		if (strcmp(name, raidrootdev[j].dv_xname) == 0) {
    917 			dv = &raidrootdev[j];
    918 			return (dv);
    919 		}
    920 	}
    921 #endif;
    922 
    923 	for (dv = TAILQ_FIRST(&alldevs); dv != NULL;
    924 	    dv = TAILQ_NEXT(dv, dv_list))
    925 		if (strcmp(dv->dv_xname, name) == 0)
    926 			break;
    927 	return (dv);
    928 }
    929 
    930 static struct device *
    931 getdisk(str, len, defpart, devp, isdump)
    932 	char *str;
    933 	int len, defpart;
    934 	dev_t *devp;
    935 	int isdump;
    936 {
    937 	struct device	*dv;
    938 #ifdef MEMORY_DISK_HOOKS
    939 	int		i;
    940 #endif
    941 #ifdef BOOT_FROM_RAID_HOOKS
    942 	int 		j;
    943 #endif
    944 
    945 	if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
    946 		printf("use one of:");
    947 #ifdef MEMORY_DISK_HOOKS
    948 		if (isdump == 0)
    949 			for (i = 0; i < NMD; i++)
    950 				printf(" %s[a-%c]", fakemdrootdev[i].dv_xname,
    951 				    'a' + MAXPARTITIONS - 1);
    952 #endif
    953 #ifdef BOOT_FROM_RAID_HOOKS
    954 		if (isdump == 0)
    955 			for (j = 0; j < numraid; j++)
    956 				printf(" %s[a-%c]", raidrootdev[j].dv_xname,
    957 				    'a' + MAXPARTITIONS - 1);
    958 #endif
    959 		for (dv = alldevs.tqh_first; dv != NULL;
    960 		    dv = dv->dv_list.tqe_next) {
    961 			if (dv->dv_class == DV_DISK)
    962 				printf(" %s[a-%c]", dv->dv_xname,
    963 				    'a' + MAXPARTITIONS - 1);
    964 			if (isdump == 0 && dv->dv_class == DV_IFNET)
    965 				printf(" %s", dv->dv_xname);
    966 		}
    967 		if (isdump)
    968 			printf(" none");
    969 		printf(" halt\n");
    970 	}
    971 	return (dv);
    972 }
    973 
    974 static struct device *
    975 parsedisk(str, len, defpart, devp)
    976 	char *str;
    977 	int len, defpart;
    978 	dev_t *devp;
    979 {
    980 	struct device *dv;
    981 	char *cp, c;
    982 	int majdev, part;
    983 #ifdef MEMORY_DISK_HOOKS
    984 	int i;
    985 #endif
    986 	if (len == 0)
    987 		return (NULL);
    988 
    989 	if (len == 4 && strcmp(str, "halt") == 0)
    990 		cpu_reboot(RB_HALT, NULL);
    991 
    992 	cp = str + len - 1;
    993 	c = *cp;
    994 	if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
    995 		part = c - 'a';
    996 		*cp = '\0';
    997 	} else
    998 		part = defpart;
    999 
   1000 #ifdef MEMORY_DISK_HOOKS
   1001 	for (i = 0; i < NMD; i++)
   1002 		if (strcmp(str, fakemdrootdev[i].dv_xname) == 0) {
   1003 			dv = &fakemdrootdev[i];
   1004 			goto gotdisk;
   1005 		}
   1006 #endif
   1007 
   1008 	dv = finddevice(str);
   1009 	if (dv != NULL) {
   1010 		if (dv->dv_class == DV_DISK) {
   1011 #ifdef MEMORY_DISK_HOOKS
   1012  gotdisk:
   1013 #endif
   1014 			majdev = findblkmajor(dv->dv_xname);
   1015 			if (majdev < 0)
   1016 				panic("parsedisk");
   1017 			*devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
   1018 		}
   1019 
   1020 		if (dv->dv_class == DV_IFNET)
   1021 			*devp = NODEV;
   1022 	}
   1023 
   1024 	*cp = c;
   1025 	return (dv);
   1026 }
   1027 
   1028 /*
   1029  * XXX shouldn't this be a common function?
   1030  */
   1031 static int
   1032 getstr(cp, size)
   1033 	char *cp;
   1034 	int size;
   1035 {
   1036 	char *lp;
   1037 	int c, len;
   1038 
   1039 	cnpollc(1);
   1040 
   1041 	lp = cp;
   1042 	len = 0;
   1043 	for (;;) {
   1044 		c = cngetc();
   1045 		switch (c) {
   1046 		case '\n':
   1047 		case '\r':
   1048 			printf("\n");
   1049 			*lp++ = '\0';
   1050 			cnpollc(0);
   1051 			return (len);
   1052 		case '\b':
   1053 		case '\177':
   1054 		case '#':
   1055 			if (len) {
   1056 				--len;
   1057 				--lp;
   1058 				printf("\b \b");
   1059 			}
   1060 			continue;
   1061 		case '@':
   1062 		case 'u'&037:
   1063 			len = 0;
   1064 			lp = cp;
   1065 			printf("\n");
   1066 			continue;
   1067 		default:
   1068 			if (len + 1 >= size || c < ' ') {
   1069 				printf("\007");
   1070 				continue;
   1071 			}
   1072 			printf("%c", c);
   1073 			++len;
   1074 			*lp++ = c;
   1075 		}
   1076 	}
   1077 }
   1078 
   1079 /*
   1080  * snprintf() `bytes' into `buf', reformatting it so that the number,
   1081  * plus a possible `x' + suffix extension) fits into len bytes (including
   1082  * the terminating NUL).
   1083  * Returns the number of bytes stored in buf, or -1 if there was a problem.
   1084  * E.g, given a len of 9 and a suffix of `B':
   1085  *	bytes		result
   1086  *	-----		------
   1087  *	99999		`99999 B'
   1088  *	100000		`97 KB'
   1089  *	66715648	`65152 KB'
   1090  *	252215296	`240 MB'
   1091  */
   1092 int
   1093 humanize_number(buf, len, bytes, suffix, divisor)
   1094 	char		*buf;
   1095 	size_t		 len;
   1096 	u_int64_t	 bytes;
   1097 	const char	*suffix;
   1098 	int 		divisor;
   1099 {
   1100 		/* prefixes are: (none), Kilo, Mega, Giga, Tera, Peta, Exa */
   1101 	static const char prefixes[] = " KMGTPE";
   1102 
   1103 	int		i, r;
   1104 	u_int64_t	max;
   1105 	size_t		suffixlen;
   1106 
   1107 	if (buf == NULL || suffix == NULL)
   1108 		return (-1);
   1109 	if (len > 0)
   1110 		buf[0] = '\0';
   1111 	suffixlen = strlen(suffix);
   1112 			/* check if enough room for `x y' + suffix + `\0' */
   1113 	if (len < 4 + suffixlen)
   1114 		return (-1);
   1115 
   1116 	max = 1;
   1117 	for (i = 0; i < len - suffixlen - 3; i++)
   1118 		max *= 10;
   1119 	for (i = 0; bytes >= max && i < sizeof(prefixes); i++)
   1120 		bytes /= divisor;
   1121 
   1122 	r = snprintf(buf, len, "%qu%s%c%s", (unsigned long long)bytes,
   1123 	    i == 0 ? "" : " ", prefixes[i], suffix);
   1124 
   1125 	return (r);
   1126 }
   1127 
   1128 int
   1129 format_bytes(buf, len, bytes)
   1130 	char		*buf;
   1131 	size_t		 len;
   1132 	u_int64_t	 bytes;
   1133 {
   1134 	int	rv;
   1135 	size_t	nlen;
   1136 
   1137 	rv = humanize_number(buf, len, bytes, "B", 1024);
   1138 	if (rv != -1) {
   1139 			/* nuke the trailing ` B' if it exists */
   1140 		nlen = strlen(buf) - 2;
   1141 		if (strcmp(&buf[nlen], " B") == 0)
   1142 			buf[nlen] = '\0';
   1143 	}
   1144 	return (rv);
   1145 }
   1146