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