1 /* $NetBSD: kern_subr.c,v 1.27 1997/06/16 00:25:05 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. 5 * Copyright (c) 1982, 1986, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * (c) UNIX System Laboratories, Inc. 8 * All or some portions of this file are derived from material licensed 9 * to the University of California by American Telephone and Telegraph 10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 11 * the permission of UNIX System Laboratories, Inc. 12 * 13 * Copyright (c) 1992, 1993 14 * The Regents of the University of California. All rights reserved. 15 * 16 * This software was developed by the Computer Systems Engineering group 17 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 18 * contributed to Berkeley. 19 * 20 * All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Lawrence Berkeley Laboratory. 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 1. Redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer. 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution. 33 * 3. All advertising materials mentioning features or use of this software 34 * must display the following acknowledgement: 35 * This product includes software developed by the University of 36 * California, Berkeley and its contributors. 37 * 4. Neither the name of the University nor the names of its contributors 38 * may be used to endorse or promote products derived from this software 39 * without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * @(#)kern_subr.c 8.3 (Berkeley) 1/21/94 54 */ 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/proc.h> 59 #include <sys/malloc.h> 60 #include <sys/mount.h> 61 #include <sys/device.h> 62 #include <sys/reboot.h> 63 #include <sys/conf.h> 64 #include <sys/disklabel.h> 65 #include <sys/queue.h> 66 67 #include <dev/cons.h> 68 69 #include <net/if.h> 70 71 /* XXX these should eventually move to subr_autoconf.c */ 72 static int findblkmajor __P((const char *, struct devnametobdevmaj *)); 73 static const char *findblkname __P((int, struct devnametobdevmaj *)); 74 static struct device *getdisk __P((char *, int, int, 75 struct devnametobdevmaj *, dev_t *, int)); 76 static struct device *parsedisk __P((char *, int, int, 77 struct devnametobdevmaj *, dev_t *)); 78 static int getstr __P((char *, int)); 79 80 int 81 uiomove(buf, n, uio) 82 register void *buf; 83 register int n; 84 register struct uio *uio; 85 { 86 register struct iovec *iov; 87 u_int cnt; 88 int error = 0; 89 char *cp = buf; 90 91 #ifdef DIAGNOSTIC 92 if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) 93 panic("uiomove: mode"); 94 if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc) 95 panic("uiomove proc"); 96 #endif 97 while (n > 0 && uio->uio_resid) { 98 iov = uio->uio_iov; 99 cnt = iov->iov_len; 100 if (cnt == 0) { 101 uio->uio_iov++; 102 uio->uio_iovcnt--; 103 continue; 104 } 105 if (cnt > n) 106 cnt = n; 107 switch (uio->uio_segflg) { 108 109 case UIO_USERSPACE: 110 if (uio->uio_rw == UIO_READ) 111 error = copyout(cp, iov->iov_base, cnt); 112 else 113 error = copyin(iov->iov_base, cp, cnt); 114 if (error) 115 return (error); 116 break; 117 118 case UIO_SYSSPACE: 119 if (uio->uio_rw == UIO_READ) 120 bcopy(cp, iov->iov_base, cnt); 121 else 122 bcopy(iov->iov_base, cp, cnt); 123 break; 124 } 125 iov->iov_base += cnt; 126 iov->iov_len -= cnt; 127 uio->uio_resid -= cnt; 128 uio->uio_offset += cnt; 129 cp += cnt; 130 n -= cnt; 131 } 132 return (error); 133 } 134 135 /* 136 * Give next character to user as result of read. 137 */ 138 int 139 ureadc(c, uio) 140 register int c; 141 register struct uio *uio; 142 { 143 register struct iovec *iov; 144 145 if (uio->uio_resid <= 0) 146 panic("ureadc: non-positive resid"); 147 again: 148 if (uio->uio_iovcnt <= 0) 149 panic("ureadc: non-positive iovcnt"); 150 iov = uio->uio_iov; 151 if (iov->iov_len <= 0) { 152 uio->uio_iovcnt--; 153 uio->uio_iov++; 154 goto again; 155 } 156 switch (uio->uio_segflg) { 157 158 case UIO_USERSPACE: 159 if (subyte(iov->iov_base, c) < 0) 160 return (EFAULT); 161 break; 162 163 case UIO_SYSSPACE: 164 *iov->iov_base = c; 165 break; 166 } 167 iov->iov_base++; 168 iov->iov_len--; 169 uio->uio_resid--; 170 uio->uio_offset++; 171 return (0); 172 } 173 174 /* 175 * General routine to allocate a hash table. 176 */ 177 void * 178 hashinit(elements, type, hashmask) 179 int elements, type; 180 u_long *hashmask; 181 { 182 long hashsize; 183 LIST_HEAD(generic, generic) *hashtbl; 184 int i; 185 186 if (elements <= 0) 187 panic("hashinit: bad cnt"); 188 for (hashsize = 1; hashsize <= elements; hashsize <<= 1) 189 continue; 190 hashsize >>= 1; 191 hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type, M_WAITOK); 192 for (i = 0; i < hashsize; i++) 193 LIST_INIT(&hashtbl[i]); 194 *hashmask = hashsize - 1; 195 return (hashtbl); 196 } 197 198 /* 199 * "Shutdown hook" types, functions, and variables. 200 */ 201 202 struct shutdownhook_desc { 203 LIST_ENTRY(shutdownhook_desc) sfd_list; 204 void (*sfd_fn) __P((void *)); 205 void *sfd_arg; 206 }; 207 208 LIST_HEAD(, shutdownhook_desc) shutdownhook_list; 209 210 void * 211 shutdownhook_establish(fn, arg) 212 void (*fn) __P((void *)); 213 void *arg; 214 { 215 struct shutdownhook_desc *ndp; 216 217 ndp = (struct shutdownhook_desc *) 218 malloc(sizeof (*ndp), M_DEVBUF, M_NOWAIT); 219 if (ndp == NULL) 220 return NULL; 221 222 ndp->sfd_fn = fn; 223 ndp->sfd_arg = arg; 224 LIST_INSERT_HEAD(&shutdownhook_list, ndp, sfd_list); 225 226 return (ndp); 227 } 228 229 void 230 shutdownhook_disestablish(vhook) 231 void *vhook; 232 { 233 #ifdef DIAGNOSTIC 234 struct shutdownhook_desc *dp; 235 236 for (dp = shutdownhook_list.lh_first; dp != NULL; 237 dp = dp->sfd_list.le_next) 238 if (dp == vhook) 239 break; 240 if (dp == NULL) 241 panic("shutdownhook_disestablish: hook not established"); 242 #endif 243 244 LIST_REMOVE((struct shutdownhook_desc *)vhook, sfd_list); 245 free(vhook, M_DEVBUF); 246 } 247 248 /* 249 * Run shutdown hooks. Should be invoked immediately before the 250 * system is halted or rebooted, i.e. after file systems unmounted, 251 * after crash dump done, etc. 252 * 253 * Each shutdown hook is removed from the list before it's run, so that 254 * it won't be run again. 255 */ 256 void 257 doshutdownhooks() 258 { 259 struct shutdownhook_desc *dp; 260 261 while ((dp = shutdownhook_list.lh_first) != NULL) { 262 LIST_REMOVE(dp, sfd_list); 263 (*dp->sfd_fn)(dp->sfd_arg); 264 #if 0 265 /* 266 * Don't bother freeing the hook structure,, since we may 267 * be rebooting because of a memory corruption problem, 268 * and this might only make things worse. It doesn't 269 * matter, anyway, since the system is just about to 270 * reboot. 271 */ 272 free(dp, M_DEVBUF); 273 #endif 274 } 275 } 276 277 /* 278 * "Mountroot hook" types, functions, and variables. 279 */ 280 281 struct mountroothook_desc { 282 LIST_ENTRY(mountroothook_desc) mrd_list; 283 struct device *mrd_device; 284 void (*mrd_func) __P((struct device *)); 285 }; 286 287 LIST_HEAD(, mountroothook_desc) mountroothook_list; 288 289 void * 290 mountroothook_establish(func, dev) 291 void (*func) __P((struct device *)); 292 struct device *dev; 293 { 294 struct mountroothook_desc *mrd; 295 296 mrd = (struct mountroothook_desc *) 297 malloc(sizeof(*mrd), M_DEVBUF, M_NOWAIT); 298 if (mrd == NULL) 299 return (NULL); 300 301 mrd->mrd_device = dev; 302 mrd->mrd_func = func; 303 LIST_INSERT_HEAD(&mountroothook_list, mrd, mrd_list); 304 305 return (mrd); 306 } 307 308 void 309 mountroothook_disestablish(vhook) 310 void *vhook; 311 { 312 #ifdef DIAGNOSTIC 313 struct mountroothook_desc *mrd; 314 315 for (mrd = mountroothook_list.lh_first; mrd != NULL; 316 mrd = mrd->mrd_list.le_next) 317 if (mrd == vhook) 318 break; 319 if (mrd == NULL) 320 panic("mountroothook_disestablish: hook not established"); 321 #endif 322 323 LIST_REMOVE((struct mountroothook_desc *)vhook, mrd_list); 324 free(vhook, M_DEVBUF); 325 } 326 327 void 328 mountroothook_destroy() 329 { 330 struct mountroothook_desc *mrd; 331 332 while ((mrd = mountroothook_list.lh_first) != NULL) { 333 LIST_REMOVE(mrd, mrd_list); 334 free(mrd, M_DEVBUF); 335 } 336 } 337 338 void 339 domountroothook() 340 { 341 struct mountroothook_desc *mrd; 342 343 for (mrd = mountroothook_list.lh_first; mrd != NULL; 344 mrd = mrd->mrd_list.le_next) { 345 if (mrd->mrd_device == root_device) { 346 (*mrd->mrd_func)(root_device); 347 return; 348 } 349 } 350 } 351 352 /* 353 * Determine the root device and, if instructed to, the root file system. 354 */ 355 356 #include "md.h" 357 #if NMD == 0 358 #undef MEMORY_DISK_HOOKS 359 #endif 360 361 #ifdef MEMORY_DISK_HOOKS 362 static struct device fakemdrootdev = { DV_DISK, {}, NULL, 0, "md0", NULL }; 363 #endif 364 365 void 366 setroot(bootdv, bootpartition, nam2blk) 367 struct device *bootdv; 368 int bootpartition; 369 struct devnametobdevmaj *nam2blk; 370 { 371 struct device *dv; 372 register int len, i; 373 dev_t nrootdev; 374 dev_t ndumpdev = NODEV; 375 char buf[128]; 376 const char *rootdevname; 377 const char *dumpdevname; 378 struct device *rootdv = NULL; /* XXX gcc -Wuninitialized */ 379 struct device *dumpdv = NULL; 380 struct ifnet *ifp; 381 const char *deffsname; 382 struct vfsops *vops; 383 extern int (*mountroot) __P((void)); 384 static struct devnametobdevmaj *last_nam2blk; 385 386 if (nam2blk == NULL) { 387 if (last_nam2blk == NULL) 388 panic("setroot: no name to bdev major map"); 389 nam2blk = last_nam2blk; 390 } 391 last_nam2blk = nam2blk; 392 393 #ifdef MEMORY_DISK_IS_ROOT 394 bootdv = &fakemdrootdev; 395 bootpartition = 0; 396 #endif 397 398 /* 399 * If NFS is specified as the file system, and we found 400 * a DV_DISK boot device (or no boot device at all), then 401 * find a reasonable network interface for "rootspec". 402 */ 403 vops = vfs_getopsbyname("nfs"); 404 if (vops != NULL && vops->vfs_mountroot == mountroot && 405 rootspec == NULL && 406 (bootdv == NULL || bootdv->dv_class != DV_IFNET)) { 407 for (ifp = ifnet.tqh_first; ifp != NULL; 408 ifp = ifp->if_list.tqe_next) 409 if ((ifp->if_flags & 410 (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) 411 break; 412 if (ifp == NULL) { 413 /* 414 * Can't find a suitable interface; ask the 415 * user. 416 */ 417 boothowto |= RB_ASKNAME; 418 } else { 419 /* 420 * Have a suitable interface; behave as if 421 * the user specified this interface. 422 */ 423 rootspec = (const char *)ifp->if_xname; 424 } 425 } 426 427 /* 428 * If wildcarded root and we the boot device wasn't determined, 429 * ask the user. 430 */ 431 if (rootspec == NULL && bootdv == NULL) 432 boothowto |= RB_ASKNAME; 433 434 top: 435 if (boothowto & RB_ASKNAME) { 436 struct device *defdumpdv; 437 438 for (;;) { 439 printf("root device"); 440 if (bootdv != NULL) { 441 printf(" (default %s", bootdv->dv_xname); 442 if (bootdv->dv_class == DV_DISK) 443 printf("%c", bootpartition + 'a'); 444 printf(")"); 445 } 446 printf(": "); 447 len = getstr(buf, sizeof(buf)); 448 if (len == 0 && bootdv != NULL) { 449 strcpy(buf, bootdv->dv_xname); 450 len = strlen(buf); 451 } 452 if (len > 0 && buf[len - 1] == '*') { 453 buf[--len] = '\0'; 454 dv = getdisk(buf, len, 1, nam2blk, 455 &nrootdev, 0); 456 if (dv != NULL) { 457 rootdv = dv; 458 break; 459 } 460 } 461 dv = getdisk(buf, len, bootpartition, nam2blk, 462 &nrootdev, 0); 463 if (dv != NULL) { 464 rootdv = dv; 465 break; 466 } 467 } 468 469 /* 470 * Set up the default dump device. If root is on 471 * a network device, there is no default dump 472 * device, since we don't support dumps to the 473 * network. 474 */ 475 if (rootdv->dv_class == DV_IFNET) 476 defdumpdv = NULL; 477 else 478 defdumpdv = rootdv; 479 480 for (;;) { 481 printf("dump device"); 482 if (defdumpdv != NULL) { 483 /* 484 * Note, we know it's a disk if we get here. 485 */ 486 printf(" (default %sb)", defdumpdv->dv_xname); 487 } 488 printf(": "); 489 len = getstr(buf, sizeof(buf)); 490 if (len == 0) { 491 if (defdumpdv != NULL) { 492 ndumpdev = MAKEDISKDEV(major(nrootdev), 493 DISKUNIT(nrootdev), 1); 494 } 495 if (rootdv->dv_class == DV_IFNET) 496 dumpdv = NULL; 497 else 498 dumpdv = rootdv; 499 break; 500 } 501 if (len == 4 && strcmp(buf, "none") == 0) { 502 dumpspec = "none"; 503 goto havedump; 504 } 505 dv = getdisk(buf, len, 1, nam2blk, &ndumpdev, 1); 506 if (dv) { 507 dumpdv = dv; 508 break; 509 } 510 } 511 512 havedump: 513 rootdev = nrootdev; 514 dumpdev = ndumpdev; 515 516 for (i = 0; i < nvfssw; i++) { 517 if (vfssw[i] != NULL && 518 vfssw[i]->vfs_mountroot != NULL && 519 vfssw[i]->vfs_mountroot == mountroot) 520 break; 521 } 522 if (i >= nvfssw) { 523 mountroot = NULL; 524 deffsname = "generic"; 525 } else 526 deffsname = vfssw[i]->vfs_name; 527 for (;;) { 528 printf("file system (default %s): ", deffsname); 529 len = getstr(buf, sizeof(buf)); 530 if (len == 0) 531 break; 532 if (len == 4 && strcmp(buf, "halt") == 0) 533 cpu_reboot(RB_HALT, NULL); 534 else if (len == 7 && strcmp(buf, "generic") == 0) { 535 mountroot = NULL; 536 break; 537 } 538 vops = vfs_getopsbyname(buf); 539 if (vops == NULL || vops->vfs_mountroot == NULL) { 540 printf("use one of: generic"); 541 for (i = 0; i < nvfssw; i++) 542 if (vfssw[i] != NULL && 543 vfssw[i]->vfs_mountroot != NULL) 544 printf(" %s", 545 vfssw[i]->vfs_name); 546 printf(" halt\n"); 547 } else { 548 mountroot = vops->vfs_mountroot; 549 break; 550 } 551 } 552 553 } else if (rootspec == NULL) { 554 int majdev; 555 556 /* 557 * Wildcarded root; use the boot device. 558 */ 559 rootdv = bootdv; 560 561 majdev = findblkmajor(bootdv->dv_xname, nam2blk); 562 if (majdev >= 0) { 563 /* 564 * Root is on a disk. `bootpartition' is root. 565 */ 566 rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit, 567 bootpartition); 568 } 569 } else { 570 571 /* 572 * `root on <dev> ...' 573 */ 574 575 /* 576 * If it's a network interface, we can bail out 577 * early. 578 */ 579 for (dv = alldevs.tqh_first; dv != NULL; 580 dv = dv->dv_list.tqe_next) 581 if (strcmp(dv->dv_xname, rootspec) == 0) 582 break; 583 if (dv != NULL && dv->dv_class == DV_IFNET) { 584 rootdv = dv; 585 goto haveroot; 586 } 587 588 rootdevname = findblkname(major(rootdev), nam2blk); 589 if (rootdevname == NULL) { 590 printf("unknown device major 0x%x\n", rootdev); 591 boothowto |= RB_ASKNAME; 592 goto top; 593 } 594 bzero(buf, sizeof(buf)); 595 sprintf(buf, "%s%d", rootdevname, DISKUNIT(rootdev)); 596 597 for (dv = alldevs.tqh_first; dv != NULL; 598 dv = dv->dv_list.tqe_next) { 599 if (strcmp(buf, dv->dv_xname) == 0) { 600 rootdv = dv; 601 break; 602 } 603 } 604 if (rootdv == NULL) { 605 printf("device %s (0x%x) not configured\n", 606 buf, rootdev); 607 boothowto |= RB_ASKNAME; 608 goto top; 609 } 610 } 611 612 haveroot: 613 614 root_device = rootdv; 615 616 switch (rootdv->dv_class) { 617 case DV_IFNET: 618 /* Nothing. */ 619 break; 620 621 case DV_DISK: 622 printf("root on %s%c", rootdv->dv_xname, 623 DISKPART(rootdev) + 'a'); 624 break; 625 626 default: 627 printf("can't determine root device\n"); 628 boothowto |= RB_ASKNAME; 629 goto top; 630 } 631 632 /* 633 * Now configure the dump device. 634 */ 635 636 if (dumpspec != NULL && strcmp(dumpspec, "none") == 0) { 637 /* 638 * Operator doesn't want a dump device. 639 */ 640 goto nodumpdev; 641 } 642 643 /* 644 * If we haven't figured out the dump device, do so, with 645 * the following rules: 646 * 647 * (a) We already know dumpdv in the RB_ASKNAME case. 648 * 649 * (b) If dumpspec is set, try to use it. If the device 650 * is not available, punt. 651 * 652 * (c) If dumpspec is not set, the dump device is 653 * wildcarded or unspecified. If the root device 654 * is DV_IFNET, punt. Otherwise, use partition b 655 * of the root device. 656 */ 657 658 if (boothowto & RB_ASKNAME) { 659 if (dumpdv == NULL) { 660 /* 661 * Just return; dumpdev is already set to NODEV 662 * and we don't want to print a newline in this 663 * case. 664 */ 665 return; 666 } 667 goto out; 668 } 669 670 if (dumpspec != NULL) { 671 if (dumpdev == NODEV) { 672 /* 673 * Looks like they tried to pick a network 674 * device. Oops. 675 */ 676 goto nodumpdev; 677 } 678 679 dumpdevname = findblkname(major(dumpdev), nam2blk); 680 if (dumpdevname == NULL) 681 goto nodumpdev; 682 bzero(buf, sizeof(buf)); 683 sprintf(buf, "%s%d", dumpdevname, DISKUNIT(dumpdev)); 684 685 for (dv = alldevs.tqh_first; dv != NULL; 686 dv = dv->dv_list.tqe_next) { 687 if (strcmp(buf, dv->dv_xname) == 0) { 688 dumpdv = dv; 689 break; 690 } 691 } 692 if (dv == NULL) { 693 /* 694 * Device not configured. 695 */ 696 goto nodumpdev; 697 } 698 } else if (rootdv->dv_class == DV_IFNET) 699 goto nodumpdev; 700 else { 701 dumpdv = rootdv; 702 dumpdev = MAKEDISKDEV(major(rootdev), dumpdv->dv_unit, 1); 703 } 704 705 out: 706 printf(" dumps on %s%c\n", dumpdv->dv_xname, DISKPART(dumpdev) + 'a'); 707 return; 708 709 nodumpdev: 710 dumpdev = NODEV; 711 printf("\n"); 712 } 713 714 static int 715 findblkmajor(name, nam2blk) 716 const char *name; 717 struct devnametobdevmaj *nam2blk; 718 { 719 int i; 720 721 if (nam2blk == NULL) 722 return (-1); 723 724 for (i = 0; nam2blk[i].d_name != NULL; i++) 725 if (strncmp(name, nam2blk[i].d_name, 726 strlen(nam2blk[i].d_name)) == 0) 727 return (nam2blk[i].d_maj); 728 return (-1); 729 } 730 731 const char * 732 findblkname(maj, nam2blk) 733 int maj; 734 struct devnametobdevmaj *nam2blk; 735 { 736 int i; 737 738 if (nam2blk == NULL) 739 return (NULL); 740 741 for (i = 0; nam2blk[i].d_name != NULL; i++) 742 if (nam2blk[i].d_maj == maj) 743 return (nam2blk[i].d_name); 744 return (NULL); 745 } 746 747 static struct device * 748 getdisk(str, len, defpart, nam2blk, devp, isdump) 749 char *str; 750 int len, defpart; 751 struct devnametobdevmaj *nam2blk; 752 dev_t *devp; 753 int isdump; 754 { 755 struct device *dv; 756 757 if ((dv = parsedisk(str, len, defpart, nam2blk, devp)) == NULL) { 758 printf("use one of:"); 759 #ifdef MEMORY_DISK_HOOKS 760 if (isdump == 0) 761 printf(" %s[a-%c]", fakemdrootdev.dv_xname, 762 'a' + MAXPARTITIONS - 1); 763 #endif 764 for (dv = alldevs.tqh_first; dv != NULL; 765 dv = dv->dv_list.tqe_next) { 766 if (dv->dv_class == DV_DISK) 767 printf(" %s[a-%c]", dv->dv_xname, 768 'a' + MAXPARTITIONS - 1); 769 if (isdump == 0 && dv->dv_class == DV_IFNET) 770 printf(" %s", dv->dv_xname); 771 } 772 if (isdump) 773 printf(" none"); 774 printf(" halt\n"); 775 } 776 return (dv); 777 } 778 779 static struct device * 780 parsedisk(str, len, defpart, nam2blk, devp) 781 char *str; 782 int len, defpart; 783 struct devnametobdevmaj *nam2blk; 784 dev_t *devp; 785 { 786 struct device *dv; 787 char *cp, c; 788 int majdev, part; 789 790 if (len == 0) 791 return (NULL); 792 793 if (len == 4 && strcmp(str, "halt") == 0) 794 cpu_reboot(RB_HALT, NULL); 795 796 cp = str + len - 1; 797 c = *cp; 798 if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) { 799 part = c - 'a'; 800 *cp = '\0'; 801 } else 802 part = defpart; 803 804 #ifdef MEMORY_DISK_HOOKS 805 if (strcmp(str, fakemdrootdev.dv_xname) == 0) { 806 dv = &fakemdrootdev; 807 goto gotdisk; 808 } 809 #endif 810 811 for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) { 812 if (dv->dv_class == DV_DISK && 813 strcmp(str, dv->dv_xname) == 0) { 814 #ifdef MEMORY_DISK_HOOKS 815 gotdisk: 816 #endif 817 majdev = findblkmajor(dv->dv_xname, nam2blk); 818 if (majdev < 0) 819 panic("parsedisk"); 820 *devp = MAKEDISKDEV(majdev, dv->dv_unit, part); 821 break; 822 } 823 824 if (dv->dv_class == DV_IFNET && 825 strcmp(str, dv->dv_xname) == 0) { 826 *devp = NODEV; 827 break; 828 } 829 } 830 831 *cp = c; 832 return (dv); 833 } 834 835 /* 836 * XXX shouldn't this be a common function? 837 */ 838 static int 839 getstr(cp, size) 840 char *cp; 841 int size; 842 { 843 char *lp; 844 int c, len; 845 846 cnpollc(1); 847 848 lp = cp; 849 len = 0; 850 for (;;) { 851 c = cngetc(); 852 switch (c) { 853 case '\n': 854 case '\r': 855 printf("\n"); 856 *lp++ = '\0'; 857 cnpollc(0); 858 return (len); 859 case '\b': 860 case '\177': 861 case '#': 862 if (len) { 863 --len; 864 --lp; 865 printf("\b \b"); 866 } 867 continue; 868 case '@': 869 case 'u'&037: 870 len = 0; 871 lp = cp; 872 printf("\n"); 873 continue; 874 default: 875 if (len + 1 >= size || c < ' ') { 876 printf("\007"); 877 continue; 878 } 879 printf("%c", c); 880 ++len; 881 *lp++ = c; 882 } 883 } 884 } 885