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