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