Home | History | Annotate | Line # | Download | only in kern
kern_subr.c revision 1.34
      1 /*	$NetBSD: kern_subr.c,v 1.34 1998/02/10 14:09:43 mrg Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1997 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.
     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.3 (Berkeley) 1/21/94
     90  */
     91 
     92 #include "opt_uvm.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 *, struct devnametobdevmaj *));
    111 static const char *findblkname __P((int, struct devnametobdevmaj *));
    112 static struct device *getdisk __P((char *, int, int,
    113 	struct devnametobdevmaj *, dev_t *, int));
    114 static struct device *parsedisk __P((char *, int, int,
    115 	struct devnametobdevmaj *, dev_t *));
    116 static int getstr __P((char *, int));
    117 
    118 int
    119 uiomove(buf, n, uio)
    120 	register void *buf;
    121 	register int n;
    122 	register struct uio *uio;
    123 {
    124 	register struct iovec *iov;
    125 	u_int cnt;
    126 	int error = 0;
    127 	char *cp = buf;
    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 && uio->uio_procp != 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 (uio->uio_rw == UIO_READ)
    149 				error = copyout(cp, iov->iov_base, cnt);
    150 			else
    151 				error = copyin(iov->iov_base, cp, cnt);
    152 			if (error)
    153 				return (error);
    154 			break;
    155 
    156 		case UIO_SYSSPACE:
    157 #if defined(UVM)
    158 			if (uio->uio_rw == UIO_READ)
    159 				error = kcopy(cp, iov->iov_base, cnt);
    160 			else
    161 				error = kcopy(iov->iov_base, cp, cnt);
    162 			if (error)
    163 				return(error);
    164 #else
    165 			if (uio->uio_rw == UIO_READ)
    166 				bcopy(cp, iov->iov_base, cnt);
    167 			else
    168 				bcopy(iov->iov_base, cp, cnt);
    169 #endif
    170 			break;
    171 		}
    172 		iov->iov_base += cnt;
    173 		iov->iov_len -= cnt;
    174 		uio->uio_resid -= cnt;
    175 		uio->uio_offset += cnt;
    176 		cp += cnt;
    177 		n -= cnt;
    178 	}
    179 	return (error);
    180 }
    181 
    182 /*
    183  * Give next character to user as result of read.
    184  */
    185 int
    186 ureadc(c, uio)
    187 	register int c;
    188 	register struct uio *uio;
    189 {
    190 	register struct iovec *iov;
    191 
    192 	if (uio->uio_resid <= 0)
    193 		panic("ureadc: non-positive resid");
    194 again:
    195 	if (uio->uio_iovcnt <= 0)
    196 		panic("ureadc: non-positive iovcnt");
    197 	iov = uio->uio_iov;
    198 	if (iov->iov_len <= 0) {
    199 		uio->uio_iovcnt--;
    200 		uio->uio_iov++;
    201 		goto again;
    202 	}
    203 	switch (uio->uio_segflg) {
    204 
    205 	case UIO_USERSPACE:
    206 		if (subyte(iov->iov_base, c) < 0)
    207 			return (EFAULT);
    208 		break;
    209 
    210 	case UIO_SYSSPACE:
    211 		*iov->iov_base = c;
    212 		break;
    213 	}
    214 	iov->iov_base++;
    215 	iov->iov_len--;
    216 	uio->uio_resid--;
    217 	uio->uio_offset++;
    218 	return (0);
    219 }
    220 
    221 /*
    222  * General routine to allocate a hash table.
    223  */
    224 void *
    225 hashinit(elements, type, flags, hashmask)
    226 	int elements, type, flags;
    227 	u_long *hashmask;
    228 {
    229 	long hashsize;
    230 	LIST_HEAD(generic, generic) *hashtbl;
    231 	int i;
    232 
    233 	if (elements <= 0)
    234 		panic("hashinit: bad cnt");
    235 	for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
    236 		continue;
    237 	hashsize >>= 1;
    238 	hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, flags);
    239 	for (i = 0; i < hashsize; i++)
    240 		LIST_INIT(&hashtbl[i]);
    241 	*hashmask = hashsize - 1;
    242 	return (hashtbl);
    243 }
    244 
    245 /*
    246  * "Shutdown hook" types, functions, and variables.
    247  */
    248 
    249 struct shutdownhook_desc {
    250 	LIST_ENTRY(shutdownhook_desc) sfd_list;
    251 	void	(*sfd_fn) __P((void *));
    252 	void	*sfd_arg;
    253 };
    254 
    255 LIST_HEAD(, shutdownhook_desc) shutdownhook_list;
    256 
    257 void *
    258 shutdownhook_establish(fn, arg)
    259 	void (*fn) __P((void *));
    260 	void *arg;
    261 {
    262 	struct shutdownhook_desc *ndp;
    263 
    264 	ndp = (struct shutdownhook_desc *)
    265 	    malloc(sizeof (*ndp), M_DEVBUF, M_NOWAIT);
    266 	if (ndp == NULL)
    267 		return NULL;
    268 
    269 	ndp->sfd_fn = fn;
    270 	ndp->sfd_arg = arg;
    271 	LIST_INSERT_HEAD(&shutdownhook_list, ndp, sfd_list);
    272 
    273 	return (ndp);
    274 }
    275 
    276 void
    277 shutdownhook_disestablish(vhook)
    278 	void *vhook;
    279 {
    280 #ifdef DIAGNOSTIC
    281 	struct shutdownhook_desc *dp;
    282 
    283 	for (dp = shutdownhook_list.lh_first; dp != NULL;
    284 	    dp = dp->sfd_list.le_next)
    285                 if (dp == vhook)
    286 			break;
    287 	if (dp == NULL)
    288 		panic("shutdownhook_disestablish: hook not established");
    289 #endif
    290 
    291 	LIST_REMOVE((struct shutdownhook_desc *)vhook, sfd_list);
    292 	free(vhook, M_DEVBUF);
    293 }
    294 
    295 /*
    296  * Run shutdown hooks.  Should be invoked immediately before the
    297  * system is halted or rebooted, i.e. after file systems unmounted,
    298  * after crash dump done, etc.
    299  *
    300  * Each shutdown hook is removed from the list before it's run, so that
    301  * it won't be run again.
    302  */
    303 void
    304 doshutdownhooks()
    305 {
    306 	struct shutdownhook_desc *dp;
    307 
    308 	while ((dp = shutdownhook_list.lh_first) != NULL) {
    309 		LIST_REMOVE(dp, sfd_list);
    310 		(*dp->sfd_fn)(dp->sfd_arg);
    311 #if 0
    312 		/*
    313 		 * Don't bother freeing the hook structure,, since we may
    314 		 * be rebooting because of a memory corruption problem,
    315 		 * and this might only make things worse.  It doesn't
    316 		 * matter, anyway, since the system is just about to
    317 		 * reboot.
    318 		 */
    319 		free(dp, M_DEVBUF);
    320 #endif
    321 	}
    322 }
    323 
    324 /*
    325  * "Mountroot hook" types, functions, and variables.
    326  */
    327 
    328 struct mountroothook_desc {
    329 	LIST_ENTRY(mountroothook_desc) mrd_list;
    330 	struct	device *mrd_device;
    331 	void 	(*mrd_func) __P((struct device *));
    332 };
    333 
    334 LIST_HEAD(, mountroothook_desc) mountroothook_list;
    335 
    336 void *
    337 mountroothook_establish(func, dev)
    338 	void (*func) __P((struct device *));
    339 	struct device *dev;
    340 {
    341 	struct mountroothook_desc *mrd;
    342 
    343 	mrd = (struct mountroothook_desc *)
    344 	    malloc(sizeof(*mrd), M_DEVBUF, M_NOWAIT);
    345 	if (mrd == NULL)
    346 		return (NULL);
    347 
    348 	mrd->mrd_device = dev;
    349 	mrd->mrd_func = func;
    350 	LIST_INSERT_HEAD(&mountroothook_list, mrd, mrd_list);
    351 
    352 	return (mrd);
    353 }
    354 
    355 void
    356 mountroothook_disestablish(vhook)
    357 	void *vhook;
    358 {
    359 #ifdef DIAGNOSTIC
    360 	struct mountroothook_desc *mrd;
    361 
    362 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
    363 	    mrd = mrd->mrd_list.le_next)
    364                 if (mrd == vhook)
    365 			break;
    366 	if (mrd == NULL)
    367 		panic("mountroothook_disestablish: hook not established");
    368 #endif
    369 
    370 	LIST_REMOVE((struct mountroothook_desc *)vhook, mrd_list);
    371 	free(vhook, M_DEVBUF);
    372 }
    373 
    374 void
    375 mountroothook_destroy()
    376 {
    377 	struct mountroothook_desc *mrd;
    378 
    379 	while ((mrd = mountroothook_list.lh_first) != NULL) {
    380 		LIST_REMOVE(mrd, mrd_list);
    381 		free(mrd, M_DEVBUF);
    382 	}
    383 }
    384 
    385 void
    386 domountroothook()
    387 {
    388 	struct mountroothook_desc *mrd;
    389 
    390 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
    391 	    mrd = mrd->mrd_list.le_next) {
    392 		if (mrd->mrd_device == root_device) {
    393 			(*mrd->mrd_func)(root_device);
    394 			return;
    395 		}
    396 	}
    397 }
    398 
    399 /*
    400  * Determine the root device and, if instructed to, the root file system.
    401  */
    402 
    403 #include "md.h"
    404 #if NMD == 0
    405 #undef MEMORY_DISK_HOOKS
    406 #endif
    407 
    408 #ifdef MEMORY_DISK_HOOKS
    409 static struct device fakemdrootdev[NMD];
    410 #endif
    411 
    412 void
    413 setroot(bootdv, bootpartition, nam2blk)
    414 	struct device *bootdv;
    415 	int bootpartition;
    416 	struct devnametobdevmaj *nam2blk;
    417 {
    418 	struct device *dv;
    419 	int len, i, print_newline = 0;
    420 	dev_t nrootdev;
    421 	dev_t ndumpdev = NODEV;
    422 	char buf[128];
    423 	const char *rootdevname;
    424 	const char *dumpdevname;
    425 	struct device *rootdv = NULL;		/* XXX gcc -Wuninitialized */
    426 	struct device *dumpdv = NULL;
    427 	struct ifnet *ifp;
    428 	const char *deffsname;
    429 	struct vfsops *vops;
    430 	extern int (*mountroot) __P((void));
    431 	static struct devnametobdevmaj *last_nam2blk;
    432 
    433 	if (nam2blk == NULL) {
    434 		if (last_nam2blk == NULL)
    435 			panic("setroot: no name to bdev major map");
    436 		nam2blk = last_nam2blk;
    437 	}
    438 	last_nam2blk = nam2blk;
    439 
    440 #ifdef MEMORY_DISK_HOOKS
    441 	for (i = 0; i < NMD; i++) {
    442 		fakemdrootdev[i].dv_class  = DV_DISK;
    443 		fakemdrootdev[i].dv_cfdata = NULL;
    444 		fakemdrootdev[i].dv_unit   = i;
    445 		fakemdrootdev[i].dv_parent = NULL;
    446 		sprintf(fakemdrootdev[i].dv_xname, "md%d", i);
    447 	}
    448 #endif /* MEMORY_DISK_HOOKS */
    449 
    450 #ifdef MEMORY_DISK_IS_ROOT
    451 	bootdv = &fakemdrootdev[0];
    452 	bootpartition = 0;
    453 #endif
    454 
    455 	/*
    456 	 * If NFS is specified as the file system, and we found
    457 	 * a DV_DISK boot device (or no boot device at all), then
    458 	 * find a reasonable network interface for "rootspec".
    459 	 */
    460 	vops = vfs_getopsbyname("nfs");
    461 	if (vops != NULL && vops->vfs_mountroot == mountroot &&
    462 	    rootspec == NULL &&
    463 	    (bootdv == NULL || bootdv->dv_class != DV_IFNET)) {
    464 		for (ifp = ifnet.tqh_first; ifp != NULL;
    465 		    ifp = ifp->if_list.tqe_next)
    466 			if ((ifp->if_flags &
    467 			     (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
    468 				break;
    469 		if (ifp == NULL) {
    470 			/*
    471 			 * Can't find a suitable interface; ask the
    472 			 * user.
    473 			 */
    474 			boothowto |= RB_ASKNAME;
    475 		} else {
    476 			/*
    477 			 * Have a suitable interface; behave as if
    478 			 * the user specified this interface.
    479 			 */
    480 			rootspec = (const char *)ifp->if_xname;
    481 		}
    482 	}
    483 
    484 	/*
    485 	 * If wildcarded root and we the boot device wasn't determined,
    486 	 * ask the user.
    487 	 */
    488 	if (rootspec == NULL && bootdv == NULL)
    489 		boothowto |= RB_ASKNAME;
    490 
    491  top:
    492 	if (boothowto & RB_ASKNAME) {
    493 		struct device *defdumpdv;
    494 
    495 		for (;;) {
    496 			printf("root device");
    497 			if (bootdv != NULL) {
    498 				printf(" (default %s", bootdv->dv_xname);
    499 				if (bootdv->dv_class == DV_DISK)
    500 					printf("%c", bootpartition + 'a');
    501 				printf(")");
    502 			}
    503 			printf(": ");
    504 			len = getstr(buf, sizeof(buf));
    505 			if (len == 0 && bootdv != NULL) {
    506 				strcpy(buf, bootdv->dv_xname);
    507 				len = strlen(buf);
    508 			}
    509 			if (len > 0 && buf[len - 1] == '*') {
    510 				buf[--len] = '\0';
    511 				dv = getdisk(buf, len, 1, nam2blk,
    512 				    &nrootdev, 0);
    513 				if (dv != NULL) {
    514 					rootdv = dv;
    515 					break;
    516 				}
    517 			}
    518 			dv = getdisk(buf, len, bootpartition, nam2blk,
    519 			    &nrootdev, 0);
    520 			if (dv != NULL) {
    521 				rootdv = dv;
    522 				break;
    523 			}
    524 		}
    525 
    526 		/*
    527 		 * Set up the default dump device.  If root is on
    528 		 * a network device, there is no default dump
    529 		 * device, since we don't support dumps to the
    530 		 * network.
    531 		 */
    532 		if (rootdv->dv_class == DV_IFNET)
    533 			defdumpdv = NULL;
    534 		else
    535 			defdumpdv = rootdv;
    536 
    537 		for (;;) {
    538 			printf("dump device");
    539 			if (defdumpdv != NULL) {
    540 				/*
    541 				 * Note, we know it's a disk if we get here.
    542 				 */
    543 				printf(" (default %sb)", defdumpdv->dv_xname);
    544 			}
    545 			printf(": ");
    546 			len = getstr(buf, sizeof(buf));
    547 			if (len == 0) {
    548 				if (defdumpdv != NULL) {
    549 					ndumpdev = MAKEDISKDEV(major(nrootdev),
    550 					    DISKUNIT(nrootdev), 1);
    551 				}
    552 				if (rootdv->dv_class == DV_IFNET)
    553 					dumpdv = NULL;
    554 				else
    555 					dumpdv = rootdv;
    556 				break;
    557 			}
    558 			if (len == 4 && strcmp(buf, "none") == 0) {
    559 				dumpspec = "none";
    560 				goto havedump;
    561 			}
    562 			dv = getdisk(buf, len, 1, nam2blk, &ndumpdev, 1);
    563 			if (dv) {
    564 				dumpdv = dv;
    565 				break;
    566 			}
    567 		}
    568 
    569  havedump:
    570 		rootdev = nrootdev;
    571 		dumpdev = ndumpdev;
    572 
    573 		for (i = 0; i < nvfssw; i++) {
    574 			if (vfssw[i] != NULL &&
    575 			    vfssw[i]->vfs_mountroot != NULL &&
    576 			    vfssw[i]->vfs_mountroot == mountroot)
    577 				break;
    578 		}
    579 		if (i >= nvfssw) {
    580 			mountroot = NULL;
    581 			deffsname = "generic";
    582 		} else
    583 			deffsname = vfssw[i]->vfs_name;
    584 		for (;;) {
    585 			printf("file system (default %s): ", deffsname);
    586 			len = getstr(buf, sizeof(buf));
    587 			if (len == 0)
    588 				break;
    589 			if (len == 4 && strcmp(buf, "halt") == 0)
    590 				cpu_reboot(RB_HALT, NULL);
    591 			else if (len == 7 && strcmp(buf, "generic") == 0) {
    592 				mountroot = NULL;
    593 				break;
    594 			}
    595 			vops = vfs_getopsbyname(buf);
    596 			if (vops == NULL || vops->vfs_mountroot == NULL) {
    597 				printf("use one of: generic");
    598 				for (i = 0; i < nvfssw; i++)
    599 					if (vfssw[i] != NULL &&
    600 					    vfssw[i]->vfs_mountroot != NULL)
    601 						printf(" %s",
    602 						    vfssw[i]->vfs_name);
    603 				printf(" halt\n");
    604 			} else {
    605 				mountroot = vops->vfs_mountroot;
    606 				break;
    607 			}
    608 		}
    609 
    610 	} else if (rootspec == NULL) {
    611 		int majdev;
    612 
    613 		/*
    614 		 * Wildcarded root; use the boot device.
    615 		 */
    616 		rootdv = bootdv;
    617 
    618 		majdev = findblkmajor(bootdv->dv_xname, nam2blk);
    619 		if (majdev >= 0) {
    620 			/*
    621 			 * Root is on a disk.  `bootpartition' is root.
    622 			 */
    623 			rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
    624 			    bootpartition);
    625 		}
    626 	} else {
    627 
    628 		/*
    629 		 * `root on <dev> ...'
    630 		 */
    631 
    632 		/*
    633 		 * If it's a network interface, we can bail out
    634 		 * early.
    635 		 */
    636 		for (dv = alldevs.tqh_first; dv != NULL;
    637 		    dv = dv->dv_list.tqe_next)
    638 			if (strcmp(dv->dv_xname, rootspec) == 0)
    639 				break;
    640 		if (dv != NULL && dv->dv_class == DV_IFNET) {
    641 			rootdv = dv;
    642 			goto haveroot;
    643 		}
    644 
    645 		rootdevname = findblkname(major(rootdev), nam2blk);
    646 		if (rootdevname == NULL) {
    647 			printf("unknown device major 0x%x\n", rootdev);
    648 			boothowto |= RB_ASKNAME;
    649 			goto top;
    650 		}
    651 		bzero(buf, sizeof(buf));
    652 		sprintf(buf, "%s%d", rootdevname, DISKUNIT(rootdev));
    653 
    654 		for (dv = alldevs.tqh_first; dv != NULL;
    655 		    dv = dv->dv_list.tqe_next) {
    656 			if (strcmp(buf, dv->dv_xname) == 0) {
    657 				rootdv = dv;
    658 				break;
    659 			}
    660 		}
    661 		if (rootdv == NULL) {
    662 			printf("device %s (0x%x) not configured\n",
    663 			    buf, rootdev);
    664 			boothowto |= RB_ASKNAME;
    665 			goto top;
    666 		}
    667 	}
    668 
    669  haveroot:
    670 
    671 	root_device = rootdv;
    672 
    673 	switch (rootdv->dv_class) {
    674 	case DV_IFNET:
    675 		/* Nothing. */
    676 		break;
    677 
    678 	case DV_DISK:
    679 		printf("root on %s%c", rootdv->dv_xname,
    680 		    DISKPART(rootdev) + 'a');
    681 		print_newline = 1;
    682 		break;
    683 
    684 	default:
    685 		printf("can't determine root device\n");
    686 		boothowto |= RB_ASKNAME;
    687 		goto top;
    688 	}
    689 
    690 	/*
    691 	 * Now configure the dump device.
    692 	 */
    693 
    694 	if (dumpspec != NULL && strcmp(dumpspec, "none") == 0) {
    695 		/*
    696 		 * Operator doesn't want a dump device.
    697 		 */
    698 		goto nodumpdev;
    699 	}
    700 
    701 	/*
    702 	 * If we haven't figured out the dump device, do so, with
    703 	 * the following rules:
    704 	 *
    705 	 *	(a) We already know dumpdv in the RB_ASKNAME case.
    706 	 *
    707 	 *	(b) If dumpspec is set, try to use it.  If the device
    708 	 *	    is not available, punt.
    709 	 *
    710 	 *	(c) If dumpspec is not set, the dump device is
    711 	 *	    wildcarded or unspecified.  If the root device
    712 	 *	    is DV_IFNET, punt.  Otherwise, use partition b
    713 	 *	    of the root device.
    714 	 */
    715 
    716 	if (boothowto & RB_ASKNAME) {
    717 		if (dumpdv == NULL) {
    718 			/*
    719 			 * Just return; dumpdev is already set to NODEV
    720 			 * and we don't want to print a newline in this
    721 			 * case.
    722 			 */
    723 			return;
    724 		}
    725 		goto out;
    726 	}
    727 
    728 	if (dumpspec != NULL) {
    729 		if (dumpdev == NODEV) {
    730 			/*
    731 			 * Looks like they tried to pick a network
    732 			 * device.  Oops.
    733 			 */
    734 			goto nodumpdev;
    735 		}
    736 
    737 		dumpdevname = findblkname(major(dumpdev), nam2blk);
    738 		if (dumpdevname == NULL)
    739 			goto nodumpdev;
    740 		bzero(buf, sizeof(buf));
    741 		sprintf(buf, "%s%d", dumpdevname, DISKUNIT(dumpdev));
    742 
    743 		for (dv = alldevs.tqh_first; dv != NULL;
    744 		    dv = dv->dv_list.tqe_next) {
    745 			if (strcmp(buf, dv->dv_xname) == 0) {
    746 				dumpdv = dv;
    747 				break;
    748 			}
    749 		}
    750 		if (dv == NULL) {
    751 			/*
    752 			 * Device not configured.
    753 			 */
    754 			goto nodumpdev;
    755 		}
    756 	} else if (rootdv->dv_class == DV_IFNET)
    757 		goto nodumpdev;
    758 	else {
    759 		dumpdv = rootdv;
    760 		dumpdev = MAKEDISKDEV(major(rootdev), dumpdv->dv_unit, 1);
    761 	}
    762 
    763  out:
    764 	printf(" dumps on %s%c\n", dumpdv->dv_xname, DISKPART(dumpdev) + 'a');
    765 	return;
    766 
    767  nodumpdev:
    768 	dumpdev = NODEV;
    769 	if (print_newline)
    770 		printf("\n");
    771 }
    772 
    773 static int
    774 findblkmajor(name, nam2blk)
    775 	const char *name;
    776 	struct devnametobdevmaj *nam2blk;
    777 {
    778 	int i;
    779 
    780 	if (nam2blk == NULL)
    781 		return (-1);
    782 
    783 	for (i = 0; nam2blk[i].d_name != NULL; i++)
    784 		if (strncmp(name, nam2blk[i].d_name,
    785 		    strlen(nam2blk[i].d_name)) == 0)
    786 			return (nam2blk[i].d_maj);
    787 	return (-1);
    788 }
    789 
    790 const char *
    791 findblkname(maj, nam2blk)
    792 	int maj;
    793 	struct devnametobdevmaj *nam2blk;
    794 {
    795 	int i;
    796 
    797 	if (nam2blk == NULL)
    798 		return (NULL);
    799 
    800 	for (i = 0; nam2blk[i].d_name != NULL; i++)
    801 		if (nam2blk[i].d_maj == maj)
    802 			return (nam2blk[i].d_name);
    803 	return (NULL);
    804 }
    805 
    806 static struct device *
    807 getdisk(str, len, defpart, nam2blk, devp, isdump)
    808 	char *str;
    809 	int len, defpart;
    810 	struct devnametobdevmaj *nam2blk;
    811 	dev_t *devp;
    812 	int isdump;
    813 {
    814 	struct device	*dv;
    815 #ifdef MEMORY_DISK_HOOKS
    816 	int		i;
    817 #endif
    818 
    819 	if ((dv = parsedisk(str, len, defpart, nam2blk, devp)) == NULL) {
    820 		printf("use one of:");
    821 #ifdef MEMORY_DISK_HOOKS
    822 		if (isdump == 0)
    823 			for (i = 0; i < NMD; i++)
    824 				printf(" %s[a-%c]", fakemdrootdev[i].dv_xname,
    825 				    'a' + MAXPARTITIONS - 1);
    826 #endif
    827 		for (dv = alldevs.tqh_first; dv != NULL;
    828 		    dv = dv->dv_list.tqe_next) {
    829 			if (dv->dv_class == DV_DISK)
    830 				printf(" %s[a-%c]", dv->dv_xname,
    831 				    'a' + MAXPARTITIONS - 1);
    832 			if (isdump == 0 && dv->dv_class == DV_IFNET)
    833 				printf(" %s", dv->dv_xname);
    834 		}
    835 		if (isdump)
    836 			printf(" none");
    837 		printf(" halt\n");
    838 	}
    839 	return (dv);
    840 }
    841 
    842 static struct device *
    843 parsedisk(str, len, defpart, nam2blk, devp)
    844 	char *str;
    845 	int len, defpart;
    846 	struct devnametobdevmaj *nam2blk;
    847 	dev_t *devp;
    848 {
    849 	struct device *dv;
    850 	char *cp, c;
    851 	int majdev, part;
    852 #ifdef MEMORY_DISK_HOOKS
    853 	int i;
    854 #endif
    855 
    856 	if (len == 0)
    857 		return (NULL);
    858 
    859 	if (len == 4 && strcmp(str, "halt") == 0)
    860 		cpu_reboot(RB_HALT, NULL);
    861 
    862 	cp = str + len - 1;
    863 	c = *cp;
    864 	if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
    865 		part = c - 'a';
    866 		*cp = '\0';
    867 	} else
    868 		part = defpart;
    869 
    870 #ifdef MEMORY_DISK_HOOKS
    871 	for (i = 0; i < NMD; i++)
    872 		if (strcmp(str, fakemdrootdev[i].dv_xname) == 0) {
    873 			dv = &fakemdrootdev[i];
    874 			goto gotdisk;
    875 		}
    876 #endif
    877 
    878 	for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
    879 		if (dv->dv_class == DV_DISK &&
    880 		    strcmp(str, dv->dv_xname) == 0) {
    881 #ifdef MEMORY_DISK_HOOKS
    882  gotdisk:
    883 #endif
    884 			majdev = findblkmajor(dv->dv_xname, nam2blk);
    885 			if (majdev < 0)
    886 				panic("parsedisk");
    887 			*devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
    888 			break;
    889 		}
    890 
    891 		if (dv->dv_class == DV_IFNET &&
    892 		    strcmp(str, dv->dv_xname) == 0) {
    893 			*devp = NODEV;
    894 			break;
    895 		}
    896 	}
    897 
    898 	*cp = c;
    899 	return (dv);
    900 }
    901 
    902 /*
    903  * XXX shouldn't this be a common function?
    904  */
    905 static int
    906 getstr(cp, size)
    907 	char *cp;
    908 	int size;
    909 {
    910 	char *lp;
    911 	int c, len;
    912 
    913 	cnpollc(1);
    914 
    915 	lp = cp;
    916 	len = 0;
    917 	for (;;) {
    918 		c = cngetc();
    919 		switch (c) {
    920 		case '\n':
    921 		case '\r':
    922 			printf("\n");
    923 			*lp++ = '\0';
    924 			cnpollc(0);
    925 			return (len);
    926 		case '\b':
    927 		case '\177':
    928 		case '#':
    929 			if (len) {
    930 				--len;
    931 				--lp;
    932 				printf("\b \b");
    933 			}
    934 			continue;
    935 		case '@':
    936 		case 'u'&037:
    937 			len = 0;
    938 			lp = cp;
    939 			printf("\n");
    940 			continue;
    941 		default:
    942 			if (len + 1 >= size || c < ' ') {
    943 				printf("\007");
    944 				continue;
    945 			}
    946 			printf("%c", c);
    947 			++len;
    948 			*lp++ = c;
    949 		}
    950 	}
    951 }
    952