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