kern_subr.c revision 1.77 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