xref: /netbsd-src/sys/kern/kern_subr.c (revision 1ca5c1b28139779176bd5c13ad7c5f25c0bcd5f8)
1 /*	$NetBSD: kern_subr.c,v 1.77 2001/11/12 15:25:15 lukem 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 <sys/cdefs.h>
93 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.77 2001/11/12 15:25:15 lukem Exp $");
94 
95 #include "opt_md.h"
96 
97 #include <sys/param.h>
98 #include <sys/systm.h>
99 #include <sys/proc.h>
100 #include <sys/malloc.h>
101 #include <sys/mount.h>
102 #include <sys/device.h>
103 #include <sys/reboot.h>
104 #include <sys/conf.h>
105 #include <sys/disklabel.h>
106 #include <sys/queue.h>
107 
108 #include <dev/cons.h>
109 
110 #include <net/if.h>
111 
112 /* XXX these should eventually move to subr_autoconf.c */
113 static int findblkmajor __P((const char *));
114 const char *findblkname __P((int));
115 static struct device *finddevice __P((const char *));
116 static struct device *getdisk __P((char *, int, int, dev_t *, int));
117 static struct device *parsedisk __P((char *, int, int, dev_t *));
118 
119 int
120 uiomove(buf, n, uio)
121 	void *buf;
122 	int n;
123 	struct uio *uio;
124 {
125 	struct iovec *iov;
126 	u_int cnt;
127 	int error = 0;
128 	char *cp = buf;
129 	struct proc *p = uio->uio_procp;
130 
131 #ifdef DIAGNOSTIC
132 	if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
133 		panic("uiomove: mode");
134 	if (uio->uio_segflg == UIO_USERSPACE && p != curproc)
135 		panic("uiomove proc");
136 #endif
137 	while (n > 0 && uio->uio_resid) {
138 		iov = uio->uio_iov;
139 		cnt = iov->iov_len;
140 		if (cnt == 0) {
141 			uio->uio_iov++;
142 			uio->uio_iovcnt--;
143 			continue;
144 		}
145 		if (cnt > n)
146 			cnt = n;
147 		switch (uio->uio_segflg) {
148 
149 		case UIO_USERSPACE:
150 			KDASSERT(p->p_cpu != NULL);
151 			KDASSERT(p->p_cpu == curcpu());
152 			if (p->p_cpu->ci_schedstate.spc_flags &
153 			    SPCF_SHOULDYIELD)
154 				preempt(NULL);
155 			if (uio->uio_rw == UIO_READ)
156 				error = copyout(cp, iov->iov_base, cnt);
157 			else
158 				error = copyin(iov->iov_base, cp, cnt);
159 			if (error)
160 				return (error);
161 			break;
162 
163 		case UIO_SYSSPACE:
164 			if (uio->uio_rw == UIO_READ)
165 				error = kcopy(cp, iov->iov_base, cnt);
166 			else
167 				error = kcopy(iov->iov_base, cp, cnt);
168 			if (error)
169 				return (error);
170 			break;
171 		}
172 		iov->iov_base = (caddr_t)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 	int c;
188 	struct uio *uio;
189 {
190 	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 		*(char *)iov->iov_base = c;
212 		break;
213 	}
214 	iov->iov_base = (caddr_t)iov->iov_base + 1;
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  * Allocate enough memory to hold at least `elements' list-head pointers.
224  * Return a pointer to the allocated space and set *hashmask to a pattern
225  * suitable for masking a value to use as an index into the returned array.
226  */
227 void *
228 hashinit(elements, htype, mtype, mflags, hashmask)
229 	int elements;
230 	enum hashtype htype;
231 	int mtype, mflags;
232 	u_long *hashmask;
233 {
234 	long hashsize;
235 	LIST_HEAD(, generic) *hashtbl_list;
236 	TAILQ_HEAD(, generic) *hashtbl_tailq;
237 	int i, esize;
238 	void *p;
239 
240 	if (elements <= 0)
241 		panic("hashinit: bad cnt");
242 	for (hashsize = 1; hashsize < elements; hashsize <<= 1)
243 		continue;
244 
245 	switch (htype) {
246 	case HASH_LIST:
247 		esize = sizeof(*hashtbl_list);
248 		break;
249 	case HASH_TAILQ:
250 		esize = sizeof(*hashtbl_tailq);
251 		break;
252 #ifdef DIAGNOSTIC
253 	default:
254 		panic("hashinit: invalid table type");
255 #endif
256 	}
257 
258 	if ((p = malloc((u_long)hashsize * esize, mtype, mflags)) == NULL)
259 		return (NULL);
260 
261 	switch (htype) {
262 	case HASH_LIST:
263 		hashtbl_list = p;
264 		for (i = 0; i < hashsize; i++)
265 			LIST_INIT(&hashtbl_list[i]);
266 		break;
267 	case HASH_TAILQ:
268 		hashtbl_tailq = p;
269 		for (i = 0; i < hashsize; i++)
270 			TAILQ_INIT(&hashtbl_tailq[i]);
271 		break;
272 	}
273 	*hashmask = hashsize - 1;
274 	return (p);
275 }
276 
277 /*
278  * Free memory from hash table previosly allocated via hashinit().
279  */
280 void
281 hashdone(hashtbl, mtype)
282 	void *hashtbl;
283 	int mtype;
284 {
285 
286 	free(hashtbl, mtype);
287 }
288 
289 /*
290  * "Shutdown hook" types, functions, and variables.
291  */
292 
293 struct shutdownhook_desc {
294 	LIST_ENTRY(shutdownhook_desc) sfd_list;
295 	void	(*sfd_fn) __P((void *));
296 	void	*sfd_arg;
297 };
298 
299 LIST_HEAD(, shutdownhook_desc) shutdownhook_list;
300 
301 void *
302 shutdownhook_establish(fn, arg)
303 	void (*fn) __P((void *));
304 	void *arg;
305 {
306 	struct shutdownhook_desc *ndp;
307 
308 	ndp = (struct shutdownhook_desc *)
309 	    malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
310 	if (ndp == NULL)
311 		return (NULL);
312 
313 	ndp->sfd_fn = fn;
314 	ndp->sfd_arg = arg;
315 	LIST_INSERT_HEAD(&shutdownhook_list, ndp, sfd_list);
316 
317 	return (ndp);
318 }
319 
320 void
321 shutdownhook_disestablish(vhook)
322 	void *vhook;
323 {
324 #ifdef DIAGNOSTIC
325 	struct shutdownhook_desc *dp;
326 
327 	for (dp = shutdownhook_list.lh_first; dp != NULL;
328 	    dp = dp->sfd_list.le_next)
329                 if (dp == vhook)
330 			break;
331 	if (dp == NULL)
332 		panic("shutdownhook_disestablish: hook not established");
333 #endif
334 
335 	LIST_REMOVE((struct shutdownhook_desc *)vhook, sfd_list);
336 	free(vhook, M_DEVBUF);
337 }
338 
339 /*
340  * Run shutdown hooks.  Should be invoked immediately before the
341  * system is halted or rebooted, i.e. after file systems unmounted,
342  * after crash dump done, etc.
343  *
344  * Each shutdown hook is removed from the list before it's run, so that
345  * it won't be run again.
346  */
347 void
348 doshutdownhooks()
349 {
350 	struct shutdownhook_desc *dp;
351 
352 	while ((dp = shutdownhook_list.lh_first) != NULL) {
353 		LIST_REMOVE(dp, sfd_list);
354 		(*dp->sfd_fn)(dp->sfd_arg);
355 #if 0
356 		/*
357 		 * Don't bother freeing the hook structure,, since we may
358 		 * be rebooting because of a memory corruption problem,
359 		 * and this might only make things worse.  It doesn't
360 		 * matter, anyway, since the system is just about to
361 		 * reboot.
362 		 */
363 		free(dp, M_DEVBUF);
364 #endif
365 	}
366 }
367 
368 /*
369  * "Power hook" types, functions, and variables.
370  * The list of power hooks is kept ordered with the last registered hook
371  * first.
372  * When running the hooks on power down the hooks are called in reverse
373  * registration order, when powering up in registration order.
374  */
375 
376 struct powerhook_desc {
377 	CIRCLEQ_ENTRY(powerhook_desc) sfd_list;
378 	void	(*sfd_fn) __P((int, void *));
379 	void	*sfd_arg;
380 };
381 
382 CIRCLEQ_HEAD(, powerhook_desc) powerhook_list =
383 	CIRCLEQ_HEAD_INITIALIZER(powerhook_list);
384 
385 void *
386 powerhook_establish(fn, arg)
387 	void (*fn) __P((int, void *));
388 	void *arg;
389 {
390 	struct powerhook_desc *ndp;
391 
392 	ndp = (struct powerhook_desc *)
393 	    malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
394 	if (ndp == NULL)
395 		return (NULL);
396 
397 	ndp->sfd_fn = fn;
398 	ndp->sfd_arg = arg;
399 	CIRCLEQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
400 
401 	return (ndp);
402 }
403 
404 void
405 powerhook_disestablish(vhook)
406 	void *vhook;
407 {
408 #ifdef DIAGNOSTIC
409 	struct powerhook_desc *dp;
410 
411 	CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list)
412                 if (dp == vhook)
413 			goto found;
414 	panic("powerhook_disestablish: hook not established");
415  found:
416 #endif
417 
418 	CIRCLEQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
419 	    sfd_list);
420 	free(vhook, M_DEVBUF);
421 }
422 
423 /*
424  * Run power hooks.
425  */
426 void
427 dopowerhooks(why)
428 	int why;
429 {
430 	struct powerhook_desc *dp;
431 
432 	if (why == PWR_RESUME || why == PWR_SOFTRESUME) {
433 		CIRCLEQ_FOREACH_REVERSE(dp, &powerhook_list, sfd_list) {
434 			(*dp->sfd_fn)(why, dp->sfd_arg);
435 		}
436 	} else {
437 		CIRCLEQ_FOREACH(dp, &powerhook_list, sfd_list) {
438 			(*dp->sfd_fn)(why, dp->sfd_arg);
439 		}
440 	}
441 }
442 
443 /*
444  * "Mountroot hook" types, functions, and variables.
445  */
446 
447 struct mountroothook_desc {
448 	LIST_ENTRY(mountroothook_desc) mrd_list;
449 	struct	device *mrd_device;
450 	void 	(*mrd_func) __P((struct device *));
451 };
452 
453 LIST_HEAD(, mountroothook_desc) mountroothook_list;
454 
455 void *
456 mountroothook_establish(func, dev)
457 	void (*func) __P((struct device *));
458 	struct device *dev;
459 {
460 	struct mountroothook_desc *mrd;
461 
462 	mrd = (struct mountroothook_desc *)
463 	    malloc(sizeof(*mrd), M_DEVBUF, M_NOWAIT);
464 	if (mrd == NULL)
465 		return (NULL);
466 
467 	mrd->mrd_device = dev;
468 	mrd->mrd_func = func;
469 	LIST_INSERT_HEAD(&mountroothook_list, mrd, mrd_list);
470 
471 	return (mrd);
472 }
473 
474 void
475 mountroothook_disestablish(vhook)
476 	void *vhook;
477 {
478 #ifdef DIAGNOSTIC
479 	struct mountroothook_desc *mrd;
480 
481 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
482 	    mrd = mrd->mrd_list.le_next)
483                 if (mrd == vhook)
484 			break;
485 	if (mrd == NULL)
486 		panic("mountroothook_disestablish: hook not established");
487 #endif
488 
489 	LIST_REMOVE((struct mountroothook_desc *)vhook, mrd_list);
490 	free(vhook, M_DEVBUF);
491 }
492 
493 void
494 mountroothook_destroy()
495 {
496 	struct mountroothook_desc *mrd;
497 
498 	while ((mrd = mountroothook_list.lh_first) != NULL) {
499 		LIST_REMOVE(mrd, mrd_list);
500 		free(mrd, M_DEVBUF);
501 	}
502 }
503 
504 void
505 domountroothook()
506 {
507 	struct mountroothook_desc *mrd;
508 
509 	for (mrd = mountroothook_list.lh_first; mrd != NULL;
510 	    mrd = mrd->mrd_list.le_next) {
511 		if (mrd->mrd_device == root_device) {
512 			(*mrd->mrd_func)(root_device);
513 			return;
514 		}
515 	}
516 }
517 
518 /*
519  * Exec hook code.
520  */
521 
522 struct exechook_desc {
523 	LIST_ENTRY(exechook_desc) ehk_list;
524 	void	(*ehk_fn) __P((struct proc *, void *));
525 	void	*ehk_arg;
526 };
527 
528 LIST_HEAD(, exechook_desc) exechook_list;
529 
530 void *
531 exechook_establish(fn, arg)
532 	void (*fn) __P((struct proc *, void *));
533 	void *arg;
534 {
535 	struct exechook_desc *edp;
536 
537 	edp = (struct exechook_desc *)
538 	    malloc(sizeof(*edp), M_DEVBUF, M_NOWAIT);
539 	if (edp == NULL)
540 		return (NULL);
541 
542 	edp->ehk_fn = fn;
543 	edp->ehk_arg = arg;
544 	LIST_INSERT_HEAD(&exechook_list, edp, ehk_list);
545 
546 	return (edp);
547 }
548 
549 void
550 exechook_disestablish(vhook)
551 	void *vhook;
552 {
553 #ifdef DIAGNOSTIC
554 	struct exechook_desc *edp;
555 
556 	for (edp = exechook_list.lh_first; edp != NULL;
557 	    edp = edp->ehk_list.le_next)
558                 if (edp == vhook)
559 			break;
560 	if (edp == NULL)
561 		panic("exechook_disestablish: hook not established");
562 #endif
563 
564 	LIST_REMOVE((struct exechook_desc *)vhook, ehk_list);
565 	free(vhook, M_DEVBUF);
566 }
567 
568 /*
569  * Run exec hooks.
570  */
571 void
572 doexechooks(p)
573 	struct proc *p;
574 {
575 	struct exechook_desc *edp;
576 
577 	for (edp = LIST_FIRST(&exechook_list);
578 	     edp != NULL;
579 	     edp = LIST_NEXT(edp, ehk_list)) {
580 		(*edp->ehk_fn)(p, edp->ehk_arg);
581 	}
582 }
583 
584 /*
585  * Determine the root device and, if instructed to, the root file system.
586  */
587 
588 #include "md.h"
589 #if NMD == 0
590 #undef MEMORY_DISK_HOOKS
591 #endif
592 
593 #ifdef MEMORY_DISK_HOOKS
594 static struct device fakemdrootdev[NMD];
595 #endif
596 
597 #include "raid.h"
598 #if NRAID == 1
599 #define BOOT_FROM_RAID_HOOKS 1
600 #endif
601 
602 #ifdef BOOT_FROM_RAID_HOOKS
603 extern int numraid;
604 extern struct device *raidrootdev;
605 #endif
606 
607 void
608 setroot(bootdv, bootpartition)
609 	struct device *bootdv;
610 	int bootpartition;
611 {
612 	struct device *dv;
613 	int len;
614 #ifdef MEMORY_DISK_HOOKS
615 	int i;
616 #endif
617 	dev_t nrootdev;
618 	dev_t ndumpdev = NODEV;
619 	char buf[128];
620 	const char *rootdevname;
621 	const char *dumpdevname;
622 	struct device *rootdv = NULL;		/* XXX gcc -Wuninitialized */
623 	struct device *dumpdv = NULL;
624 	struct ifnet *ifp;
625 	const char *deffsname;
626 	struct vfsops *vops;
627 	extern int (*mountroot) __P((void));
628 
629 #ifdef MEMORY_DISK_HOOKS
630 	for (i = 0; i < NMD; i++) {
631 		fakemdrootdev[i].dv_class  = DV_DISK;
632 		fakemdrootdev[i].dv_cfdata = NULL;
633 		fakemdrootdev[i].dv_unit   = i;
634 		fakemdrootdev[i].dv_parent = NULL;
635 		sprintf(fakemdrootdev[i].dv_xname, "md%d", i);
636 	}
637 #endif /* MEMORY_DISK_HOOKS */
638 
639 #ifdef MEMORY_DISK_IS_ROOT
640 	bootdv = &fakemdrootdev[0];
641 	bootpartition = 0;
642 #endif
643 
644 	/*
645 	 * If NFS is specified as the file system, and we found
646 	 * a DV_DISK boot device (or no boot device at all), then
647 	 * find a reasonable network interface for "rootspec".
648 	 */
649 	vops = vfs_getopsbyname("nfs");
650 	if (vops != NULL && vops->vfs_mountroot == mountroot &&
651 	    rootspec == NULL &&
652 	    (bootdv == NULL || bootdv->dv_class != DV_IFNET)) {
653 		for (ifp = ifnet.tqh_first; ifp != NULL;
654 		    ifp = ifp->if_list.tqe_next)
655 			if ((ifp->if_flags &
656 			     (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
657 				break;
658 		if (ifp == NULL) {
659 			/*
660 			 * Can't find a suitable interface; ask the
661 			 * user.
662 			 */
663 			boothowto |= RB_ASKNAME;
664 		} else {
665 			/*
666 			 * Have a suitable interface; behave as if
667 			 * the user specified this interface.
668 			 */
669 			rootspec = (const char *)ifp->if_xname;
670 		}
671 	}
672 
673 	/*
674 	 * If wildcarded root and we the boot device wasn't determined,
675 	 * ask the user.
676 	 */
677 	if (rootspec == NULL && bootdv == NULL)
678 		boothowto |= RB_ASKNAME;
679 
680  top:
681 	if (boothowto & RB_ASKNAME) {
682 		struct device *defdumpdv;
683 
684 		for (;;) {
685 			printf("root device");
686 			if (bootdv != NULL) {
687 				printf(" (default %s", bootdv->dv_xname);
688 				if (bootdv->dv_class == DV_DISK)
689 					printf("%c", bootpartition + 'a');
690 				printf(")");
691 			}
692 			printf(": ");
693 			len = cngetsn(buf, sizeof(buf));
694 			if (len == 0 && bootdv != NULL) {
695 				strcpy(buf, bootdv->dv_xname);
696 				len = strlen(buf);
697 			}
698 			if (len > 0 && buf[len - 1] == '*') {
699 				buf[--len] = '\0';
700 				dv = getdisk(buf, len, 1, &nrootdev, 0);
701 				if (dv != NULL) {
702 					rootdv = dv;
703 					break;
704 				}
705 			}
706 			dv = getdisk(buf, len, bootpartition, &nrootdev, 0);
707 			if (dv != NULL) {
708 				rootdv = dv;
709 				break;
710 			}
711 		}
712 
713 		/*
714 		 * Set up the default dump device.  If root is on
715 		 * a network device, there is no default dump
716 		 * device, since we don't support dumps to the
717 		 * network.
718 		 */
719 		if (rootdv->dv_class == DV_IFNET)
720 			defdumpdv = NULL;
721 		else
722 			defdumpdv = rootdv;
723 
724 		for (;;) {
725 			printf("dump device");
726 			if (defdumpdv != NULL) {
727 				/*
728 				 * Note, we know it's a disk if we get here.
729 				 */
730 				printf(" (default %sb)", defdumpdv->dv_xname);
731 			}
732 			printf(": ");
733 			len = cngetsn(buf, sizeof(buf));
734 			if (len == 0) {
735 				if (defdumpdv != NULL) {
736 					ndumpdev = MAKEDISKDEV(major(nrootdev),
737 					    DISKUNIT(nrootdev), 1);
738 				}
739 				dumpdv = defdumpdv;
740 				break;
741 			}
742 			if (len == 4 && strcmp(buf, "none") == 0) {
743 				dumpdv = NULL;
744 				break;
745 			}
746 			dv = getdisk(buf, len, 1, &ndumpdev, 1);
747 			if (dv != NULL) {
748 				dumpdv = dv;
749 				break;
750 			}
751 		}
752 
753 		rootdev = nrootdev;
754 		dumpdev = ndumpdev;
755 
756 		for (vops = LIST_FIRST(&vfs_list); vops != NULL;
757 		     vops = LIST_NEXT(vops, vfs_list)) {
758 			if (vops->vfs_mountroot != NULL &&
759 			    vops->vfs_mountroot == mountroot)
760 			break;
761 		}
762 
763 		if (vops == NULL) {
764 			mountroot = NULL;
765 			deffsname = "generic";
766 		} else
767 			deffsname = vops->vfs_name;
768 
769 		for (;;) {
770 			printf("file system (default %s): ", deffsname);
771 			len = cngetsn(buf, sizeof(buf));
772 			if (len == 0)
773 				break;
774 			if (len == 4 && strcmp(buf, "halt") == 0)
775 				cpu_reboot(RB_HALT, NULL);
776 			else if (len == 6 && strcmp(buf, "reboot") == 0)
777 				cpu_reboot(0, NULL);
778 			else if (len == 7 && strcmp(buf, "generic") == 0) {
779 				mountroot = NULL;
780 				break;
781 			}
782 			vops = vfs_getopsbyname(buf);
783 			if (vops == NULL || vops->vfs_mountroot == NULL) {
784 				printf("use one of: generic");
785 				for (vops = LIST_FIRST(&vfs_list);
786 				     vops != NULL;
787 				     vops = LIST_NEXT(vops, vfs_list)) {
788 					if (vops->vfs_mountroot != NULL)
789 						printf(" %s", vops->vfs_name);
790 				}
791 				printf(" halt reboot\n");
792 			} else {
793 				mountroot = vops->vfs_mountroot;
794 				break;
795 			}
796 		}
797 
798 	} else if (rootspec == NULL) {
799 		int majdev;
800 
801 		/*
802 		 * Wildcarded root; use the boot device.
803 		 */
804 		rootdv = bootdv;
805 
806 		majdev = findblkmajor(bootdv->dv_xname);
807 		if (majdev >= 0) {
808 			/*
809 			 * Root is on a disk.  `bootpartition' is root.
810 			 */
811 			rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
812 			    bootpartition);
813 		}
814 	} else {
815 
816 		/*
817 		 * `root on <dev> ...'
818 		 */
819 
820 		/*
821 		 * If it's a network interface, we can bail out
822 		 * early.
823 		 */
824 		dv = finddevice(rootspec);
825 		if (dv != NULL && dv->dv_class == DV_IFNET) {
826 			rootdv = dv;
827 			goto haveroot;
828 		}
829 
830 		rootdevname = findblkname(major(rootdev));
831 		if (rootdevname == NULL) {
832 			printf("unknown device major 0x%x\n", rootdev);
833 			boothowto |= RB_ASKNAME;
834 			goto top;
835 		}
836 		memset(buf, 0, sizeof(buf));
837 		sprintf(buf, "%s%d", rootdevname, DISKUNIT(rootdev));
838 
839 		rootdv = finddevice(buf);
840 		if (rootdv == NULL) {
841 			printf("device %s (0x%x) not configured\n",
842 			    buf, rootdev);
843 			boothowto |= RB_ASKNAME;
844 			goto top;
845 		}
846 	}
847 
848  haveroot:
849 
850 	root_device = rootdv;
851 
852 	switch (rootdv->dv_class) {
853 	case DV_IFNET:
854 		printf("root on %s", rootdv->dv_xname);
855 		break;
856 
857 	case DV_DISK:
858 		printf("root on %s%c", rootdv->dv_xname,
859 		    DISKPART(rootdev) + 'a');
860 		break;
861 
862 	default:
863 		printf("can't determine root device\n");
864 		boothowto |= RB_ASKNAME;
865 		goto top;
866 	}
867 
868 	/*
869 	 * Now configure the dump device.
870 	 *
871 	 * If we haven't figured out the dump device, do so, with
872 	 * the following rules:
873 	 *
874 	 *	(a) We already know dumpdv in the RB_ASKNAME case.
875 	 *
876 	 *	(b) If dumpspec is set, try to use it.  If the device
877 	 *	    is not available, punt.
878 	 *
879 	 *	(c) If dumpspec is not set, the dump device is
880 	 *	    wildcarded or unspecified.  If the root device
881 	 *	    is DV_IFNET, punt.  Otherwise, use partition b
882 	 *	    of the root device.
883 	 */
884 
885 	if (boothowto & RB_ASKNAME) {		/* (a) */
886 		if (dumpdv == NULL)
887 			goto nodumpdev;
888 	} else if (dumpspec != NULL) {		/* (b) */
889 		if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) {
890 			/*
891 			 * Operator doesn't want a dump device.
892 			 * Or looks like they tried to pick a network
893 			 * device.  Oops.
894 			 */
895 			goto nodumpdev;
896 		}
897 
898 		dumpdevname = findblkname(major(dumpdev));
899 		if (dumpdevname == NULL)
900 			goto nodumpdev;
901 		memset(buf, 0, sizeof(buf));
902 		sprintf(buf, "%s%d", dumpdevname, DISKUNIT(dumpdev));
903 
904 		dumpdv = finddevice(buf);
905 		if (dumpdv == NULL) {
906 			/*
907 			 * Device not configured.
908 			 */
909 			goto nodumpdev;
910 		}
911 	} else {				/* (c) */
912 		if (rootdv->dv_class == DV_IFNET)
913 			goto nodumpdev;
914 		else {
915 			dumpdv = rootdv;
916 			dumpdev = MAKEDISKDEV(major(rootdev),
917 			    dumpdv->dv_unit, 1);
918 		}
919 	}
920 
921 	printf(" dumps on %s%c\n", dumpdv->dv_xname, DISKPART(dumpdev) + 'a');
922 	return;
923 
924  nodumpdev:
925 	dumpdev = NODEV;
926 	printf("\n");
927 }
928 
929 static int
930 findblkmajor(name)
931 	const char *name;
932 {
933 	int i;
934 
935 	for (i = 0; dev_name2blk[i].d_name != NULL; i++)
936 		if (strncmp(name, dev_name2blk[i].d_name,
937 		    strlen(dev_name2blk[i].d_name)) == 0)
938 			return (dev_name2blk[i].d_maj);
939 	return (-1);
940 }
941 
942 const char *
943 findblkname(maj)
944 	int maj;
945 {
946 	int i;
947 
948 	for (i = 0; dev_name2blk[i].d_name != NULL; i++)
949 		if (dev_name2blk[i].d_maj == maj)
950 			return (dev_name2blk[i].d_name);
951 	return (NULL);
952 }
953 
954 static struct device *
955 finddevice(name)
956 	const char *name;
957 {
958 	struct device *dv;
959 #ifdef BOOT_FROM_RAID_HOOKS
960 	int j;
961 
962 	for (j = 0; j < numraid; j++) {
963 		if (strcmp(name, raidrootdev[j].dv_xname) == 0) {
964 			dv = &raidrootdev[j];
965 			return (dv);
966 		}
967 	}
968 #endif
969 
970 	for (dv = TAILQ_FIRST(&alldevs); dv != NULL;
971 	    dv = TAILQ_NEXT(dv, dv_list))
972 		if (strcmp(dv->dv_xname, name) == 0)
973 			break;
974 	return (dv);
975 }
976 
977 static struct device *
978 getdisk(str, len, defpart, devp, isdump)
979 	char *str;
980 	int len, defpart;
981 	dev_t *devp;
982 	int isdump;
983 {
984 	struct device	*dv;
985 #ifdef MEMORY_DISK_HOOKS
986 	int		i;
987 #endif
988 #ifdef BOOT_FROM_RAID_HOOKS
989 	int 		j;
990 #endif
991 
992 	if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
993 		printf("use one of:");
994 #ifdef MEMORY_DISK_HOOKS
995 		if (isdump == 0)
996 			for (i = 0; i < NMD; i++)
997 				printf(" %s[a-%c]", fakemdrootdev[i].dv_xname,
998 				    'a' + MAXPARTITIONS - 1);
999 #endif
1000 #ifdef BOOT_FROM_RAID_HOOKS
1001 		if (isdump == 0)
1002 			for (j = 0; j < numraid; j++)
1003 				printf(" %s[a-%c]", raidrootdev[j].dv_xname,
1004 				    'a' + MAXPARTITIONS - 1);
1005 #endif
1006 		for (dv = alldevs.tqh_first; dv != NULL;
1007 		    dv = dv->dv_list.tqe_next) {
1008 			if (dv->dv_class == DV_DISK)
1009 				printf(" %s[a-%c]", dv->dv_xname,
1010 				    'a' + MAXPARTITIONS - 1);
1011 			if (isdump == 0 && dv->dv_class == DV_IFNET)
1012 				printf(" %s", dv->dv_xname);
1013 		}
1014 		if (isdump)
1015 			printf(" none");
1016 		printf(" halt reboot\n");
1017 	}
1018 	return (dv);
1019 }
1020 
1021 static struct device *
1022 parsedisk(str, len, defpart, devp)
1023 	char *str;
1024 	int len, defpart;
1025 	dev_t *devp;
1026 {
1027 	struct device *dv;
1028 	char *cp, c;
1029 	int majdev, part;
1030 #ifdef MEMORY_DISK_HOOKS
1031 	int i;
1032 #endif
1033 	if (len == 0)
1034 		return (NULL);
1035 
1036 	if (len == 4 && strcmp(str, "halt") == 0)
1037 		cpu_reboot(RB_HALT, NULL);
1038 	else if (len == 6 && strcmp(str, "reboot") == 0)
1039 		cpu_reboot(0, NULL);
1040 
1041 	cp = str + len - 1;
1042 	c = *cp;
1043 	if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
1044 		part = c - 'a';
1045 		*cp = '\0';
1046 	} else
1047 		part = defpart;
1048 
1049 #ifdef MEMORY_DISK_HOOKS
1050 	for (i = 0; i < NMD; i++)
1051 		if (strcmp(str, fakemdrootdev[i].dv_xname) == 0) {
1052 			dv = &fakemdrootdev[i];
1053 			goto gotdisk;
1054 		}
1055 #endif
1056 
1057 	dv = finddevice(str);
1058 	if (dv != NULL) {
1059 		if (dv->dv_class == DV_DISK) {
1060 #ifdef MEMORY_DISK_HOOKS
1061  gotdisk:
1062 #endif
1063 			majdev = findblkmajor(dv->dv_xname);
1064 			if (majdev < 0)
1065 				panic("parsedisk");
1066 			*devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
1067 		}
1068 
1069 		if (dv->dv_class == DV_IFNET)
1070 			*devp = NODEV;
1071 	}
1072 
1073 	*cp = c;
1074 	return (dv);
1075 }
1076 
1077 /*
1078  * snprintf() `bytes' into `buf', reformatting it so that the number,
1079  * plus a possible `x' + suffix extension) fits into len bytes (including
1080  * the terminating NUL).
1081  * Returns the number of bytes stored in buf, or -1 if there was a problem.
1082  * E.g, given a len of 9 and a suffix of `B':
1083  *	bytes		result
1084  *	-----		------
1085  *	99999		`99999 B'
1086  *	100000		`97 KB'
1087  *	66715648	`65152 KB'
1088  *	252215296	`240 MB'
1089  */
1090 int
1091 humanize_number(buf, len, bytes, suffix, divisor)
1092 	char		*buf;
1093 	size_t		 len;
1094 	u_int64_t	 bytes;
1095 	const char	*suffix;
1096 	int 		divisor;
1097 {
1098 		/* prefixes are: (none), Kilo, Mega, Giga, Tera, Peta, Exa */
1099 	static const char prefixes[] = " KMGTPE";
1100 
1101 	int		i, r;
1102 	u_int64_t	max;
1103 	size_t		suffixlen;
1104 
1105 	if (buf == NULL || suffix == NULL)
1106 		return (-1);
1107 	if (len > 0)
1108 		buf[0] = '\0';
1109 	suffixlen = strlen(suffix);
1110 			/* check if enough room for `x y' + suffix + `\0' */
1111 	if (len < 4 + suffixlen)
1112 		return (-1);
1113 
1114 	max = 1;
1115 	for (i = 0; i < len - suffixlen - 3; i++)
1116 		max *= 10;
1117 	for (i = 0; bytes >= max && i < sizeof(prefixes); i++)
1118 		bytes /= divisor;
1119 
1120 	r = snprintf(buf, len, "%qu%s%c%s", (unsigned long long)bytes,
1121 	    i == 0 ? "" : " ", prefixes[i], suffix);
1122 
1123 	return (r);
1124 }
1125 
1126 int
1127 format_bytes(buf, len, bytes)
1128 	char		*buf;
1129 	size_t		 len;
1130 	u_int64_t	 bytes;
1131 {
1132 	int	rv;
1133 	size_t	nlen;
1134 
1135 	rv = humanize_number(buf, len, bytes, "B", 1024);
1136 	if (rv != -1) {
1137 			/* nuke the trailing ` B' if it exists */
1138 		nlen = strlen(buf) - 2;
1139 		if (strcmp(&buf[nlen], " B") == 0)
1140 			buf[nlen] = '\0';
1141 	}
1142 	return (rv);
1143 }
1144