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