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