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