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