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