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