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