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