The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_subr.c,v 1.231 2023/01/19 07:40:58 mlelstv Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center, and by Luke Mewburn.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Copyright (c) 1982, 1986, 1991, 1993
   35  *      The Regents of the University of California.  All rights reserved.
   36  * (c) UNIX System Laboratories, Inc.
   37  * All or some portions of this file are derived from material licensed
   38  * to the University of California by American Telephone and Telegraph
   39  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   40  * the permission of UNIX System Laboratories, Inc.
   41  *
   42  * Copyright (c) 1992, 1993
   43  *      The Regents of the University of California.  All rights reserved.
   44  *
   45  * This software was developed by the Computer Systems Engineering group
   46  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
   47  * contributed to Berkeley.
   48  *
   49  * All advertising materials mentioning features or use of this software
   50  * must display the following acknowledgement:
   51  *      This product includes software developed by the University of
   52  *      California, Lawrence Berkeley Laboratory.
   53  *
   54  * Redistribution and use in source and binary forms, with or without
   55  * modification, are permitted provided that the following conditions
   56  * are met:
   57  * 1. Redistributions of source code must retain the above copyright
   58  *    notice, this list of conditions and the following disclaimer.
   59  * 2. Redistributions in binary form must reproduce the above copyright
   60  *    notice, this list of conditions and the following disclaimer in the
   61  *    documentation and/or other materials provided with the distribution.
   62  * 3. Neither the name of the University nor the names of its contributors
   63  *    may be used to endorse or promote products derived from this software
   64  *    without specific prior written permission.
   65  *
   66  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   67  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   68  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   69  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   70  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   71  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   72  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   73  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   74  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   75  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   76  * SUCH DAMAGE.
   77  *
   78  *      @(#)kern_subr.c 8.4 (Berkeley) 2/14/95
   79  */
   80 
   81 #include <sys/cdefs.h>
   82 __KERNEL_RCSID(0, "$NetBSD: kern_subr.c,v 1.231 2023/01/19 07:40:58 mlelstv Exp $");
   83 
   84 #include "opt_ddb.h"
   85 #include "opt_md.h"
   86 #include "opt_tftproot.h"
   87 
   88 #include <sys/param.h>
   89 #include <sys/systm.h>
   90 #include <sys/proc.h>
   91 #include <sys/mount.h>
   92 #include <sys/device.h>
   93 #include <sys/reboot.h>
   94 #include <sys/conf.h>
   95 #include <sys/disk.h>
   96 #include <sys/disklabel.h>
   97 #include <sys/queue.h>
   98 #include <sys/fcntl.h>
   99 #include <sys/kauth.h>
  100 #include <sys/stat.h>
  101 #include <sys/vnode.h>
  102 #include <sys/module.h>
  103 
  104 #include <dev/cons.h>
  105 
  106 #include <net/if.h>
  107 
  108 /* XXX these should eventually move to subr_autoconf.c */
  109 static device_t finddevice(const char *);
  110 static device_t getdisk(const char *, int, int, dev_t *, int);
  111 static device_t parsedisk(const char *, int, int, dev_t *);
  112 static const char *getwedgename(const char *, int);
  113 
  114 static void setroot_nfs(device_t);
  115 static void setroot_md(device_t *);
  116 static void setroot_ask(device_t, int);
  117 static void setroot_root(device_t, int);
  118 static void setroot_dump(device_t, device_t);
  119 
  120 
  121 #ifdef TFTPROOT
  122 int tftproot_dhcpboot(device_t);
  123 #endif
  124 
  125 dev_t   dumpcdev;       /* for savecore */
  126 
  127 static int
  128 isswap(device_t dv)
  129 {
  130         struct dkwedge_info wi;
  131         struct vnode *vn;
  132         int error;
  133 
  134         if (device_class(dv) != DV_DISK || !device_is_a(dv, "dk"))
  135                 return 0;
  136 
  137         if ((vn = opendisk(dv)) == NULL)
  138                 return 0;
  139 
  140         VOP_UNLOCK(vn);
  141         error = VOP_IOCTL(vn, DIOCGWEDGEINFO, &wi, FREAD, NOCRED);
  142         vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);
  143         VOP_CLOSE(vn, FREAD, NOCRED);
  144         vput(vn);
  145         if (error) {
  146 #ifdef DEBUG_WEDGE
  147                 printf("%s: Get wedge info returned %d\n", device_xname(dv), error);
  148 #endif
  149                 return 0;
  150         }
  151         return strcmp(wi.dkw_ptype, DKW_PTYPE_SWAP) == 0;
  152 }
  153 
  154 /*
  155  * Determine the root device and, if instructed to, the root file system.
  156  */
  157 
  158 #ifdef MEMORY_DISK_IS_ROOT
  159 int md_is_root = 1;
  160 #else
  161 int md_is_root = 0;
  162 #endif
  163 
  164 /*
  165  * The device and partition that we booted from.
  166  *
  167  * This data might be initialized by MD code, but is defined here.
  168  */
  169 device_t booted_device;
  170 const char *booted_method;
  171 int booted_partition;
  172 daddr_t booted_startblk;
  173 uint64_t booted_nblks;
  174 char *bootspec;
  175 
  176 /*
  177  * Time to wait for a specified boot device to appear.
  178  */
  179 #ifndef ROOT_WAITTIME
  180 #define ROOT_WAITTIME 20
  181 #endif
  182 
  183 /*
  184  * Use partition letters if it's a disk class but not a wedge or flash.
  185  * XXX Check for wedge/flash is kinda gross.
  186  */
  187 #define DEV_USES_PARTITIONS(dv)                                         \
  188         (device_class((dv)) == DV_DISK &&                               \
  189          !device_is_a((dv), "dk") &&                                    \
  190          !device_is_a((dv), "flash"))
  191 
  192 void
  193 setroot(device_t bootdv, int bootpartition)
  194 {
  195         time_t waitend;
  196 
  197         /*
  198          * Let bootcode augment "rootspec", ensure that
  199          * rootdev is invalid to avoid confusion.
  200          */
  201         if (rootspec == NULL) {
  202                 rootspec = bootspec;
  203                 rootdev = NODEV;
  204         }
  205 
  206         /*
  207          * force boot device to md0
  208          */
  209         if (md_is_root)
  210                 setroot_md(&bootdv);
  211 
  212 #ifdef TFTPROOT
  213         /*
  214          * XXX
  215          * if rootspec specifies an interface
  216          * sets root_device to that interface
  217          * reuses NFS init code to set up network
  218          * fetch image into ram disk
  219          *
  220          * if successful, we change boot device
  221          */
  222         if (tftproot_dhcpboot(bootdv) == 0)
  223                 setroot_md(&bootdv);
  224 #endif
  225         
  226         /*
  227          * quirk for
  228          *  evbarm/mini2440
  229          *  hpcarm
  230          *  hpcmips
  231          *  hpcsh
  232          *
  233          * if rootfstype is set to NFS and the
  234          * kernel supports NFS and the boot device
  235          * is unknown or not a network interface
  236          * -> chose the first network interface you find
  237          *
  238          * hp300 has similar MD code
  239          */
  240         setroot_nfs(bootdv);
  241 
  242         /*
  243          * If no bootdv was found by MD code and no
  244          * root specified ask the user.
  245          */
  246         if (rootspec == NULL && bootdv == NULL)
  247                 boothowto |= RB_ASKNAME;
  248 
  249         /*
  250          * loop until a root device is specified
  251          */
  252         waitend = time_uptime + ROOT_WAITTIME;
  253         do {
  254                 if (boothowto & RB_ASKNAME)
  255                         setroot_ask(bootdv, bootpartition);
  256                 else {
  257                         setroot_root(bootdv, bootpartition);
  258                         if (root_device == NULL) {
  259                                 if (time_uptime < waitend) {
  260                                         kpause("root", false, hz, NULL);
  261                                 } else
  262                                         boothowto |= RB_ASKNAME;
  263                         }
  264                 }
  265         } while (root_device == NULL);
  266 }
  267 
  268 /*
  269  * If NFS is specified as the file system, and we found
  270  * a DV_DISK boot device (or no boot device at all), then
  271  * find a reasonable network interface for "rootspec".
  272  */
  273 static void
  274 setroot_nfs(device_t dv)
  275 {
  276         struct vfsops *vops;
  277         struct ifnet *ifp;
  278 
  279         vops = vfs_getopsbyname(MOUNT_NFS);
  280         if (vops != NULL && strcmp(rootfstype, MOUNT_NFS) == 0 &&
  281             rootspec == NULL &&
  282             (dv == NULL || device_class(dv) != DV_IFNET)) {
  283                 int s = pserialize_read_enter();
  284                 IFNET_READER_FOREACH(ifp) {
  285                         if ((ifp->if_flags &
  286                              (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
  287                                 break;
  288                 }
  289                 if (ifp != NULL) {
  290                         /*
  291                          * Have a suitable interface; behave as if
  292                          * the user specified this interface.
  293                          */
  294                         rootspec = (const char *)ifp->if_xname;
  295                 }
  296                 pserialize_read_exit(s);
  297         }
  298         if (vops != NULL)
  299                 vfs_delref(vops);
  300 }
  301 
  302 /*
  303  * Change boot device to md0
  304  *
  305  * md0 only exists when it is opened once.
  306  */
  307 static void
  308 setroot_md(device_t *dvp)
  309 {
  310         int md_major;
  311         dev_t md_dev;
  312 
  313         md_major = devsw_name2blk("md", NULL, 0);
  314         if (md_major >= 0) {
  315                 md_dev = MAKEDISKDEV(md_major, 0, RAW_PART);
  316                 if (bdev_open(md_dev, FREAD, S_IFBLK, curlwp) == 0)
  317                         *dvp = device_find_by_xname("md0");
  318         }
  319 }
  320 
  321 static void
  322 setroot_ask(device_t bootdv, int bootpartition)
  323 {
  324         device_t dv, defdumpdv, rootdv, dumpdv;
  325         dev_t nrootdev, ndumpdev;
  326         struct vfsops *vops;
  327         const char *deffsname;
  328         int len;
  329         char buf[128];
  330 
  331         for (;;) {
  332                 printf("root device");
  333                 if (bootdv != NULL) {
  334                         printf(" (default %s", device_xname(bootdv));
  335                         if (DEV_USES_PARTITIONS(bootdv))
  336                                 printf("%c", bootpartition + 'a');
  337                         printf(")");
  338                 }
  339                 printf(": ");
  340                 len = cngetsn(buf, sizeof(buf));
  341                 if (len == 0 && bootdv != NULL) {
  342                         strlcpy(buf, device_xname(bootdv), sizeof(buf));
  343                         len = strlen(buf);
  344                 }
  345                 if (len > 0 && buf[len - 1] == '*') {
  346                         buf[--len] = '\0';
  347                         dv = getdisk(buf, len, 1, &nrootdev, 0);
  348                         if (dv != NULL) {
  349                                 rootdv = dv;
  350                                 break;
  351                         }
  352                 }
  353                 dv = getdisk(buf, len, bootpartition, &nrootdev, 0);
  354                 if (dv != NULL) {
  355                         rootdv = dv;
  356                         break;
  357                 }
  358         }
  359         rootdev = nrootdev;
  360 
  361         /*
  362          * Set up the default dump device.  If root is on
  363          * a network device or a disk without partitions,
  364          * there is no default dump device.
  365          */
  366         if (DEV_USES_PARTITIONS(rootdv) == 0)
  367                 defdumpdv = NULL;
  368         else
  369                 defdumpdv = rootdv;
  370 
  371         ndumpdev = NODEV;
  372         for (;;) {
  373                 printf("dump device");
  374                 if (defdumpdv != NULL) {
  375                         /*
  376                          * Note, we know it's a disk if we get here.
  377                          */
  378                         printf(" (default %sb)", device_xname(defdumpdv));
  379                 }
  380                 printf(": ");
  381                 len = cngetsn(buf, sizeof(buf));
  382                 if (len == 0) {
  383                         if (defdumpdv != NULL) {
  384                                 ndumpdev = MAKEDISKDEV(major(nrootdev),
  385                                     DISKUNIT(nrootdev), 1);
  386                         }
  387                         dumpdv = defdumpdv;
  388                         break;
  389                 }
  390                 if (len == 4 && strcmp(buf, "none") == 0) {
  391                         dumpdv = NULL;
  392                         break;
  393                 }
  394                 dv = getdisk(buf, len, 1, &ndumpdev, 1);
  395                 if (dv != NULL) {
  396                         dumpdv = dv;
  397                         break;
  398                 }
  399         }
  400         dumpdev = ndumpdev;
  401 
  402         for (vops = LIST_FIRST(&vfs_list); vops != NULL;
  403              vops = LIST_NEXT(vops, vfs_list)) {
  404                 if (vops->vfs_mountroot != NULL &&
  405                     strcmp(rootfstype, vops->vfs_name) == 0)
  406                 break;
  407         }
  408 
  409         if (vops == NULL) {
  410                 deffsname = "generic";
  411         } else
  412                 deffsname = vops->vfs_name;
  413 
  414         for (;;) {
  415                 printf("file system (default %s): ", deffsname);
  416                 len = cngetsn(buf, sizeof(buf));
  417                 if (len == 0) {
  418                         if (strcmp(deffsname, "generic") == 0)
  419                                 rootfstype = ROOT_FSTYPE_ANY;
  420                         break;
  421                 }
  422                 if (len == 4 && strcmp(buf, "halt") == 0)
  423                         kern_reboot(RB_HALT, NULL);
  424                 else if (len == 6 && strcmp(buf, "reboot") == 0)
  425                         kern_reboot(0, NULL);
  426 #if defined(DDB)
  427                 else if (len == 3 && strcmp(buf, "ddb") == 0) {
  428                         console_debugger();
  429                 }
  430 #endif
  431                 else if (len == 7 && strcmp(buf, "generic") == 0) {
  432                         rootfstype = ROOT_FSTYPE_ANY;
  433                         break;
  434                 }
  435                 vops = vfs_getopsbyname(buf);
  436                 if (vops == NULL || vops->vfs_mountroot == NULL) {
  437                         printf("use one of: generic");
  438                         for (vops = LIST_FIRST(&vfs_list);
  439                              vops != NULL;
  440                              vops = LIST_NEXT(vops, vfs_list)) {
  441                                 if (vops->vfs_mountroot != NULL)
  442                                         printf(" %s", vops->vfs_name);
  443                         }
  444                         if (vops != NULL)
  445                                 vfs_delref(vops);
  446 #if defined(DDB)
  447                         printf(" ddb");
  448 #endif
  449                         printf(" halt reboot\n");
  450                 } else {
  451                         /*
  452                          * XXX If *vops gets freed between here and
  453                          * the call to mountroot(), rootfstype will
  454                          * point to something unexpected.  But in
  455                          * this case the system will fail anyway.
  456                          */
  457                         rootfstype = vops->vfs_name;
  458                         vfs_delref(vops);
  459                         break;
  460                 }
  461         }
  462 
  463         switch (device_class(rootdv)) {
  464         case DV_IFNET:
  465         case DV_DISK:
  466                 aprint_normal("root on %s", device_xname(rootdv));
  467                 if (DEV_USES_PARTITIONS(rootdv))
  468                         aprint_normal("%c", (int)DISKPART(rootdev) + 'a');
  469                 break;
  470         default:
  471                 printf("can't determine root device\n");
  472                 return;
  473         }
  474 
  475         root_device = rootdv;
  476         setroot_dump(rootdv, dumpdv);
  477 }
  478 
  479 /*
  480  * configure
  481  *   device_t root_device
  482  *   dev_t rootdev (for disks)
  483  * 
  484  */
  485 static void
  486 setroot_root(device_t bootdv, int bootpartition)
  487 {
  488         device_t rootdv;
  489         int majdev;
  490         const char *rootdevname;
  491         char buf[128];
  492         dev_t nrootdev;
  493 
  494         if (rootspec == NULL) {
  495 
  496                 /*
  497                  * Wildcarded root; use the boot device.
  498                  */
  499                 rootdv = bootdv;
  500 
  501                 if (bootdv)
  502                         majdev = devsw_name2blk(device_xname(bootdv), NULL, 0);
  503                 else
  504                         majdev = -1;
  505                 if (majdev >= 0) {
  506                         /*
  507                          * Root is on a disk.  `bootpartition' is root,
  508                          * unless the device does not use partitions.
  509                          */
  510                         if (DEV_USES_PARTITIONS(bootdv))
  511                                 rootdev = MAKEDISKDEV(majdev,
  512                                                       device_unit(bootdv),
  513                                                       bootpartition);
  514                         else
  515                                 rootdev = makedev(majdev, device_unit(bootdv));
  516                 }
  517         } else {
  518 
  519                 /*
  520                  * `root on <dev> ...'
  521                  */
  522 
  523                 /*
  524                  * If rootspec can be parsed, just use it.
  525                  */
  526                 rootdv = parsedisk(rootspec, strlen(rootspec), 0, &nrootdev);
  527                 if (rootdv != NULL) {
  528                         rootdev = nrootdev;
  529                         goto haveroot;
  530                 }
  531 
  532                 /*
  533                  * Fall back to rootdev, compute rootdv for it
  534                  */
  535                 rootdevname = devsw_blk2name(major(rootdev));
  536                 if (rootdevname == NULL) {
  537                         printf("unknown device major 0x%llx\n",
  538                             (unsigned long long)rootdev);
  539                         return;
  540                 }
  541                 memset(buf, 0, sizeof(buf));
  542                 snprintf(buf, sizeof(buf), "%s%llu", rootdevname,
  543                     (unsigned long long)DISKUNIT(rootdev));
  544 
  545                 rootdv = finddevice(buf);
  546                 if (rootdv == NULL) {
  547                         printf("device %s (0x%llx) not configured\n",
  548                             buf, (unsigned long long)rootdev);
  549                         return;
  550                 }
  551         }
  552 
  553 haveroot:
  554         switch (device_class(rootdv)) {
  555         case DV_IFNET:
  556         case DV_DISK:
  557                 aprint_normal("root on %s", device_xname(rootdv));
  558                 if (DEV_USES_PARTITIONS(rootdv))
  559                         aprint_normal("%c", (int)DISKPART(rootdev) + 'a');
  560                 break;
  561         default:
  562                 printf("can't determine root device\n");
  563                 return;
  564         }
  565 
  566         root_device = rootdv;
  567         setroot_dump(rootdv, NULL);
  568 }
  569 
  570 /*
  571  * configure
  572  *   dev_t dumpdev
  573  *   dev_t dumpcdev
  574  *
  575  * set to NODEV if device not found
  576  */
  577 static void
  578 setroot_dump(device_t rootdv, device_t dumpdv)
  579 {
  580         device_t dv;
  581         deviter_t di;
  582         const char *dumpdevname;
  583         int majdev;
  584         char buf[128];
  585 
  586         /*
  587          * Now configure the dump device.
  588          *
  589          * If we haven't figured out the dump device, do so, with
  590          * the following rules:
  591          *
  592          *      (a) We already know dumpdv in the RB_ASKNAME case.
  593          *
  594          *      (b) If dumpspec is set, try to use it.  If the device
  595          *          is not available, punt.
  596          *
  597          *      (c) If dumpspec is not set, the dump device is
  598          *          wildcarded or unspecified.  If the root device
  599          *          is DV_IFNET, punt.  Otherwise, use partition b
  600          *          of the root device.
  601          */
  602 
  603         if (boothowto & RB_ASKNAME) {           /* (a) */
  604                 if (dumpdv == NULL)
  605                         goto nodumpdev;
  606         } else if (dumpspec != NULL) {          /* (b) */
  607                 if (strcmp(dumpspec, "none") == 0 || dumpdev == NODEV) {
  608                         /*
  609                          * Operator doesn't want a dump device.
  610                          * Or looks like they tried to pick a network
  611                          * device.  Oops.
  612                          */
  613                         goto nodumpdev;
  614                 }
  615 
  616                 dumpdevname = devsw_blk2name(major(dumpdev));
  617                 if (dumpdevname == NULL)
  618                         goto nodumpdev;
  619                 memset(buf, 0, sizeof(buf));
  620                 snprintf(buf, sizeof(buf), "%s%llu", dumpdevname,
  621                     (unsigned long long)DISKUNIT(dumpdev));
  622 
  623                 dumpdv = finddevice(buf);
  624                 if (dumpdv == NULL) {
  625                         /*
  626                          * Device not configured.
  627                          */
  628                         goto nodumpdev;
  629                 }
  630         } else {                                /* (c) */
  631                 if (DEV_USES_PARTITIONS(rootdv) == 0) {
  632                         for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
  633                              dv != NULL;
  634                              dv = deviter_next(&di))
  635                                 if (isswap(dv))
  636                                         break;
  637                         deviter_release(&di);
  638                         if (dv == NULL)
  639                                 goto nodumpdev;
  640 
  641                         majdev = devsw_name2blk(device_xname(dv), NULL, 0);
  642                         if (majdev < 0)
  643                                 goto nodumpdev;
  644                         dumpdv = dv;
  645                         dumpdev = makedev(majdev, device_unit(dumpdv));
  646                 } else {
  647                         dumpdv = rootdv;
  648                         dumpdev = MAKEDISKDEV(major(rootdev),
  649                             device_unit(dumpdv), 1);
  650                 }
  651         }
  652 
  653         dumpcdev = devsw_blk2chr(dumpdev);
  654         aprint_normal(" dumps on %s", device_xname(dumpdv));
  655         if (DEV_USES_PARTITIONS(dumpdv))
  656                 aprint_normal("%c", (int)DISKPART(dumpdev) + 'a');
  657         aprint_normal("\n");
  658         return;
  659 
  660  nodumpdev:
  661         dumpdev = NODEV;
  662         dumpcdev = NODEV;
  663         aprint_normal("\n");
  664 }
  665 
  666 static device_t
  667 finddevice(const char *name)
  668 {
  669         const char *wname;
  670 
  671         if ((wname = getwedgename(name, strlen(name))) != NULL)
  672                 return dkwedge_find_by_wname(wname);
  673 
  674         return device_find_by_xname(name);
  675 }
  676 
  677 static device_t
  678 getdisk(const char *str, int len, int defpart, dev_t *devp, int isdump)
  679 {
  680         device_t dv;
  681         deviter_t di;
  682 
  683         if (len == 4 && strcmp(str, "halt") == 0)
  684                 kern_reboot(RB_HALT, NULL);
  685         else if (len == 6 && strcmp(str, "reboot") == 0)
  686                 kern_reboot(0, NULL);
  687 #if defined(DDB)
  688         else if (len == 3 && strcmp(str, "ddb") == 0) {
  689                 console_debugger();
  690                 return NULL;
  691         }
  692 #endif
  693 
  694         if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
  695                 printf("use one of:");
  696                 for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL;
  697                      dv = deviter_next(&di)) {
  698                         if (DEV_USES_PARTITIONS(dv))
  699                                 printf(" %s[a-%c]", device_xname(dv),
  700                                     'a' + MAXPARTITIONS - 1);
  701                         else if (device_class(dv) == DV_DISK)
  702                                 printf(" %s", device_xname(dv));
  703                         if (isdump == 0 && device_class(dv) == DV_IFNET)
  704                                 printf(" %s", device_xname(dv));
  705                 }
  706                 deviter_release(&di);
  707                 dkwedge_print_wnames();
  708                 if (isdump)
  709                         printf(" none");
  710 #if defined(DDB)
  711                 printf(" ddb");
  712 #endif
  713                 printf(" halt reboot\n");
  714         }
  715         return dv;
  716 }
  717 
  718 static const char *
  719 getwedgename(const char *name, int namelen)
  720 {
  721         const char *wpfx1 = "wedge:";
  722         const char *wpfx2 = "NAME=";
  723         const int wpfx1len = strlen(wpfx1);
  724         const int wpfx2len = strlen(wpfx2);
  725 
  726         if (namelen > wpfx1len && strncmp(name, wpfx1, wpfx1len) == 0)
  727                 return name + wpfx1len;
  728 
  729         if (namelen > wpfx2len && strncasecmp(name, wpfx2, wpfx2len) == 0)
  730                 return name + wpfx2len;
  731 
  732         return NULL;
  733 }
  734 
  735 static device_t
  736 parsedisk(const char *str, int len, int defpart, dev_t *devp)
  737 {
  738         device_t dv;
  739         const char *wname;
  740         char c;
  741         int majdev, part;
  742         char xname[16]; /* same size as dv_xname */
  743 
  744         if (len == 0)
  745                 return (NULL);
  746 
  747         if ((wname = getwedgename(str, len)) != NULL) {
  748                 if ((dv = dkwedge_find_by_wname(wname)) == NULL)
  749                         return NULL;
  750                 part = defpart;
  751                 goto gotdisk;
  752         }
  753 
  754         c = str[len-1];
  755         if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
  756                 part = c - 'a';
  757                 len--;
  758                 if (len > sizeof(xname)-1)
  759                         return NULL;
  760                 memcpy(xname, str, len);
  761                 xname[len] = '\0';
  762                 str = xname;
  763         } else
  764                 part = defpart;
  765 
  766         dv = finddevice(str);
  767         if (dv != NULL) {
  768                 if (device_class(dv) == DV_DISK) {
  769  gotdisk:
  770                         majdev = devsw_name2blk(device_xname(dv), NULL, 0);
  771                         if (majdev < 0)
  772                                 panic("parsedisk");
  773                         if (DEV_USES_PARTITIONS(dv))
  774                                 *devp = MAKEDISKDEV(majdev, device_unit(dv),
  775                                                     part);
  776                         else
  777                                 *devp = makedev(majdev, device_unit(dv));
  778                 }
  779 
  780                 if (device_class(dv) == DV_IFNET)
  781                         *devp = NODEV;
  782         }
  783 
  784         return (dv);
  785 }

Cache object: 3266337ceefcb30e1e39a98627f5a2c3


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.