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